-
Notifications
You must be signed in to change notification settings - Fork 39.6k
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
kubectl binary plugins #37499
kubectl binary plugins #37499
Conversation
3515f17
to
806fb34
Compare
Jenkins GCI GKE smoke e2e failed for commit 3515f173e82520fa67b134e85dda4c850f7dbc33. Full PR test history. The magic incantation to run this job again is |
Jenkins GKE smoke e2e failed for commit 3515f173e82520fa67b134e85dda4c850f7dbc33. Full PR test history. The magic incantation to run this job again is |
Jenkins CRI GCE Node e2e failed for commit 3515f173e82520fa67b134e85dda4c850f7dbc33. Full PR test history. The magic incantation to run this job again is |
806fb34
to
ad600b7
Compare
@kubernetes/kubectl @kubernetes/sig-cli |
@fabianofranz 👍 I would take a deep look the next Monday. |
@@ -47,8 +47,9 @@ const ( | |||
RecommendedSchemaName = "schema" | |||
) | |||
|
|||
var RecommendedHomeFile = path.Join(homedir.HomeDir(), RecommendedHomeDir, RecommendedFileName) | |||
var RecommendedSchemaFile = path.Join(homedir.HomeDir(), RecommendedHomeDir, RecommendedSchemaName) | |||
var RecommenderConfigDir = path.Join(homedir.HomeDir(), RecommendedHomeDir) |
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.
var (
...
)
please 😸
pkg/kubectl/cmd/cmd.go
Outdated
@@ -225,25 +227,25 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob | |||
{ | |||
Message: "Basic Commands (Beginner):", | |||
Commands: []*cobra.Command{ | |||
NewCmdCreate(f, out, err), | |||
NewCmdCreate(f, out, errOut), |
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.
We should be passing out
and errOut
to every single command, as a rule of thumb. Not all our commands write errors to stderr, but should.
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.
yes, this should be a basic rule.
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.
+1
pkg/kubectl/plugin/loader.go
Outdated
|
||
list := PluginList{} | ||
err := filepath.Walk(l.pluginsDir, func(path string, fileInfo os.FileInfo, err error) error { | ||
glog.V(9).Infof("Checking plugin in %s...", path) |
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 stick with 5 & 6 levels, 7 and above usually contain HTTP data, which will hide this log.
pkg/kubectl/plugin/plugin.go
Outdated
|
||
package plugin | ||
|
||
type Plugin struct { |
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 needs to be documented in details so that the plugin writers know what to return here.
@@ -0,0 +1,21 @@ | |||
#!/usr/bin/env ruby | |||
|
|||
if ARGV[0] == "metadata" |
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.
If this serves as an example, put detailed comments what/why and where?
puts "I'm the magnificent foo plugin." | ||
puts "" | ||
puts "I can use the API from #{api_host}:" | ||
puts `curl -s #{api_endpoint}` |
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 liked this example, b/c it was simple and quite self-explanatory, why removing it?
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 wanted to make this one as dumb as possible (doesn't even access the API), and then I wrote the more complex kubectl aging
which uses API data.
This is looking really nice, but most importantly thorough doc is needed for users writing the plugins. |
@soltysh this is just a PoC, still a lot to do, and of course thorough doc is necessary. |
The Helm plugin guide could be a good reference: |
pkg/kubectl/plugins/plugin.go
Outdated
"github.com/golang/glog" | ||
) | ||
|
||
type Plugin struct { |
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.
some comments are necessary here.
pkg/kubectl/plugins/loader.go
Outdated
return nil | ||
} | ||
|
||
cmd := exec.Command(path, "metadata") |
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.
Compared with Helm file based metadata, I am worrying the performance, since this lookup happens every time command execute.
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.
@adohe Absolutely, this is one of my major concerns. While this makes plugins much more portable (everything is in the executable), if definitely doesn't scale well. I'll think about an intermediate idea, maybe cache the metadata, look for a descriptor file first and fallback to the metadata
call, something like that.
Definitely, I just didn't do it given the PoC nature of this PR. But it needs both docs and very good inline comments. ;) |
ad600b7
to
fd83635
Compare
@liggitt @soltysh @pwittrock @monopole PTAL. Plugins are now loaded under |
32b955c
to
096285f
Compare
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.
A small nit, but overall lgtm!
plugin_long = templates.LongDesc(` | ||
Runs a command-line plugin. | ||
|
||
Plugins are subcommands that are not part of the major command-line distribution |
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.
It's worth mentioning from where these plugins are loaded, I think.
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.
Yeah it started like that but I didn't like the results, too clumsy for a command help. Ahead we'll probably want something better than relying on just the help as the default command run, then we can think of something better. And we will have proper docs which we can link to.
@fabianofranz you need to run |
e4ca8b0
to
2ee97cb
Compare
00f8f61
to
1c2b1ae
Compare
@k8s-bot verify test this |
@k8s-bot unit test this |
1c2b1ae
to
f1153bd
Compare
@k8s-bot unit test this |
f1153bd
to
2158473
Compare
@soltysh @monopole @pwittrock @liggitt FYI on tests green, I'd like to get this merged. I'm already putting together the next PR that will include parts of post-V0 like global flags through env vars, better support for plugin flags and so on. |
Very cool work @fabianofranz ! Can't wait to use this. lgtm but I will let one of the main reviewers tag it. |
/lgtm |
/approve for remaining code given agreement from sig owners and that this is initial |
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: fabianofranz, monopole, smarterclayton, soltysh
Needs approval from an approver in each of these OWNERS Files:
You can indicate your approval by writing |
Automatic merge from submit-queue |
What this PR does / why we need it:
Introduces the ability to extend
kubectl
by adding third-party plugins that will be exposed throughkubectl
.Plugins are executable commands written in any language. To be included as a plugin, a binary or script file has to
1.1
~/.kubectl/plugins
dir1.2. one or more directory set in the
KUBECTL_PLUGINS_PATH
env var1.3. the
kubectl/plugins
dir under one or more directory set in theXDG_DATA_DIRS
env var, which defaults to/usr/local/share:/usr/share
plugin.yaml
file that describes the pluginExample:
In case the plugin declarestunnel: true
, the plugin engine will pass theKUBECTL_PLUGIN_API_HOST
env var when calling the plugin binary. Plugins can then access the Kube REST API in "http://$KUBECTL_PLUGIN_API_HOST/api" using the same context currently in use bykubectl
.Test plugins are provided in
pkg/kubectl/plugins/examples
. Just copy (or symlink) the files to~/.kube/plugins
to test.Which issue this PR fixes:
Related to the discussions in the proposal document: #30086 and kubernetes/community#122.
Release note:
This change is