Allow modifying current context with kubectl set-context

pull/8/head
Jordan Liggitt 2018-07-12 17:19:01 -04:00
parent 82c986ecbc
commit fe53c618e8
No known key found for this signature in database
GPG Key ID: 39928704103C7229
2 changed files with 61 additions and 18 deletions

View File

@ -34,6 +34,7 @@ import (
type createContextOptions struct { type createContextOptions struct {
configAccess clientcmd.ConfigAccess configAccess clientcmd.ConfigAccess
name string name string
currContext bool
cluster flag.StringFlag cluster flag.StringFlag
authInfo flag.StringFlag authInfo flag.StringFlag
namespace flag.StringFlag namespace flag.StringFlag
@ -54,23 +55,24 @@ func NewCmdConfigSetContext(out io.Writer, configAccess clientcmd.ConfigAccess)
options := &createContextOptions{configAccess: configAccess} options := &createContextOptions{configAccess: configAccess}
cmd := &cobra.Command{ cmd := &cobra.Command{
Use: fmt.Sprintf("set-context NAME [--%v=cluster_nickname] [--%v=user_nickname] [--%v=namespace]", clientcmd.FlagClusterName, clientcmd.FlagAuthInfoName, clientcmd.FlagNamespace), Use: fmt.Sprintf("set-context [NAME | --current] [--%v=cluster_nickname] [--%v=user_nickname] [--%v=namespace]", clientcmd.FlagClusterName, clientcmd.FlagAuthInfoName, clientcmd.FlagNamespace),
DisableFlagsInUseLine: true, DisableFlagsInUseLine: true,
Short: i18n.T("Sets a context entry in kubeconfig"), Short: i18n.T("Sets a context entry in kubeconfig"),
Long: create_context_long, Long: create_context_long,
Example: create_context_example, Example: create_context_example,
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
cmdutil.CheckErr(options.complete(cmd)) cmdutil.CheckErr(options.complete(cmd))
exists, err := options.run() name, exists, err := options.run()
cmdutil.CheckErr(err) cmdutil.CheckErr(err)
if exists { if exists {
fmt.Fprintf(out, "Context %q modified.\n", options.name) fmt.Fprintf(out, "Context %q modified.\n", name)
} else { } else {
fmt.Fprintf(out, "Context %q created.\n", options.name) fmt.Fprintf(out, "Context %q created.\n", name)
} }
}, },
} }
cmd.Flags().BoolVar(&options.currContext, "current", options.currContext, "Modify the current context")
cmd.Flags().Var(&options.cluster, clientcmd.FlagClusterName, clientcmd.FlagClusterName+" for the context entry in kubeconfig") cmd.Flags().Var(&options.cluster, clientcmd.FlagClusterName, clientcmd.FlagClusterName+" for the context entry in kubeconfig")
cmd.Flags().Var(&options.authInfo, clientcmd.FlagAuthInfoName, clientcmd.FlagAuthInfoName+" for the context entry in kubeconfig") cmd.Flags().Var(&options.authInfo, clientcmd.FlagAuthInfoName, clientcmd.FlagAuthInfoName+" for the context entry in kubeconfig")
cmd.Flags().Var(&options.namespace, clientcmd.FlagNamespace, clientcmd.FlagNamespace+" for the context entry in kubeconfig") cmd.Flags().Var(&options.namespace, clientcmd.FlagNamespace, clientcmd.FlagNamespace+" for the context entry in kubeconfig")
@ -78,29 +80,37 @@ func NewCmdConfigSetContext(out io.Writer, configAccess clientcmd.ConfigAccess)
return cmd return cmd
} }
func (o createContextOptions) run() (bool, error) { func (o createContextOptions) run() (string, bool, error) {
err := o.validate() err := o.validate()
if err != nil { if err != nil {
return false, err return "", false, err
} }
config, err := o.configAccess.GetStartingConfig() config, err := o.configAccess.GetStartingConfig()
if err != nil { if err != nil {
return false, err return "", false, err
} }
startingStanza, exists := config.Contexts[o.name] name := o.name
if o.currContext {
if len(config.CurrentContext) == 0 {
return "", false, errors.New("no current context is set")
}
name = config.CurrentContext
}
startingStanza, exists := config.Contexts[name]
if !exists { if !exists {
startingStanza = clientcmdapi.NewContext() startingStanza = clientcmdapi.NewContext()
} }
context := o.modifyContext(*startingStanza) context := o.modifyContext(*startingStanza)
config.Contexts[o.name] = &context config.Contexts[name] = &context
if err := clientcmd.ModifyConfig(o.configAccess, *config, true); err != nil { if err := clientcmd.ModifyConfig(o.configAccess, *config, true); err != nil {
return exists, err return name, exists, err
} }
return exists, nil return name, exists, nil
} }
func (o *createContextOptions) modifyContext(existingContext clientcmdapi.Context) clientcmdapi.Context { func (o *createContextOptions) modifyContext(existingContext clientcmdapi.Context) clientcmdapi.Context {
@ -121,17 +131,21 @@ func (o *createContextOptions) modifyContext(existingContext clientcmdapi.Contex
func (o *createContextOptions) complete(cmd *cobra.Command) error { func (o *createContextOptions) complete(cmd *cobra.Command) error {
args := cmd.Flags().Args() args := cmd.Flags().Args()
if len(args) != 1 { if len(args) > 1 {
return helpErrorf(cmd, "Unexpected args: %v", args) return helpErrorf(cmd, "Unexpected args: %v", args)
} }
if len(args) == 1 {
o.name = args[0] o.name = args[0]
}
return nil return nil
} }
func (o createContextOptions) validate() error { func (o createContextOptions) validate() error {
if len(o.name) == 0 { if len(o.name) == 0 && !o.currContext {
return errors.New("you must specify a non-empty context name") return errors.New("you must specify a non-empty context name or --current-context")
}
if len(o.name) > 0 && o.currContext {
return errors.New("you cannot specify a context name and --current-context")
} }
return nil return nil

View File

@ -28,6 +28,7 @@ import (
type createContextTest struct { type createContextTest struct {
description string description string
testContext string // name of the context being modified
config clientcmdapi.Config //initiate kubectl config config clientcmdapi.Config //initiate kubectl config
args []string //kubectl set-context args args []string //kubectl set-context args
flags []string //kubectl set-context flags flags []string //kubectl set-context flags
@ -38,6 +39,7 @@ type createContextTest struct {
func TestCreateContext(t *testing.T) { func TestCreateContext(t *testing.T) {
conf := clientcmdapi.Config{} conf := clientcmdapi.Config{}
test := createContextTest{ test := createContextTest{
testContext: "shaker-context",
description: "Testing for create a new context", description: "Testing for create a new context",
config: conf, config: conf,
args: []string{"shaker-context"}, args: []string{"shaker-context"},
@ -60,6 +62,7 @@ func TestModifyContext(t *testing.T) {
"shaker-context": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}, "shaker-context": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"},
"not-this": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}}} "not-this": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}}}
test := createContextTest{ test := createContextTest{
testContext: "shaker-context",
description: "Testing for modify a already exist context", description: "Testing for modify a already exist context",
config: conf, config: conf,
args: []string{"shaker-context"}, args: []string{"shaker-context"},
@ -77,6 +80,32 @@ func TestModifyContext(t *testing.T) {
test.run(t) test.run(t)
} }
func TestModifyCurrentContext(t *testing.T) {
conf := clientcmdapi.Config{
CurrentContext: "shaker-context",
Contexts: map[string]*clientcmdapi.Context{
"shaker-context": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"},
"not-this": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}}}
test := createContextTest{
testContext: "shaker-context",
description: "Testing for modify a current context",
config: conf,
args: []string{},
flags: []string{
"--current",
"--cluster=cluster_nickname",
"--user=user_nickname",
"--namespace=namespace",
},
expected: `Context "shaker-context" modified.` + "\n",
expectedConfig: clientcmdapi.Config{
Contexts: map[string]*clientcmdapi.Context{
"shaker-context": {AuthInfo: "user_nickname", Cluster: "cluster_nickname", Namespace: "namespace"},
"not-this": {AuthInfo: "blue-user", Cluster: "big-cluster", Namespace: "saw-ns"}}},
}
test.run(t)
}
func (test createContextTest) run(t *testing.T) { func (test createContextTest) run(t *testing.T) {
fakeKubeFile, err := ioutil.TempFile(os.TempDir(), "") fakeKubeFile, err := ioutil.TempFile(os.TempDir(), "")
if err != nil { if err != nil {
@ -108,8 +137,8 @@ func (test createContextTest) run(t *testing.T) {
} }
} }
if test.expectedConfig.Contexts != nil { if test.expectedConfig.Contexts != nil {
expectContext := test.expectedConfig.Contexts[test.args[0]] expectContext := test.expectedConfig.Contexts[test.testContext]
actualContext := config.Contexts[test.args[0]] actualContext := config.Contexts[test.testContext]
if expectContext.AuthInfo != actualContext.AuthInfo || expectContext.Cluster != actualContext.Cluster || if expectContext.AuthInfo != actualContext.AuthInfo || expectContext.Cluster != actualContext.Cluster ||
expectContext.Namespace != actualContext.Namespace { expectContext.Namespace != actualContext.Namespace {
t.Errorf("Fail in %q:\n expected Context %v\n but found %v in kubeconfig\n", test.description, expectContext, actualContext) t.Errorf("Fail in %q:\n expected Context %v\n but found %v in kubeconfig\n", test.description, expectContext, actualContext)