type createContextOptions struct {//setcontext结构体 configAccess clientcmd.ConfigAccess name string currContext bool cluster cliflag.StringFlag authInfo cliflag.StringFlag namespace cliflag.StringFlag }
//创建set-context命令 func NewCmdConfigSetContext(out io.Writer, configAccess clientcmd.ConfigAccess) *cobra.Command { options := &createContextOptions{configAccess: configAccess}//初始化结构体 cmd := &cobra.Command{//创建cobra命令 Use: fmt.Sprintf("set-context [NAME | --current] [--%v=cluster_nickname] [--%v=user_nickname] [--%v=namespace]", clientcmd.FlagClusterName, clientcmd.FlagAuthInfoName, clientcmd.FlagNamespace), DisableFlagsInUseLine: true, Short: i18n.T("Sets a context entry in kubeconfig"), Long: createContextLong, Example: createContextExample, Run: func(cmd *cobra.Command, args []string) { cmdutil.CheckErr(options.complete(cmd))//准备 name, exists, err := options.run()//运行 cmdutil.CheckErr(err) if exists { fmt.Fprintf(out, "Context %q modified.\n", name)//打印结果 } else { fmt.Fprintf(out, "Context %q created.\n", name) } }, } cmd.Flags().BoolVar(&options.currContext, "current", options.currContext, "Modify the current context")//current选项 cmd.Flags().Var(&options.cluster, clientcmd.FlagClusterName, clientcmd.FlagClusterName+" for the context entry in kubeconfig")//cluster选项 cmd.Flags().Var(&options.authInfo, clientcmd.FlagAuthInfoName, clientcmd.FlagAuthInfoName+" for the context entry in kubeconfig")//user选项 cmd.Flags().Var(&options.namespace, clientcmd.FlagNamespace, clientcmd.FlagNamespace+" for the context entry in kubeconfig")//namespace选项 return cmd }
//准备 func (o *createContextOptions) complete(cmd *cobra.Command) error { args := cmd.Flags().Args()//获取参数 if len(args) > 1 {//参数不能大于1个 return helpErrorf(cmd, "Unexpected args: %v", args) } if len(args) == 1 {//如果参数为1个,设置name o.name = args[0] } return nil }
//运行 func (o createContextOptions) run() (string, bool, error) { err := o.validate()//校验 if err != nil { return "", false, err } config, err := o.configAccess.GetStartingConfig()//加载config if err != nil { return "", false, err } name := o.name if o.currContext {//如果指定了current if len(config.CurrentContext) == 0 {//如果当前config currentcontext为空报错 return "", false, errors.New("no current context is set") } name = config.CurrentContext//设置name为currentContext } startingStanza, exists := config.Contexts[name]//判断context是否存在 if !exists {//不存在则创建 startingStanza = clientcmdapi.NewContext() } context := o.modifyContext(*startingStanza)//修改context config.Contexts[name] = &context//设置context if err := clientcmd.ModifyConfig(o.configAccess, *config, true); err != nil {//把配置写会文件 return name, exists, err } return name, exists, nil }
//校验 func (o createContextOptions) validate() error { if len(o.name) == 0 && !o.currContext {//名称和currnetContext不能同时为空 return errors.New("you must specify a non-empty context name or --current") } if len(o.name) > 0 && o.currContext {//名称和currentcontext不能同时指定 return errors.New("you cannot specify both a context name and --current") } return nil }
//修改context func (o *createContextOptions) modifyContext(existingContext clientcmdapi.Context) clientcmdapi.Context { modifiedContext := existingContext if o.cluster.Provided() {//如果cluster有值设置cluster modifiedContext.Cluster = o.cluster.Value() } if o.authInfo.Provided() {//如果authinfo有值,设置authinfo modifiedContext.AuthInfo = o.authInfo.Value() } if o.namespace.Provided() {//如果namespace有值设置namespace modifiedContext.Namespace = o.namespace.Value() } return modifiedContext }