forked from kubernetes/kubernetes
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request kubernetes#37499 from fabianofranz/kubectl_plugins
Automatic merge from submit-queue kubectl binary plugins **What this PR does / why we need it**: Introduces the ability to extend `kubectl` by adding third-party plugins that will be exposed through `kubectl`. Plugins are executable commands written in any language. To be included as a plugin, a binary or script file has to 1. be located under one of the supported plugin path locations: 1.1 `~/.kubectl/plugins` dir 1.2. one or more directory set in the `KUBECTL_PLUGINS_PATH` env var 1.3. the `kubectl/plugins` dir under one or more directory set in the `XDG_DATA_DIRS` env var, which defaults to `/usr/local/share:/usr/share` 2. in any of the plugin path above, have a subfolder with the plugin file(s) 3. in the subfolder, contain at least a `plugin.yaml` file that describes the plugin Example: ``` $ cat ~/.kube/plugins/myplugin/plugin.yaml name: "myplugin" shortDesc: "My plugin's short description" command: "echo Hello plugins!" $ kubectl myplugin Hello plugins! ``` ~~In case the plugin declares `tunnel: true`, the plugin engine will pass the `KUBECTL_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 by `kubectl`.~~ 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: kubernetes#30086 and kubernetes/community#122. **Release note**: ```release-note Introduces the ability to extend kubectl by adding third-party plugins. Developer preview, please refer to the documentation for instructions about how to use it. ```
- Loading branch information
Showing
33 changed files
with
1,146 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
This file is autogenerated, but we've stopped checking such files into the | ||
repository to reduce the need for rebases. Please run hack/generate-docs.sh to | ||
populate this file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
This file is autogenerated, but we've stopped checking such files into the | ||
repository to reduce the need for rebases. Please run hack/generate-docs.sh to | ||
populate this file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
This file is autogenerated, but we've stopped checking such files into the | ||
repository to reduce the need for rebases. Please run hack/generate-docs.sh to | ||
populate this file. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
/* | ||
Copyright 2017 The Kubernetes Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package cmd | ||
|
||
import ( | ||
"fmt" | ||
"io" | ||
"os" | ||
|
||
"github.com/golang/glog" | ||
"github.com/spf13/cobra" | ||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates" | ||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | ||
"k8s.io/kubernetes/pkg/kubectl/plugins" | ||
"k8s.io/kubernetes/pkg/util/i18n" | ||
) | ||
|
||
var ( | ||
plugin_long = templates.LongDesc(` | ||
Runs a command-line plugin. | ||
Plugins are subcommands that are not part of the major command-line distribution | ||
and can even be provided by third-parties. Please refer to the documentation and | ||
examples for more information about how to install and write your own plugins.`) | ||
) | ||
|
||
// NewCmdPlugin creates the command that is the top-level for plugin commands. | ||
func NewCmdPlugin(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Command { | ||
// Loads plugins and create commands for each plugin identified | ||
loadedPlugins, loadErr := f.PluginLoader().Load() | ||
if loadErr != nil { | ||
glog.V(1).Infof("Unable to load plugins: %v", loadErr) | ||
} | ||
|
||
cmd := &cobra.Command{ | ||
Use: "plugin NAME", | ||
Short: i18n.T("Runs a command-line plugin"), | ||
Long: plugin_long, | ||
Run: func(cmd *cobra.Command, args []string) { | ||
if len(loadedPlugins) == 0 { | ||
cmdutil.CheckErr(fmt.Errorf("no plugins installed.")) | ||
} | ||
cmdutil.DefaultSubCommandRun(err)(cmd, args) | ||
}, | ||
} | ||
|
||
if len(loadedPlugins) > 0 { | ||
pluginRunner := f.PluginRunner() | ||
for _, p := range loadedPlugins { | ||
cmd.AddCommand(NewCmdForPlugin(p, pluginRunner, in, out, err)) | ||
} | ||
} | ||
|
||
return cmd | ||
} | ||
|
||
// NewCmdForPlugin creates a command capable of running the provided plugin. | ||
func NewCmdForPlugin(plugin *plugins.Plugin, runner plugins.PluginRunner, in io.Reader, out, errout io.Writer) *cobra.Command { | ||
if !plugin.IsValid() { | ||
return nil | ||
} | ||
|
||
return &cobra.Command{ | ||
Use: plugin.Name, | ||
Short: plugin.ShortDesc, | ||
Long: templates.LongDesc(plugin.LongDesc), | ||
Example: templates.Examples(plugin.Example), | ||
Run: func(cmd *cobra.Command, args []string) { | ||
ctx := plugins.RunningContext{ | ||
In: in, | ||
Out: out, | ||
ErrOut: errout, | ||
Args: args, | ||
Env: os.Environ(), | ||
WorkingDir: plugin.Dir, | ||
} | ||
if err := runner.Run(plugin, ctx); err != nil { | ||
cmdutil.CheckErr(err) | ||
} | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
/* | ||
Copyright 2017 The Kubernetes Authors. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
package cmd | ||
|
||
import ( | ||
"bytes" | ||
"fmt" | ||
"testing" | ||
|
||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" | ||
"k8s.io/kubernetes/pkg/kubectl/plugins" | ||
) | ||
|
||
type mockPluginRunner struct { | ||
success bool | ||
} | ||
|
||
func (r *mockPluginRunner) Run(p *plugins.Plugin, ctx plugins.RunningContext) error { | ||
if !r.success { | ||
return fmt.Errorf("oops %s", p.Name) | ||
} | ||
ctx.Out.Write([]byte(fmt.Sprintf("ok: %s", p.Name))) | ||
return nil | ||
} | ||
|
||
func TestPluginCmd(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
plugin *plugins.Plugin | ||
expectedSuccess bool | ||
expectedNilCmd bool | ||
}{ | ||
{ | ||
name: "success", | ||
plugin: &plugins.Plugin{ | ||
Description: plugins.Description{ | ||
Name: "success", | ||
ShortDesc: "The Test Plugin", | ||
Command: "echo ok", | ||
}, | ||
}, | ||
expectedSuccess: true, | ||
}, | ||
{ | ||
name: "incomplete", | ||
plugin: &plugins.Plugin{ | ||
Description: plugins.Description{ | ||
Name: "incomplete", | ||
ShortDesc: "The Incomplete Plugin", | ||
}, | ||
}, | ||
expectedNilCmd: true, | ||
}, | ||
{ | ||
name: "failure", | ||
plugin: &plugins.Plugin{ | ||
Description: plugins.Description{ | ||
Name: "failure", | ||
ShortDesc: "The Failing Plugin", | ||
Command: "false", | ||
}, | ||
}, | ||
expectedSuccess: false, | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
inBuf := bytes.NewBuffer([]byte{}) | ||
outBuf := bytes.NewBuffer([]byte{}) | ||
errBuf := bytes.NewBuffer([]byte{}) | ||
|
||
cmdutil.BehaviorOnFatal(func(str string, code int) { | ||
errBuf.Write([]byte(str)) | ||
}) | ||
|
||
runner := &mockPluginRunner{ | ||
success: test.expectedSuccess, | ||
} | ||
|
||
cmd := NewCmdForPlugin(test.plugin, runner, inBuf, outBuf, errBuf) | ||
if cmd == nil { | ||
if !test.expectedNilCmd { | ||
t.Fatalf("%s: command was unexpectedly not registered", test.name) | ||
} | ||
continue | ||
} | ||
cmd.Run(cmd, []string{}) | ||
|
||
if test.expectedSuccess && outBuf.String() != fmt.Sprintf("ok: %s", test.plugin.Name) { | ||
t.Errorf("%s: unexpected output: %q", test.name, outBuf.String()) | ||
} | ||
|
||
if !test.expectedSuccess && errBuf.String() != fmt.Sprintf("error: oops %s", test.plugin.Name) { | ||
t.Errorf("%s: unexpected err output: %q", test.name, errBuf.String()) | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.