1
16
17 package config
18
19 import (
20 "errors"
21 "fmt"
22 "io"
23
24 "github.com/spf13/cobra"
25
26 "k8s.io/client-go/tools/clientcmd"
27 clientcmdapi "k8s.io/client-go/tools/clientcmd/api"
28 cliflag "k8s.io/component-base/cli/flag"
29 cmdutil "k8s.io/kubectl/pkg/cmd/util"
30 "k8s.io/kubectl/pkg/util/completion"
31 "k8s.io/kubectl/pkg/util/i18n"
32 "k8s.io/kubectl/pkg/util/templates"
33 )
34
35 type setContextOptions struct {
36 configAccess clientcmd.ConfigAccess
37 name string
38 currContext bool
39 cluster cliflag.StringFlag
40 authInfo cliflag.StringFlag
41 namespace cliflag.StringFlag
42 }
43
44 var (
45 setContextLong = templates.LongDesc(i18n.T(`
46 Set a context entry in kubeconfig.
47
48 Specifying a name that already exists will merge new fields on top of existing values for those fields.`))
49
50 setContextExample = templates.Examples(`
51 # Set the user field on the gce context entry without touching other values
52 kubectl config set-context gce --user=cluster-admin`)
53 )
54
55
56 func NewCmdConfigSetContext(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command {
57 options := &setContextOptions{configAccess: configAccess}
58
59 cmd := &cobra.Command{
60 Use: fmt.Sprintf("set-context [NAME | --current] [--%v=cluster_nickname] [--%v=user_nickname] [--%v=namespace]", clientcmd.FlagClusterName, clientcmd.FlagAuthInfoName, clientcmd.FlagNamespace),
61 DisableFlagsInUseLine: true,
62 Short: i18n.T("Set a context entry in kubeconfig"),
63 Long: setContextLong,
64 Example: setContextExample,
65 ValidArgsFunction: completion.ContextCompletionFunc,
66 Run: func(cmd *cobra.Command, args []string) {
67 cmdutil.CheckErr(options.complete(cmd))
68 name, exists, err := options.run()
69 cmdutil.CheckErr(err)
70 if exists {
71 fmt.Fprintf(out, "Context %q modified.\n", name)
72 } else {
73 fmt.Fprintf(out, "Context %q created.\n", name)
74 }
75 },
76 }
77
78 cmd.Flags().BoolVar(&options.currContext, "current", options.currContext, "Modify the current context")
79 cmd.Flags().Var(&options.cluster, clientcmd.FlagClusterName, clientcmd.FlagClusterName+" for the context entry in kubeconfig")
80 cmd.Flags().Var(&options.authInfo, clientcmd.FlagAuthInfoName, clientcmd.FlagAuthInfoName+" for the context entry in kubeconfig")
81 cmd.Flags().Var(&options.namespace, clientcmd.FlagNamespace, clientcmd.FlagNamespace+" for the context entry in kubeconfig")
82
83 return cmd
84 }
85
86 func (o setContextOptions) run() (string, bool, error) {
87 err := o.validate()
88 if err != nil {
89 return "", false, err
90 }
91
92 config, err := o.configAccess.GetStartingConfig()
93 if err != nil {
94 return "", false, err
95 }
96
97 name := o.name
98 if o.currContext {
99 if len(config.CurrentContext) == 0 {
100 return "", false, errors.New("no current context is set")
101 }
102 name = config.CurrentContext
103 }
104
105 startingStanza, exists := config.Contexts[name]
106 if !exists {
107 startingStanza = clientcmdapi.NewContext()
108 }
109 context := o.modifyContext(*startingStanza)
110 config.Contexts[name] = &context
111
112 if err := clientcmd.ModifyConfig(o.configAccess, *config, true); err != nil {
113 return name, exists, err
114 }
115
116 return name, exists, nil
117 }
118
119 func (o *setContextOptions) modifyContext(existingContext clientcmdapi.Context) clientcmdapi.Context {
120 modifiedContext := existingContext
121
122 if o.cluster.Provided() {
123 modifiedContext.Cluster = o.cluster.Value()
124 }
125 if o.authInfo.Provided() {
126 modifiedContext.AuthInfo = o.authInfo.Value()
127 }
128 if o.namespace.Provided() {
129 modifiedContext.Namespace = o.namespace.Value()
130 }
131
132 return modifiedContext
133 }
134
135 func (o *setContextOptions) complete(cmd *cobra.Command) error {
136 args := cmd.Flags().Args()
137 if len(args) > 1 {
138 return helpErrorf(cmd, "Unexpected args: %v", args)
139 }
140 if len(args) == 1 {
141 o.name = args[0]
142 }
143 return nil
144 }
145
146 func (o setContextOptions) validate() error {
147 if len(o.name) == 0 && !o.currContext {
148 return errors.New("you must specify a non-empty context name or --current")
149 }
150 if len(o.name) > 0 && o.currContext {
151 return errors.New("you cannot specify both a context name and --current")
152 }
153
154 return nil
155 }
156
View as plain text