kubectl源码分析之delete

发布一个k8s部署视频:https://edu.csdn.net/course/detail/26967

课程内容:各种k8s部署方式。包括minikube部署,kubeadm部署,kubeasz部署,rancher部署,k3s部署。包括开发测试环境部署k8s,和生产环境部署k8s。

腾讯课堂连接地址https://ke.qq.com/course/478827?taid=4373109931462251&tuin=ba64518

第二个视频发布  https://edu.csdn.net/course/detail/27109

腾讯课堂连接地址https://ke.qq.com/course/484107?tuin=ba64518

介绍主要的k8s资源的使用配置和命令。包括configmap,pod,service,replicaset,namespace,deployment,daemonset,ingress,pv,pvc,sc,role,rolebinding,clusterrole,clusterrolebinding,secret,serviceaccount,statefulset,job,cronjob,podDisruptionbudget,podSecurityPolicy,networkPolicy,resourceQuota,limitrange,endpoint,event,conponentstatus,node,apiservice,controllerRevision等。

第三个视频发布:https://edu.csdn.net/course/detail/27574

详细介绍helm命令,学习helm chart语法,编写helm chart。深入分析各项目源码,学习编写helm插件

第四个课程发布:https://edu.csdn.net/course/detail/28488

本课程将详细介绍k8s所有命令,以及命令的go源码分析,学习知其然,知其所以然

 

加qq群,请联系:


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

