-
Notifications
You must be signed in to change notification settings - Fork 39.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Command tree and exported env in kubectl plugins #45981
Command tree and exported env in kubectl plugins #45981
Conversation
f7f3da6
to
6f638d2
Compare
@k8s-bot bazel test this |
357be18
to
a9e790a
Compare
@monopole a couple pieces for V1 here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice progress
pkg/kubectl/plugins/runner.go
Outdated
env = append(env, FieldToEnv("ShortDesc", p.Plugin.ShortDesc, prefix)) | ||
env = append(env, FieldToEnv("LongDesc", p.Plugin.LongDesc, prefix)) | ||
env = append(env, FieldToEnv("Example", p.Plugin.Example, prefix)) | ||
env = append(env, FieldToEnv("Command", p.Plugin.Command, prefix)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given that one starts from a literal string, might as well use the final result here rather than have all the reflection-y camelcase and period interpretation, i.e.
env = env.append(env, makePair(prefix + "NAME", p.Plugin.Name))
env = env.append(env, makePair(prefix + "SHORT_DESC", p.Plugin.ShortDesc))
that way one can find this code with a code search on SHORT_DESC.
As it is the code has the complexity of reflection without actually reading from variables.
Plus, if FieldToEnvName doesn't exist, it doesn't need test coverage.
setSource(path, fileInfo, child) | ||
} | ||
} | ||
setSource(path, fileInfo, plugin) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, this looks clever! if you want to add code for subtrees, please also add test coverage.
command trees and env var propagation are orthogonal. RPs that don't mix orthogonal things are easier to review, right? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have subtrees covered in test-cmd
, will also add some unit tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
kthnks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have them in 2 separate commits here, but I'll remember that for the next ones. ;)
pkg/kubectl/cmd/plugin.go
Outdated
env = append(env, plugins.FieldToEnv("APIPath", p.cfg.APIPath, prefix)) | ||
env = append(env, plugins.FieldToEnv("Prefix", p.cfg.Prefix, prefix)) | ||
env = append(env, plugins.FieldToEnv("Username", p.cfg.Username, prefix)) | ||
env = append(env, plugins.FieldToEnv("Password", p.cfg.Password, prefix)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This enables a world of perl scripts passing around passwords, certs etc, building libraries that attempt to make restful calls without the benefit of apimachinery client libs.
Wouldn't it be better to fire up a proxy within kubectl, then make that available to the plugin? Pass the (local) port via an env var, and simplify the the job of the plugin author. Maybe hold off on this particular provider?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd like to provide plugin authors a way to access the api (other that invoking kubectl
through the KUBECTL_PLUGINS_CALLER
env we are introducing here), so both ideas work for me. I agree with the concerns of these sensitive data passing around and the proxy is definitely easier for plugin authors, but do you think it would be easier to get approved? If so, that was part of my original plugins R&D and should not be too hard to adjust/improve be added here or in a follow-up PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@pwittrock might weigh in. Personally I'd rather approve a PR that set up the proxy for the plugin and fed the plugin what it needed to know about the proxy via env vars, than the above code which is simple but enables bad behavior. A proxy would encourage simpler plugins that followed a particular recognizable pattern.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as you say - you did a bunch of research on the proxy idea already... just dust it off in a separate PR.
pkg/kubectl/cmd/plugin.go
Outdated
return []string{}, err | ||
} | ||
return []string{fmt.Sprintf("%s=%s", "KUBECTL_PLUGINS_CURRENT_NAMESPACE", cmdNamespace)}, nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice job on the env provider interface and various impls! Very clear.
One nit: at this level it makes sense to create an array of pair struct {n, v string} and push the
fmt.Sprintf("%s=%s",
(which occurs several times here) down into runner.Run, converting to the format exec.Command seems to need just before it is invoked. That odd detail shouldn't leak up this high.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm +1 about a struct pair, the caveat is that os.Environ()
already returns []string
and it's used in one of the env providers. I'd need to iterate over it and split to make the pairs that would be returned in the provider list. Do you think it's worth?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sigh - didn't see that. Up to you. Seems a bit silly to unpack os.Environ.
OTHO, is osEnviron needed? I'd think a plugin running in subprocess has access to exported vars present in the parent process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Setting os.Environ
is needed, the subprocess only takes what you set there.
a9e790a
to
782c46c
Compare
@monopole Thanks for the review, PR updated. Addressing comments, more tests added, and the config env provider was removed. An additional way to access the API (likely through proxy) will be in a separate PR. |
782c46c
to
b718375
Compare
b718375
to
18cb56b
Compare
/lgtm Thanks! |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: fabianofranz, monopole
Needs approval from an approver in each of these OWNERS Files:
You can indicate your approval by writing |
@k8s-bot pull-kubernetes-federation-e2e-gce test this |
1 similar comment
@k8s-bot pull-kubernetes-federation-e2e-gce test this |
@fabianofranz: The following test(s) failed:
Full PR test history. Your PR dashboard. Please help us cut down on flakes by linking to an open issue when you hit one in your PR. Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository. I understand the commands that are listed here. |
Automatic merge from submit-queue (batch tested with PRs 46033, 46122, 46053, 46018, 45981) |
Automatic merge from submit-queue (batch tested with PRs 46033, 46122, 46053, 46018, 45981) Command tree and exported env in kubectl plugins This is part of `kubectl` plugins V1: - Adds support to several env vars passing context information to the plugin. Plugins can make use of them to connect to the REST API, access global flags, get the path of the plugin caller (so that `kubectl` can be invoked) and so on. Exported env vars include - `KUBECTL_PLUGINS_DESCRIPTOR_*`: the plugin descriptor fields - `KUBECTL_PLUGINS_GLOBAL_FLAG_*`: one for each global flag, useful to access namespace, context, etc - ~`KUBECTL_PLUGINS_REST_CLIENT_CONFIG_*`: one for most fields in `rest.Config` so that a REST client can be built.~ - `KUBECTL_PLUGINS_CALLER`: path to `kubectl` - `KUBECTL_PLUGINS_CURRENT_NAMESPACE`: namespace in use - Adds support for plugins as child of other plugins so that a tree of commands can be built (e.g. `kubectl myplugin list`, `kubectl myplugin add`, etc) **Release note**: ```release-note Added support to a hierarchy of kubectl plugins (a tree of plugins as children of other plugins). Added exported env vars to kubectl plugins so that plugin developers have access to global flags, namespace, the plugin descriptor and the full path to the caller binary. ``` @kubernetes/sig-cli-pr-reviews
This is part of
kubectl
plugins V1:kubectl
can be invoked) and so on. Exported env vars includeKUBECTL_PLUGINS_DESCRIPTOR_*
: the plugin descriptor fieldsKUBECTL_PLUGINS_GLOBAL_FLAG_*
: one for each global flag, useful to access namespace, context, etcKUBECTL_PLUGINS_REST_CLIENT_CONFIG_*
: one for most fields inrest.Config
so that a REST client can be built.KUBECTL_PLUGINS_CALLER
: path tokubectl
KUBECTL_PLUGINS_CURRENT_NAMESPACE
: namespace in usekubectl myplugin list
,kubectl myplugin add
, etc)Release note:
@kubernetes/sig-cli-pr-reviews