kubectl源码分析之auth can-i

发布一个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源码分析,学习知其然,知其所以然
————————————————

//创建auth命令
func NewCmdAuth(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	// Parent command to which all subcommands are added.
	cmds := &cobra.Command{//创建cobra命令
		Use:   "auth",
		Short: "Inspect authorization",
		Long:  `Inspect authorization`,
		Run:   cmdutil.DefaultSubCommandRun(streams.ErrOut),
	}

	cmds.AddCommand(NewCmdCanI(f, streams))//添加can-i子命令
	cmds.AddCommand(NewCmdReconcile(f, streams))//添加reconcile子命令

	return cmds
}
type CanIOptions struct {//can-i结构体
	AllNamespaces   bool
	Quiet           bool
	NoHeaders       bool
	Namespace       string
	AuthClient      authorizationv1client.AuthorizationV1Interface
	DiscoveryClient discovery.DiscoveryInterface

	Verb           string
	Resource       schema.GroupVersionResource
	NonResourceURL string
	Subresource    string
	ResourceName   string
	List           bool

	genericclioptions.IOStreams
}
//创建can-i命令
func NewCmdCanI(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.Command {
	o := &CanIOptions{//初始化结构体
		IOStreams: streams,
	}

	cmd := &cobra.Command{//创建cobra命令
		Use:                   "can-i VERB [TYPE | TYPE/NAME | NONRESOURCEURL]",
		DisableFlagsInUseLine: true,
		Short:                 "Check whether an action is allowed",
		Long:                  canILong,
		Example:               canIExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, args))//准备
			cmdutil.CheckErr(o.Validate())//校验
			var err error
			if o.List {//如果指定--list
				err = o.RunAccessList()//运行list
			} else {
				var allowed bool
				allowed, err = o.RunAccessCheck()//运行check
				if err == nil {
					if !allowed {
						os.Exit(1)
					}
				}
			}
			cmdutil.CheckErr(err)
		},
	}

	cmd.Flags().BoolVarP(&o.AllNamespaces, "all-namespaces", "A", o.AllNamespaces, "If true, check the specified action in all namespaces.")//all-namespaces选项
	cmd.Flags().BoolVarP(&o.Quiet, "quiet", "q", o.Quiet, "If true, suppress output and just return the exit code.")//quiet选项
	cmd.Flags().StringVar(&o.Subresource, "subresource", o.Subresource, "SubResource such as pod/log or deployment/scale")//subresource选项
	cmd.Flags().BoolVar(&o.List, "list", o.List, "If true, prints all allowed actions.")//list选项
	cmd.Flags().BoolVar(&o.NoHeaders, "no-headers", o.NoHeaders, "If true, prints allowed actions without headers")//no-headers选项
	return cmd
}
//准备
func (o *CanIOptions) Complete(f cmdutil.Factory, args []string) error {
	if o.List {//如果指定了--list
		if len(args) != 0 {//参数不等于0个报错
			return errors.New("list option must be specified with no arguments")
		}
	} else {
		if o.Quiet {//指定了quiet
			o.Out = ioutil.Discard//设置out
		}

		switch len(args) {//判断参数个数
		case 2://为2个
			o.Verb = args[0]//第0个位动作
			if strings.HasPrefix(args[1], "/") {//第1个参数有/开头
				o.NonResourceURL = args[1]//设置非资源url
				break
			}
			resourceTokens := strings.SplitN(args[1], "/", 2)//用/分割
			restMapper, err := f.ToRESTMapper()//获取restMapper
			if err != nil {
				return err
			}
			o.Resource = o.resourceFor(restMapper, resourceTokens[0])//设置资源
			if len(resourceTokens) > 1 {
				o.ResourceName = resourceTokens[1]//设置资源名称
			}
		default:
			return errors.New("you must specify two or three arguments: verb, resource, and optional resourceName")//报错
		}
	}

	var err error
	client, err := f.KubernetesClientSet()//获取clientset
	if err != nil {
		return err
	}
	o.AuthClient = client.AuthorizationV1()//从clientset获取authClient
	o.DiscoveryClient = client.Discovery()//从clientset获取discoberyClient
	o.Namespace = ""//设置namespace为空
	if !o.AllNamespaces {//没有指定all-namespaces
		o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()//设置namespace
		if err != nil {
			return err
		}
	}

	return nil
}
//校验
func (o *CanIOptions) Validate() error {
	if o.List {//指定了list
		if o.Quiet || o.AllNamespaces || o.Subresource != "" {//list不能和这三个同时指定
			return errors.New("list option can't be specified with neither quiet, all-namespaces nor subresource options")
		}
		return nil
	}

	if o.NonResourceURL != "" {//指定了非资源url
		if o.Subresource != "" {//不能同时指定子资源
			return fmt.Errorf("--subresource can not be used with NonResourceURL")
		}
		if o.Resource != (schema.GroupVersionResource{}) || o.ResourceName != "" {//不能同时指定资源名称
			return fmt.Errorf("NonResourceURL and ResourceName can not specified together")
		}
	} else if !o.Resource.Empty() && !o.AllNamespaces && o.DiscoveryClient != nil {
		if namespaced, err := isNamespaced(o.Resource, o.DiscoveryClient); err == nil && !namespaced {//判断资源是否集群范围
			if len(o.Resource.Group) == 0 {//输出告警
				fmt.Fprintf(o.ErrOut, "Warning: resource '%s' is not namespace scoped\n", o.Resource.Resource)
			} else {
				fmt.Fprintf(o.ErrOut, "Warning: resource '%s' is not namespace scoped in group '%s'\n", o.Resource.Resource, o.Resource.Group)
			}
		}
	}

	if o.NoHeaders {//no-headers必须和list同时指定
		return fmt.Errorf("--no-headers cannot be set without --list specified")
	}
	return nil
}
//执行list
func (o *CanIOptions) RunAccessList() error {
	sar := &authorizationv1.SelfSubjectRulesReview{//创建SelfSubjectRulesReview
		Spec: authorizationv1.SelfSubjectRulesReviewSpec{
			Namespace: o.Namespace,
		},
	}
	response, err := o.AuthClient.SelfSubjectRulesReviews().Create(sar)//应用SelfSubjectRulesReview到服务端
	if err != nil {
		return err
	}

	return o.printStatus(response.Status)//输出结果
}
//执行check
func (o *CanIOptions) RunAccessCheck() (bool, error) {
	var sar *authorizationv1.SelfSubjectAccessReview//定义SelfSubjectAccessReview
	if o.NonResourceURL == "" {//非资源url为空
		sar = &authorizationv1.SelfSubjectAccessReview{//创建SelfSubjectAccessReview
			Spec: authorizationv1.SelfSubjectAccessReviewSpec{
				ResourceAttributes: &authorizationv1.ResourceAttributes{
					Namespace:   o.Namespace,
					Verb:        o.Verb,
					Group:       o.Resource.Group,
					Resource:    o.Resource.Resource,
					Subresource: o.Subresource,
					Name:        o.ResourceName,
				},
			},
		}
	} else {
		sar = &authorizationv1.SelfSubjectAccessReview{//创建SelfSubjectAccessReview
			Spec: authorizationv1.SelfSubjectAccessReviewSpec{
				NonResourceAttributes: &authorizationv1.NonResourceAttributes{
					Verb: o.Verb,
					Path: o.NonResourceURL,
				},
			},
		}
	}

	response, err := o.AuthClient.SelfSubjectAccessReviews().Create(sar)//应用SelfSubjectAccessReview到服务端
	if err != nil {
		return false, err
	}

	if response.Status.Allowed {//结果为allowed打印yes
		fmt.Fprintln(o.Out, "yes")
	} else {
		fmt.Fprint(o.Out, "no")//打印no
		if len(response.Status.Reason) > 0 {//打印reason
			fmt.Fprintf(o.Out, " - %v", response.Status.Reason)
		}
		if len(response.Status.EvaluationError) > 0 {//打印EvaluationError
			fmt.Fprintf(o.Out, " - %v", response.Status.EvaluationError)
		}
		fmt.Fprintln(o.Out)
	}

	return response.Status.Allowed, nil
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(kubectl源码分析之auth can-i)