kubectl源码分析之replace

 欢迎关注我的公众号:

 目前刚开始写一个月,一共写了18篇原创文章,文章目录如下:

istio多集群探秘,部署了50次多集群后我得出的结论

istio多集群链路追踪,附实操视频

istio防故障利器,你知道几个,istio新手不要读,太难!

istio业务权限控制,原来可以这么玩

istio实现非侵入压缩,微服务之间如何实现压缩

不懂envoyfilter也敢说精通istio系列-http-rbac-不要只会用AuthorizationPolicy配置权限

不懂envoyfilter也敢说精通istio系列-02-http-corsFilter-不要只会vs

不懂envoyfilter也敢说精通istio系列-03-http-csrf filter-再也不用再代码里写csrf逻辑了

不懂envoyfilter也敢说精通istio系列http-jwt_authn-不要只会RequestAuthorization

不懂envoyfilter也敢说精通istio系列-05-fault-filter-故障注入不止是vs

不懂envoyfilter也敢说精通istio系列-06-http-match-配置路由不只是vs

不懂envoyfilter也敢说精通istio系列-07-负载均衡配置不止是dr

不懂envoyfilter也敢说精通istio系列-08-连接池和断路器

不懂envoyfilter也敢说精通istio系列-09-http-route filter

不懂envoyfilter也敢说精通istio系列-network filter-redis proxy

不懂envoyfilter也敢说精通istio系列-network filter-HttpConnectionManager

不懂envoyfilter也敢说精通istio系列-ratelimit-istio ratelimit完全手册

 

————————————————

