mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-05 10:19:50 +00:00
kubectl plugins have access config, global flags and environment
This commit is contained in:
parent
da85262f70
commit
18cb56bf78
@ -3784,6 +3784,15 @@ __EOF__
|
|||||||
kube::test::if_has_not_string "${output_message}" 'child1'
|
kube::test::if_has_not_string "${output_message}" 'child1'
|
||||||
kube::test::if_has_not_string "${output_message}" 'The first child'
|
kube::test::if_has_not_string "${output_message}" 'The first child'
|
||||||
|
|
||||||
|
# plugin env
|
||||||
|
output_message=$(KUBECTL_PLUGINS_PATH=test/fixtures/pkg/kubectl/plugins kubectl plugin env 2>&1)
|
||||||
|
kube::test::if_has_string "${output_message}" 'KUBECTL_PLUGINS_CURRENT_NAMESPACE'
|
||||||
|
kube::test::if_has_string "${output_message}" 'KUBECTL_PLUGINS_CALLER'
|
||||||
|
kube::test::if_has_string "${output_message}" 'KUBECTL_PLUGINS_DESCRIPTOR_COMMAND=./env.sh'
|
||||||
|
kube::test::if_has_string "${output_message}" 'KUBECTL_PLUGINS_DESCRIPTOR_SHORT_DESC=The plugin envs plugin'
|
||||||
|
kube::test::if_has_string "${output_message}" 'KUBECTL_PLUGINS_GLOBAL_FLAG_KUBECONFIG'
|
||||||
|
kube::test::if_has_string "${output_message}" 'KUBECTL_PLUGINS_GLOBAL_FLAG_REQUEST_TIMEOUT=0'
|
||||||
|
|
||||||
#################
|
#################
|
||||||
# Impersonation #
|
# Impersonation #
|
||||||
#################
|
#################
|
||||||
|
@ -19,10 +19,10 @@ package cmd
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/spf13/pflag"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/plugins"
|
"k8s.io/kubernetes/pkg/kubectl/plugins"
|
||||||
@ -61,7 +61,7 @@ func NewCmdPlugin(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Co
|
|||||||
if len(loadedPlugins) > 0 {
|
if len(loadedPlugins) > 0 {
|
||||||
pluginRunner := f.PluginRunner()
|
pluginRunner := f.PluginRunner()
|
||||||
for _, p := range loadedPlugins {
|
for _, p := range loadedPlugins {
|
||||||
cmd.AddCommand(NewCmdForPlugin(p, pluginRunner, in, out, err))
|
cmd.AddCommand(NewCmdForPlugin(f, p, pluginRunner, in, out, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,28 +69,81 @@ func NewCmdPlugin(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cobra.Co
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewCmdForPlugin creates a command capable of running the provided plugin.
|
// 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 {
|
func NewCmdForPlugin(f cmdutil.Factory, plugin *plugins.Plugin, runner plugins.PluginRunner, in io.Reader, out, errout io.Writer) *cobra.Command {
|
||||||
if !plugin.IsValid() {
|
if !plugin.IsValid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return &cobra.Command{
|
cmd := &cobra.Command{
|
||||||
Use: plugin.Name,
|
Use: plugin.Name,
|
||||||
Short: plugin.ShortDesc,
|
Short: plugin.ShortDesc,
|
||||||
Long: templates.LongDesc(plugin.LongDesc),
|
Long: templates.LongDesc(plugin.LongDesc),
|
||||||
Example: templates.Examples(plugin.Example),
|
Example: templates.Examples(plugin.Example),
|
||||||
Run: func(cmd *cobra.Command, args []string) {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
ctx := plugins.RunningContext{
|
if len(plugin.Command) == 0 {
|
||||||
In: in,
|
cmdutil.DefaultSubCommandRun(errout)(cmd, args)
|
||||||
Out: out,
|
return
|
||||||
ErrOut: errout,
|
|
||||||
Args: args,
|
|
||||||
Env: os.Environ(),
|
|
||||||
WorkingDir: plugin.Dir,
|
|
||||||
}
|
}
|
||||||
if err := runner.Run(plugin, ctx); err != nil {
|
|
||||||
|
envProvider := &plugins.MultiEnvProvider{
|
||||||
|
&plugins.PluginCallerEnvProvider{},
|
||||||
|
&plugins.OSEnvProvider{},
|
||||||
|
&plugins.PluginDescriptorEnvProvider{
|
||||||
|
Plugin: plugin,
|
||||||
|
},
|
||||||
|
&flagsPluginEnvProvider{
|
||||||
|
cmd: cmd,
|
||||||
|
},
|
||||||
|
&factoryAttrsPluginEnvProvider{
|
||||||
|
factory: f,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
runningContext := plugins.RunningContext{
|
||||||
|
In: in,
|
||||||
|
Out: out,
|
||||||
|
ErrOut: errout,
|
||||||
|
Args: args,
|
||||||
|
EnvProvider: envProvider,
|
||||||
|
WorkingDir: plugin.Dir,
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := runner.Run(plugin, runningContext); err != nil {
|
||||||
cmdutil.CheckErr(err)
|
cmdutil.CheckErr(err)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, childPlugin := range plugin.Tree {
|
||||||
|
cmd.AddCommand(NewCmdForPlugin(f, childPlugin, runner, in, out, errout))
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
type flagsPluginEnvProvider struct {
|
||||||
|
cmd *cobra.Command
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *flagsPluginEnvProvider) Env() (plugins.EnvList, error) {
|
||||||
|
prefix := "KUBECTL_PLUGINS_GLOBAL_FLAG_"
|
||||||
|
env := plugins.EnvList{}
|
||||||
|
p.cmd.Flags().VisitAll(func(flag *pflag.Flag) {
|
||||||
|
env = append(env, plugins.FlagToEnv(flag, prefix))
|
||||||
|
})
|
||||||
|
return env, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type factoryAttrsPluginEnvProvider struct {
|
||||||
|
factory cmdutil.Factory
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *factoryAttrsPluginEnvProvider) Env() (plugins.EnvList, error) {
|
||||||
|
cmdNamespace, _, err := p.factory.DefaultNamespace()
|
||||||
|
if err != nil {
|
||||||
|
return plugins.EnvList{}, err
|
||||||
|
}
|
||||||
|
return plugins.EnvList{
|
||||||
|
plugins.Env{N: "KUBECTL_PLUGINS_CURRENT_NAMESPACE", V: cmdNamespace},
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
cmdtesting "k8s.io/kubernetes/pkg/kubectl/cmd/testing"
|
||||||
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
|
||||||
"k8s.io/kubernetes/pkg/kubectl/plugins"
|
"k8s.io/kubernetes/pkg/kubectl/plugins"
|
||||||
)
|
)
|
||||||
@ -91,7 +92,8 @@ func TestPluginCmd(t *testing.T) {
|
|||||||
success: test.expectedSuccess,
|
success: test.expectedSuccess,
|
||||||
}
|
}
|
||||||
|
|
||||||
cmd := NewCmdForPlugin(test.plugin, runner, inBuf, outBuf, errBuf)
|
f, _, _, _ := cmdtesting.NewAPIFactory()
|
||||||
|
cmd := NewCmdForPlugin(f, test.plugin, runner, inBuf, outBuf, errBuf)
|
||||||
if cmd == nil {
|
if cmd == nil {
|
||||||
if !test.expectedNilCmd {
|
if !test.expectedNilCmd {
|
||||||
t.Fatalf("%s: command was unexpectedly not registered", test.name)
|
t.Fatalf("%s: command was unexpectedly not registered", test.name)
|
||||||
|
@ -11,6 +11,7 @@ load(
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"env.go",
|
||||||
"loader.go",
|
"loader.go",
|
||||||
"plugins.go",
|
"plugins.go",
|
||||||
"runner.go",
|
"runner.go",
|
||||||
@ -19,6 +20,7 @@ go_library(
|
|||||||
deps = [
|
deps = [
|
||||||
"//vendor/github.com/ghodss/yaml:go_default_library",
|
"//vendor/github.com/ghodss/yaml:go_default_library",
|
||||||
"//vendor/github.com/golang/glog:go_default_library",
|
"//vendor/github.com/golang/glog:go_default_library",
|
||||||
|
"//vendor/github.com/spf13/pflag:go_default_library",
|
||||||
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
"//vendor/k8s.io/client-go/tools/clientcmd:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
@ -39,10 +41,12 @@ filegroup(
|
|||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = [
|
srcs = [
|
||||||
|
"env_test.go",
|
||||||
"loader_test.go",
|
"loader_test.go",
|
||||||
"plugins_test.go",
|
"plugins_test.go",
|
||||||
"runner_test.go",
|
"runner_test.go",
|
||||||
],
|
],
|
||||||
library = ":go_default_library",
|
library = ":go_default_library",
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
|
deps = ["//vendor/github.com/spf13/pflag:go_default_library"],
|
||||||
)
|
)
|
||||||
|
147
pkg/kubectl/plugins/env.go
Normal file
147
pkg/kubectl/plugins/env.go
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
/*
|
||||||
|
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 plugins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Env represents an environment variable with its name and value
|
||||||
|
type Env struct {
|
||||||
|
N string
|
||||||
|
V string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e Env) String() string {
|
||||||
|
return fmt.Sprintf("%s=%s", e.N, e.V)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnvList is a list of Env
|
||||||
|
type EnvList []Env
|
||||||
|
|
||||||
|
func (e EnvList) Slice() []string {
|
||||||
|
envs := []string{}
|
||||||
|
for _, env := range e {
|
||||||
|
envs = append(envs, env.String())
|
||||||
|
}
|
||||||
|
return envs
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e EnvList) Merge(s ...string) EnvList {
|
||||||
|
newList := e
|
||||||
|
newList = append(newList, fromSlice(s)...)
|
||||||
|
return newList
|
||||||
|
}
|
||||||
|
|
||||||
|
// EnvProvider provides the environment in which the plugin will run.
|
||||||
|
type EnvProvider interface {
|
||||||
|
Env() (EnvList, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MultiEnvProvider is an EnvProvider for multiple env providers, returns on first error.
|
||||||
|
type MultiEnvProvider []EnvProvider
|
||||||
|
|
||||||
|
func (p MultiEnvProvider) Env() (EnvList, error) {
|
||||||
|
env := EnvList{}
|
||||||
|
for _, provider := range p {
|
||||||
|
pEnv, err := provider.Env()
|
||||||
|
if err != nil {
|
||||||
|
return EnvList{}, err
|
||||||
|
}
|
||||||
|
env = append(env, pEnv...)
|
||||||
|
}
|
||||||
|
return env, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginCallerEnvProvider provides env with the path to the caller binary (usually full path to 'kubectl').
|
||||||
|
type PluginCallerEnvProvider struct{}
|
||||||
|
|
||||||
|
func (p *PluginCallerEnvProvider) Env() (EnvList, error) {
|
||||||
|
caller, err := os.Executable()
|
||||||
|
if err != nil {
|
||||||
|
return EnvList{}, err
|
||||||
|
}
|
||||||
|
return EnvList{
|
||||||
|
{"KUBECTL_PLUGINS_CALLER", caller},
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PluginDescriptorEnvProvider provides env vars with information about the running plugin.
|
||||||
|
type PluginDescriptorEnvProvider struct {
|
||||||
|
Plugin *Plugin
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *PluginDescriptorEnvProvider) Env() (EnvList, error) {
|
||||||
|
if p.Plugin == nil {
|
||||||
|
return []Env{}, fmt.Errorf("plugin not present to extract env")
|
||||||
|
}
|
||||||
|
prefix := "KUBECTL_PLUGINS_DESCRIPTOR_"
|
||||||
|
env := EnvList{
|
||||||
|
{prefix + "NAME", p.Plugin.Name},
|
||||||
|
{prefix + "SHORT_DESC", p.Plugin.ShortDesc},
|
||||||
|
{prefix + "LONG_DESC", p.Plugin.LongDesc},
|
||||||
|
{prefix + "EXAMPLE", p.Plugin.Example},
|
||||||
|
{prefix + "COMMAND", p.Plugin.Command},
|
||||||
|
}
|
||||||
|
return env, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OSEnvProvider provides current environment from the operating system.
|
||||||
|
type OSEnvProvider struct{}
|
||||||
|
|
||||||
|
func (p *OSEnvProvider) Env() (EnvList, error) {
|
||||||
|
return fromSlice(os.Environ()), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type EmptyEnvProvider struct{}
|
||||||
|
|
||||||
|
func (p *EmptyEnvProvider) Env() (EnvList, error) {
|
||||||
|
return EnvList{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func FlagToEnvName(flagName, prefix string) string {
|
||||||
|
envName := strings.TrimPrefix(flagName, "--")
|
||||||
|
envName = strings.ToUpper(envName)
|
||||||
|
envName = strings.Replace(envName, "-", "_", -1)
|
||||||
|
envName = prefix + envName
|
||||||
|
return envName
|
||||||
|
}
|
||||||
|
|
||||||
|
func FlagToEnv(flag *pflag.Flag, prefix string) Env {
|
||||||
|
envName := FlagToEnvName(flag.Name, prefix)
|
||||||
|
return Env{envName, flag.Value.String()}
|
||||||
|
}
|
||||||
|
|
||||||
|
func fromSlice(envs []string) EnvList {
|
||||||
|
list := EnvList{}
|
||||||
|
for _, env := range envs {
|
||||||
|
list = append(list, parseEnv(env))
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseEnv(env string) Env {
|
||||||
|
if !strings.Contains(env, "=") {
|
||||||
|
env = env + "="
|
||||||
|
}
|
||||||
|
parsed := strings.SplitN(env, "=", 2)
|
||||||
|
return Env{parsed[0], parsed[1]}
|
||||||
|
}
|
162
pkg/kubectl/plugins/env_test.go
Normal file
162
pkg/kubectl/plugins/env_test.go
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
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 plugins
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/spf13/pflag"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEnv(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
env Env
|
||||||
|
expected string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
env: Env{"FOO", "BAR"},
|
||||||
|
expected: "FOO=BAR",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
env: Env{"FOO", "BAR="},
|
||||||
|
expected: "FOO=BAR=",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
env: Env{"FOO", ""},
|
||||||
|
expected: "FOO=",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
if s := test.env.String(); s != test.expected {
|
||||||
|
t.Errorf("%v: expected string %q, got %q", test.env, test.expected, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEnvListToSlice(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
env EnvList
|
||||||
|
expected []string
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
env: EnvList{
|
||||||
|
{"FOO", "BAR"},
|
||||||
|
{"ZEE", "YO"},
|
||||||
|
{"ONE", "1"},
|
||||||
|
{"EQUALS", "=="},
|
||||||
|
{"EMPTY", ""},
|
||||||
|
},
|
||||||
|
expected: []string{"FOO=BAR", "ZEE=YO", "ONE=1", "EQUALS===", "EMPTY="},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
if s := test.env.Slice(); !reflect.DeepEqual(test.expected, s) {
|
||||||
|
t.Errorf("%v: expected %v, got %v", test.env, test.expected, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAddToEnvList(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
add []string
|
||||||
|
expected EnvList
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
add: []string{"FOO=BAR", "EMPTY=", "EQUALS===", "JUSTNAME"},
|
||||||
|
expected: EnvList{
|
||||||
|
{"FOO", "BAR"},
|
||||||
|
{"EMPTY", ""},
|
||||||
|
{"EQUALS", "=="},
|
||||||
|
{"JUSTNAME", ""},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
env := EnvList{}.Merge(test.add...)
|
||||||
|
if !reflect.DeepEqual(test.expected, env) {
|
||||||
|
t.Errorf("%v: expected %v, got %v", test.add, test.expected, env)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFlagToEnv(t *testing.T) {
|
||||||
|
flags := pflag.NewFlagSet("", pflag.ContinueOnError)
|
||||||
|
flags.String("test", "ok", "")
|
||||||
|
flags.String("kube-master", "http://something", "")
|
||||||
|
flags.String("from-file", "default", "")
|
||||||
|
flags.Parse([]string{"--from-file=nondefault"})
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
flag *pflag.Flag
|
||||||
|
prefix string
|
||||||
|
expected Env
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
flag: flags.Lookup("test"),
|
||||||
|
expected: Env{"TEST", "ok"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
flag: flags.Lookup("kube-master"),
|
||||||
|
expected: Env{"KUBE_MASTER", "http://something"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
prefix: "KUBECTL_",
|
||||||
|
flag: flags.Lookup("from-file"),
|
||||||
|
expected: Env{"KUBECTL_FROM_FILE", "nondefault"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
if env := FlagToEnv(test.flag, test.prefix); !reflect.DeepEqual(test.expected, env) {
|
||||||
|
t.Errorf("%v: expected %v, got %v", test.flag.Name, test.expected, env)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPluginDescriptorEnvProvider(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
plugin *Plugin
|
||||||
|
expected EnvList
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
plugin: &Plugin{
|
||||||
|
Description: Description{
|
||||||
|
Name: "test",
|
||||||
|
ShortDesc: "Short Description",
|
||||||
|
Command: "foo --bar",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expected: EnvList{
|
||||||
|
{"KUBECTL_PLUGINS_DESCRIPTOR_NAME", "test"},
|
||||||
|
{"KUBECTL_PLUGINS_DESCRIPTOR_SHORT_DESC", "Short Description"},
|
||||||
|
{"KUBECTL_PLUGINS_DESCRIPTOR_LONG_DESC", ""},
|
||||||
|
{"KUBECTL_PLUGINS_DESCRIPTOR_EXAMPLE", ""},
|
||||||
|
{"KUBECTL_PLUGINS_DESCRIPTOR_COMMAND", "foo --bar"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
provider := &PluginDescriptorEnvProvider{
|
||||||
|
Plugin: test.plugin,
|
||||||
|
}
|
||||||
|
env, _ := provider.Env()
|
||||||
|
if !reflect.DeepEqual(test.expected, env) {
|
||||||
|
t.Errorf("%v: expected %v, got %v", test.plugin.Name, test.expected, env)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -34,12 +34,12 @@ type PluginRunner interface {
|
|||||||
// in, out, and err streams, arguments and environment passed to it, and the
|
// in, out, and err streams, arguments and environment passed to it, and the
|
||||||
// working directory.
|
// working directory.
|
||||||
type RunningContext struct {
|
type RunningContext struct {
|
||||||
In io.Reader
|
In io.Reader
|
||||||
Out io.Writer
|
Out io.Writer
|
||||||
ErrOut io.Writer
|
ErrOut io.Writer
|
||||||
Args []string
|
Args []string
|
||||||
Env []string
|
EnvProvider EnvProvider
|
||||||
WorkingDir string
|
WorkingDir string
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExecPluginRunner is a PluginRunner that uses Go's os/exec to run plugins.
|
// ExecPluginRunner is a PluginRunner that uses Go's os/exec to run plugins.
|
||||||
@ -62,7 +62,11 @@ func (r *ExecPluginRunner) Run(plugin *Plugin, ctx RunningContext) error {
|
|||||||
cmd.Stdout = ctx.Out
|
cmd.Stdout = ctx.Out
|
||||||
cmd.Stderr = ctx.ErrOut
|
cmd.Stderr = ctx.ErrOut
|
||||||
|
|
||||||
cmd.Env = ctx.Env
|
env, err := ctx.EnvProvider.Env()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
cmd.Env = env.Slice()
|
||||||
cmd.Dir = ctx.WorkingDir
|
cmd.Dir = ctx.WorkingDir
|
||||||
|
|
||||||
glog.V(9).Infof("Running plugin %q as base command %q with args %v", plugin.Name, base, args)
|
glog.V(9).Infof("Running plugin %q as base command %q with args %v", plugin.Name, base, args)
|
||||||
|
@ -61,8 +61,9 @@ func TestExecRunner(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ctx := RunningContext{
|
ctx := RunningContext{
|
||||||
Out: outBuf,
|
Out: outBuf,
|
||||||
WorkingDir: ".",
|
WorkingDir: ".",
|
||||||
|
EnvProvider: &EmptyEnvProvider{},
|
||||||
}
|
}
|
||||||
|
|
||||||
runner := &ExecPluginRunner{}
|
runner := &ExecPluginRunner{}
|
||||||
|
17
test/fixtures/pkg/kubectl/plugins/env/env.sh
vendored
Executable file
17
test/fixtures/pkg/kubectl/plugins/env/env.sh
vendored
Executable file
@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
|
||||||
|
env | grep 'KUBECTL_PLUGINS' | sort
|
3
test/fixtures/pkg/kubectl/plugins/env/plugin.yaml
vendored
Normal file
3
test/fixtures/pkg/kubectl/plugins/env/plugin.yaml
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
name: env
|
||||||
|
shortDesc: "The plugin envs plugin"
|
||||||
|
command: "./env.sh"
|
@ -3,11 +3,11 @@ shortDesc: "Plugin with a tree of commands"
|
|||||||
tree:
|
tree:
|
||||||
- name: "child1"
|
- name: "child1"
|
||||||
shortDesc: "The first child of a tree"
|
shortDesc: "The first child of a tree"
|
||||||
command: echo child1
|
command: echo child one
|
||||||
- name: "child2"
|
- name: "child2"
|
||||||
shortDesc: "The second child of a tree"
|
shortDesc: "The second child of a tree"
|
||||||
command: echo child2
|
command: echo child two
|
||||||
- name: "child3"
|
- name: "child3"
|
||||||
shortDesc: "The third child of a tree"
|
shortDesc: "The third child of a tree"
|
||||||
command: echo child3
|
command: echo child three
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user