type DeleteOptions struct {//delete结构体
	resource.FilenameOptions

	LabelSelector       string
	FieldSelector       string
	DeleteAll           bool
	DeleteAllNamespaces bool
	IgnoreNotFound      bool
	Cascade             bool
	DeleteNow           bool
	ForceDeletion       bool
	WaitForDeletion     bool
	Quiet               bool
	WarnClusterScope    bool
	Raw                 string

	GracePeriod int
	Timeout     time.Duration

	Output string

	DynamicClient dynamic.Interface
	Mapper        meta.RESTMapper
	Result        *resource.Result

	genericclioptions.IOStreams
}
func NewCmdDelete(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	deleteFlags := NewDeleteCommandFlags("containing the resource to delete.")//初始化deleteflags

	cmd := &cobra.Command{//cobra命令
		Use:                   "delete ([-f FILENAME] | [-k DIRECTORY] | TYPE [(NAME | -l label | --all)])",
		DisableFlagsInUseLine: true,
		Short:                 i18n.T("Delete resources by filenames, stdin, resources and names, or by resources and label selector"),
		Long:                  deleteLong,
		Example:               deleteExample,
		Run: func(cmd *cobra.Command, args []string) {
			o := deleteFlags.ToOptions(nil, streams)//deleteflag转deleteOption
			cmdutil.CheckErr(o.Complete(f, args, cmd))//准备
			cmdutil.CheckErr(o.Validate())//校验
			cmdutil.CheckErr(o.RunDelete(f))//运行
		},
		SuggestFor: []string{"rm"},
	}

	deleteFlags.AddFlags(cmd)//设置选项

	cmdutil.AddIncludeUninitializedFlag(cmd)
	return cmd
}
//准备
func (o *DeleteOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Command) error {
	cmdNamespace, enforceNamespace, err := f.ToRawKubeConfigLoader().Namespace()//获取namespace和enforcenamespace
	if err != nil {
		return err
	}

	o.WarnClusterScope = enforceNamespace && !o.DeleteAllNamespaces//设置warnClusterScope

	if o.DeleteAll || len(o.LabelSelector) > 0 || len(o.FieldSelector) > 0 {
		if f := cmd.Flags().Lookup("ignore-not-found"); f != nil && !f.Changed {
			// If the user didn't explicitly set the option, default to ignoring NotFound errors when used with --all, -l, or --field-selector
			o.IgnoreNotFound = true//如果是deleteall,或指定selector或指定field-selector则ignor-not-found我true
		}
	}
	if o.DeleteNow {//如果now为true
		if o.GracePeriod != -1 {//grace-period不为默认值报错
			return fmt.Errorf("--now and --grace-period cannot be specified together")
		}
		o.GracePeriod = 1//设置grace period为1
	}
	if o.GracePeriod == 0 && !o.ForceDeletion {//如果grace-period为0,并且不是force
		// To preserve backwards compatibility, but prevent accidental data loss, we convert --grace-period=0
		// into --grace-period=1. Users may provide --force to bypass this conversion.
		o.GracePeriod = 1//grace-period设置为1
	}

	if len(o.Raw) == 0 {
		r := f.NewBuilder().
			Unstructured().
			ContinueOnError().
			NamespaceParam(cmdNamespace).DefaultNamespace().
			FilenameParam(enforceNamespace, &o.FilenameOptions).
			LabelSelectorParam(o.LabelSelector).
			FieldSelectorParam(o.FieldSelector).
			SelectAllParam(o.DeleteAll).
			AllNamespaces(o.DeleteAllNamespaces).
			ResourceTypeOrNameArgs(false, args...).RequireObject(false).
			Flatten().
			Do()//构造result对象
		err = r.Err()
		if err != nil {
			return err
		}
		o.Result = r//设置result对象

		o.Mapper, err = f.ToRESTMapper()//设置mapper
		if err != nil {
			return err
		}

		o.DynamicClient, err = f.DynamicClient()//设置client
		if err != nil {
			return err
		}
	}

	return nil
}
//校验
func (o *DeleteOptions) Validate() error {
	if o.Output != "" && o.Output != "name" {//output必须是空或name
		return fmt.Errorf("unexpected -o output mode: %v. We only support '-o name'", o.Output)
	}

	if o.DeleteAll && len(o.LabelSelector) > 0 {//all和selector不能同时指定
		return fmt.Errorf("cannot set --all and --selector at the same time")
	}
	if o.DeleteAll && len(o.FieldSelector) > 0 {//all和field-selector不能同时指定
		return fmt.Errorf("cannot set --all and --field-selector at the same time")
	}

	switch {
	case o.GracePeriod == 0 && o.ForceDeletion://如果是grace-period为0,并且是force,则输出告警
		fmt.Fprintf(o.ErrOut, "warning: Immediate deletion does not wait for confirmation that the running resource has been terminated. The resource may continue to run on the cluster indefinitely.\n")
	case o.ForceDeletion://如果grace-period不为0,force为0,则输出告警
		fmt.Fprintf(o.ErrOut, "warning: --force is ignored because --grace-period is not 0.\n")
	}

	if len(o.Raw) > 0 {//raw大于0
		if len(o.FilenameOptions.Filenames) > 1 {//不能指定多个文件
			return fmt.Errorf("--raw can only use a single local file or stdin")
		} else if len(o.FilenameOptions.Filenames) == 1 {
			if strings.Index(o.FilenameOptions.Filenames[0], "http://") == 0 || strings.Index(o.FilenameOptions.Filenames[0], "https://") == 0 {//文件不能是url
				return fmt.Errorf("--raw cannot read from a url")
			}
		}

		if o.FilenameOptions.Recursive {//不能指定递归
			return fmt.Errorf("--raw and --recursive are mutually exclusive")
		}
		if len(o.Output) > 0 {//不能指定output
			return fmt.Errorf("--raw and --output are mutually exclusive")
		}
		if _, err := url.ParseRequestURI(o.Raw); err != nil {//url必须合法
			return fmt.Errorf("--raw must be a valid URL path: %v", err)
		}
	}

	return nil
}
//运行
func (o *DeleteOptions) RunDelete(f cmdutil.Factory) error {
	if len(o.Raw) > 0 {//如果指定了raw,则调用http处理
		restClient, err := f.RESTClient()
		if err != nil {
			return err
		}
		if len(o.Filenames) == 0 {
			return rawhttp.RawDelete(restClient, o.IOStreams, o.Raw, "")
		}
		return rawhttp.RawDelete(restClient, o.IOStreams, o.Raw, o.Filenames[0])
	}
	return o.DeleteResult(o.Result)//如果没有指定raw,则处理删除
}
//删除逻辑
func (o *DeleteOptions) DeleteResult(r *resource.Result) error {
	found := 0
	if o.IgnoreNotFound {
		r = r.IgnoreErrors(errors.IsNotFound)
	}
	warnClusterScope := o.WarnClusterScope
	deletedInfos := []*resource.Info{}
	uidMap := cmdwait.UIDMap{}
	err := r.Visit(func(info *resource.Info, err error) error {//visit info对象
		if err != nil {
			return err
		}
		deletedInfos = append(deletedInfos, info)//追加deleteInfo
		found++

		options := &metav1.DeleteOptions{}//创建delete option
		if o.GracePeriod >= 0 {
			options = metav1.NewDeleteOptions(int64(o.GracePeriod))//创建delete option
		}
		policy := metav1.DeletePropagationBackground
		if !o.Cascade {//如果cascade为false
			policy = metav1.DeletePropagationOrphan
		}
		options.PropagationPolicy = &policy//设置级联策略

		if warnClusterScope && info.Mapping.Scope.Name() == meta.RESTScopeNameRoot {//如果warnClusterScope为true,并且资源是集群资源则输出告警
			fmt.Fprintf(o.ErrOut, "warning: deleting cluster-scoped resources, not scoped to the provided namespace\n")
			warnClusterScope = false
		}
		response, err := o.deleteResource(info, options)//删除资源
		if err != nil {
			return err
		}
		resourceLocation := cmdwait.ResourceLocation{//创建资源位置
			GroupResource: info.Mapping.Resource.GroupResource(),
			Namespace:     info.Namespace,
			Name:          info.Name,
		}
		if status, ok := response.(*metav1.Status); ok && status.Details != nil {
			uidMap[resourceLocation] = status.Details.UID//设置uidMap
			return nil
		}
		responseMetadata, err := meta.Accessor(response)
		if err != nil {
			// we don't have UID, but we didn't fail the delete, next best thing is just skipping the UID
			klog.V(1).Info(err)
			return nil
		}
		uidMap[resourceLocation] = responseMetadata.GetUID()//设置uidmap

		return nil
	})
	if err != nil {
		return err
	}
	if found == 0 {//资源没找到则打印没找到,并返回
		fmt.Fprintf(o.Out, "No resources found\n")
		return nil
	}
	if !o.WaitForDeletion {//不等待则返回
		return nil
	}
	// if we don't have a dynamic client, we don't want to wait.  Eventually when delete is cleaned up, this will likely
	// drop out.
	if o.DynamicClient == nil {//client为空,返回
		return nil
	}

	effectiveTimeout := o.Timeout
	if effectiveTimeout == 0 {
		// if we requested to wait forever, set it to a week.
		effectiveTimeout = 168 * time.Hour
	}
	waitOptions := cmdwait.WaitOptions{//创建等待选项
		ResourceFinder: genericclioptions.ResourceFinderForResult(resource.InfoListVisitor(deletedInfos)),
		UIDMap:         uidMap,
		DynamicClient:  o.DynamicClient,
		Timeout:        effectiveTimeout,

		Printer:     printers.NewDiscardingPrinter(),
		ConditionFn: cmdwait.IsDeleted,
		IOStreams:   o.IOStreams,
	}
	err = waitOptions.RunWait() //等待删除完成
	if errors.IsForbidden(err) || errors.IsMethodNotSupported(err) {
		// if we're forbidden from waiting, we shouldn't fail.
		// if the resource doesn't support a verb we need, we shouldn't fail.
		klog.V(1).Info(err)
		return nil
	}
	return err
}

func (o *DeleteOptions) deleteResource(info *resource.Info, deleteOptions *metav1.DeleteOptions) (runtime.Object, error) {//删除资源
	deleteResponse, err := resource.NewHelper(info.Client, info.Mapping).DeleteWithOptions(info.Namespace, info.Name, deleteOptions)//删除服务器资源
	if err != nil {
		return nil, cmdutil.AddSourceToErr("deleting", info.Source, err)
	}

	if !o.Quiet {//如果不为quiet,则打印结果
		o.PrintObj(info)
	}
	return deleteResponse, nil
}

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(kubectl源码分析之delete)