type ReplaceOptions struct {//replace结构体
	PrintFlags  *genericclioptions.PrintFlags
	RecordFlags *genericclioptions.RecordFlags

	DeleteFlags   *delete.DeleteFlags
	DeleteOptions *delete.DeleteOptions

	PrintObj func(obj runtime.Object) error

	createAnnotation bool
	validate         bool

	Schema      validation.Schema
	Builder     func() *resource.Builder
	BuilderArgs []string

	Namespace        string
	EnforceNamespace bool
	Raw              string

	Recorder genericclioptions.Recorder

	genericclioptions.IOStreams
}
func NewReplaceOptions(streams genericclioptions.IOStreams) *ReplaceOptions {
	return &ReplaceOptions{//初始化结构体
		PrintFlags:  genericclioptions.NewPrintFlags("replaced"),
		DeleteFlags: delete.NewDeleteFlags("to use to replace the resource."),

		IOStreams: streams,
	}
}
//创建replace命令
func NewCmdReplace(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	o := NewReplaceOptions(streams)//初始化结构体

	cmd := &cobra.Command{//创建cobra命令
		Use:                   "replace -f FILENAME",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Replace a resource by filename or stdin"),
		Long:                  replaceLong,
		Example:               replaceExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, cmd, args))//准备
			cmdutil.CheckErr(o.Validate(cmd))//校验
			cmdutil.CheckErr(o.Run(f))//运行
		},
	}

	o.PrintFlags.AddFlags(cmd)//打印选项
	o.DeleteFlags.AddFlags(cmd)//删除选项
	o.RecordFlags.AddFlags(cmd)//record选项

	cmdutil.AddValidateFlags(cmd)//校验选项
	cmdutil.AddApplyAnnotationFlags(cmd)//save-config选项

	cmd.Flags().StringVar(&o.Raw, "raw", o.Raw, "Raw URI to PUT to the server.  Uses the transport specified by the kubeconfig file.")//raw选项

	return cmd
}
//准备
func (o *ReplaceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
	var err error

	o.RecordFlags.Complete(cmd)//record准备
	o.Recorder, err = o.RecordFlags.ToRecorder()//record flag转recorder
	if err != nil {
		return err
	}

	o.validate = cmdutil.GetFlagBool(cmd, "validate")//设置validate
	o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)//设置createAnnotation

	printer, err := o.PrintFlags.ToPrinter()//print flag转printer
	if err != nil {
		return err
	}
	o.PrintObj = func(obj runtime.Object) error {//设置printObj函数
		return printer.PrintObj(obj, o.Out)
	}

	dynamicClient, err := f.DynamicClient()//获取dynamicClient
	if err != nil {
		return err
	}
	deleteOpts := o.DeleteFlags.ToOptions(dynamicClient, o.IOStreams)//deleteflag转deleteOption

	//Replace will create a resource if it doesn't exist already, so ignore not found error
	deleteOpts.IgnoreNotFound = true//设置IgnoreNotFound 
	if o.PrintFlags.OutputFormat != nil {
		deleteOpts.Output = *o.PrintFlags.OutputFormat//设置Output 
	}
	if deleteOpts.GracePeriod == 0 {//设置GracePeriod 和WaitForDeletion 
		// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
		// into --grace-period=1 and wait until the object is successfully deleted.
		deleteOpts.GracePeriod = 1
		deleteOpts.WaitForDeletion = true
	}
	o.DeleteOptions = deleteOpts//设置DeleteOptions 

	err = o.DeleteOptions.FilenameOptions.RequireFilenameOrKustomize()//文件是必须的
	if err != nil {
		return err
	}

	schema, err := f.Validator(o.validate)//获取validator
	if err != nil {
		return err
	}

	o.Schema = schema//设置validateSchema
	o.Builder = f.NewBuilder//设置builder
	o.BuilderArgs = args//设置参数

	o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()//设置namespace和enforceNamespace
	if err != nil {
		return err
	}

	return nil
}
//校验
func (o *ReplaceOptions) Validate(cmd *cobra.Command) error {
	if o.DeleteOptions.GracePeriod >= 0 && !o.DeleteOptions.ForceDeletion {//如果指定了grace-period必须指定force
		return fmt.Errorf("--grace-period must have --force specified")
	}

	if o.DeleteOptions.Timeout != 0 && !o.DeleteOptions.ForceDeletion {//如果指定了timeout必须指定force
		return fmt.Errorf("--timeout must have --force specified")
	}

	if cmdutil.IsFilenameSliceEmpty(o.DeleteOptions.FilenameOptions.Filenames, o.DeleteOptions.FilenameOptions.Kustomize) {//文件是必须的
		return cmdutil.UsageErrorf(cmd, "Must specify --filename to replace")
	}

	if len(o.Raw) > 0 {//如果指定了--raw
		if len(o.DeleteOptions.FilenameOptions.Filenames) != 1 {//只能指定一个文件
			return cmdutil.UsageErrorf(cmd, "--raw can only use a single local file or stdin")
		}
		if strings.Index(o.DeleteOptions.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.DeleteOptions.FilenameOptions.Filenames[0], "https://") == 0 {//不能是url
			return cmdutil.UsageErrorf(cmd, "--raw cannot read from a url")
		}
		if o.DeleteOptions.FilenameOptions.Recursive {//不能指定递归
			return cmdutil.UsageErrorf(cmd, "--raw and --recursive are mutually exclusive")
		}
		if len(cmdutil.GetFlagString(cmd, "output")) > 0 {//不能指定output
			return cmdutil.UsageErrorf(cmd, "--raw and --output are mutually exclusive")
		}
		if _, err := url.ParseRequestURI(o.Raw); err != nil {//raw必须是有效url
			return cmdutil.UsageErrorf(cmd, "--raw must be a valid URL path: %v", err)
		}
	}

	return nil
}
//运行
func (o *ReplaceOptions) Run(f cmdutil.Factory) error {
	// raw only makes sense for a single file resource multiple objects aren't likely to do what you want.
	// the validator enforces this, so
	if len(o.Raw) > 0 {//如果指定了raw
		restClient, err := f.RESTClient()
		if err != nil {
			return err
		}
		return rawhttp.RawPut(restClient, o.IOStreams, o.Raw, o.DeleteOptions.Filenames[0])//执行rawPut
	}

	if o.DeleteOptions.ForceDeletion {//如果指定了force
		return o.forceReplace()//执行先删除后创建
	}

	r := o.Builder().
		Unstructured().
		Schema(o.Schema).
		ContinueOnError().
		NamespaceParam(o.Namespace).DefaultNamespace().
		FilenameParam(o.EnforceNamespace, &o.DeleteOptions.FilenameOptions).
		Flatten().
		Do()//用builder构造result对象
	if err := r.Err(); err != nil {
		return err
	}

	return r.Visit(func(info *resource.Info, err error) error {//visit result
		if err != nil {
			return err
		}

		if err := util.CreateOrUpdateAnnotation(o.createAnnotation, info.Object, scheme.DefaultJSONEncoder()); err != nil {//判断是否创建last-applied-configuration注解
			return cmdutil.AddSourceToErr("replacing", info.Source, err)
		}

		if err := o.Recorder.Record(info.Object); err != nil {//判断是否创建change-cause注解
			klog.V(4).Infof("error recording current command: %v", err)
		}

		// Serialize the object with the annotation applied.
		obj, err := resource.NewHelper(info.Client, info.Mapping).Replace(info.Namespace, info.Name, true, info.Object)//replace对象到服务端
		if err != nil {
			return cmdutil.AddSourceToErr("replacing", info.Source, err)
		}

		info.Refresh(obj, true)//刷新对象
		return o.PrintObj(info.Object)//打印对象
	})
}
//执行先删除后创建
func (o *ReplaceOptions) forceReplace() error {
	for i, filename := range o.DeleteOptions.FilenameOptions.Filenames {//遍历文件
		if filename == "-" {//如果文件是-
			tempDir, err := ioutil.TempDir("", "kubectl_replace_")//创建临时目录
			if err != nil {
				return err
			}
			defer os.RemoveAll(tempDir)//defer删除临时目录
			tempFilename := filepath.Join(tempDir, "resource.stdin")//构造文件名称
			err = cmdutil.DumpReaderToFile(os.Stdin, tempFilename)//输出stdin到文件
			if err != nil {
				return err
			}
			o.DeleteOptions.FilenameOptions.Filenames[i] = tempFilename//设置文件
		}
	}

	r := o.Builder().
		Unstructured().
		ContinueOnError().
		NamespaceParam(o.Namespace).DefaultNamespace().
		ResourceTypeOrNameArgs(false, o.BuilderArgs...).RequireObject(false).
		FilenameParam(o.EnforceNamespace, &o.DeleteOptions.FilenameOptions).
		Flatten().
		Do()//用builder构造result对象
	if err := r.Err(); err != nil {
		return err
	}

	if err := o.DeleteOptions.DeleteResult(r); err != nil {//删除对象
		return err
	}

	timeout := o.DeleteOptions.Timeout
	if timeout == 0 {//如果没指定timeout,则timeout为5分钟
		timeout = 5 * time.Minute
	}
	err := r.Visit(func(info *resource.Info, err error) error {//访问result
		if err != nil {
			return err
		}

		return wait.PollImmediate(1*time.Second, timeout, func() (bool, error) {//等待删除成功
			if err := info.Get(); !errors.IsNotFound(err) {
				return false, err
			}
			return true, nil
		})
	})
	if err != nil {
		return err
	}

	r = o.Builder().
		Unstructured().
		Schema(o.Schema).
		ContinueOnError().
		NamespaceParam(o.Namespace).DefaultNamespace().
		FilenameParam(o.EnforceNamespace, &o.DeleteOptions.FilenameOptions).
		Flatten().
		Do()//用build构造result对象
	err = r.Err()
	if err != nil {
		return err
	}

	count := 0
	err = r.Visit(func(info *resource.Info, err error) error {// visit result
		if err != nil {
			return err
		}

		if err := util.CreateOrUpdateAnnotation(o.createAnnotation, info.Object, scheme.DefaultJSONEncoder()); err != nil {//判断是否创建last-applied-configuration注解
			return err
		}

		if err := o.Recorder.Record(info.Object); err != nil {//判断是否创建change-cause注解
			klog.V(4).Infof("error recording current command: %v", err)
		}

		obj, err := resource.NewHelper(info.Client, info.Mapping).Create(info.Namespace, true, info.Object, nil)//创建对象到服务端
		if err != nil {
			return err
		}

		count++
		info.Refresh(obj, true)//刷新对象
		return o.PrintObj(info.Object)//打印对象
	})
	if err != nil {
		return err
	}
	if count == 0 {
		return fmt.Errorf("no objects passed to replace")
	}
	return nil
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

hxpjava1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值