kubectl源码分析之create role

 欢迎关注我的公众号:

 目前刚开始写一个月,一共写了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完全手册

 

————————————————----------------------------------------------------------------------------------------

var (
	roleLong = templates.LongDesc(i18n.T(`
		Create a role with single rule.`))

	roleExample = templates.Examples(i18n.T(`
		# Create a Role named "pod-reader" that allows user to perform "get", "watch" and "list" on pods
		kubectl create role pod-reader --verb=get --verb=list --verb=watch --resource=pods

		# Create a Role named "pod-reader" with ResourceName specified
		kubectl create role pod-reader --verb=get --resource=pods --resource-name=readablepod --resource-name=anotherpod

		# Create a Role named "foo" with API Group specified
		kubectl create role foo --verb=get,list,watch --resource=rs.extensions

		# Create a Role named "foo" with SubResource specified
		kubectl create role foo --verb=get,list,watch --resource=pods,pods/status`))

	// Valid resource verb list for validation.
    //有效动作
	validResourceVerbs = []string{"*", "get", "delete", "list", "create", "update", "patch", "watch", "proxy", "deletecollection", "use", "bind", "escalate", "impersonate"}

	// Specialized verbs and GroupResources
	specialVerbs = map[string][]schema.GroupResource{//特殊动作资源
		"use": {
			{
				Group:    "extensions",
				Resource: "podsecuritypolicies",
			},
		},
		"bind": {
			{
				Group:    "rbac.authorization.k8s.io",
				Resource: "roles",
			},
			{
				Group:    "rbac.authorization.k8s.io",
				Resource: "clusterroles",
			},
		},
		"escalate": {
			{
				Group:    "rbac.authorization.k8s.io",
				Resource: "roles",
			},
			{
				Group:    "rbac.authorization.k8s.io",
				Resource: "clusterroles",
			},
		},
		"impersonate": {
			{
				Group:    "",
				Resource: "users",
			},
			{
				Group:    "",
				Resource: "serviceaccounts",
			},
			{
				Group:    "",
				Resource: "groups",
			},
			{
				Group:    "authentication.k8s.io",
				Resource: "userextras",
			},
		},
	}
)
type ResourceOptions struct {//resource结构体
	Group       string
	Resource    string
	SubResource string
}

// CreateRoleOptions holds the options for 'create role' sub command
type CreateRoleOptions struct {//create role 结构体
	PrintFlags *genericclioptions.PrintFlags

	Name          string
	Verbs         []string
	Resources     []ResourceOptions
	ResourceNames []string

	DryRun       bool
	OutputFormat string
	Namespace    string
	Client       clientgorbacv1.RbacV1Interface
	Mapper       meta.RESTMapper
	PrintObj     func(obj runtime.Object) error

	genericclioptions.IOStreams
}
func NewCreateRoleOptions(ioStreams genericclioptions.IOStreams) *CreateRoleOptions {
	return &CreateRoleOptions{创建create role结构体
		PrintFlags: genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),

		IOStreams: ioStreams,
	}
}
//创建create role 命令
func NewCmdCreateRole(f cmdutil.Factory, ioStreams genericclioptions.IOStreams) *cobra.Command {
	o := NewCreateRoleOptions(ioStreams)//初始化结构体

	cmd := &cobra.Command{//创建cobra命令
		Use:                   "role NAME --verb=verb --resource=resource.group/subresource [--resource-name=resourcename] [--dry-run]",
		DisableFlagsInUseLine: true,
		Short:                 roleLong,
		Long:                  roleLong,
		Example:               roleExample,
		Run: func(cmd *cobra.Command, args []string) {
			cmdutil.CheckErr(o.Complete(f, cmd, args))//准备运行
			cmdutil.CheckErr(o.Validate())//校验参数
			cmdutil.CheckErr(o.RunCreateRole())//运行
		},
	}

	o.PrintFlags.AddFlags(cmd)//设置print选项

	cmdutil.AddApplyAnnotationFlags(cmd)//创建save-config选项
	cmdutil.AddValidateFlags(cmd)//创建validate选项
	cmdutil.AddDryRunFlag(cmd)//创建dry-run选项
	cmd.Flags().StringSliceVar(&o.Verbs, "verb", o.Verbs, "Verb that applies to the resources contained in the rule")//创建verb选项
	cmd.Flags().StringSlice("resource", []string{}, "Resource that the rule applies to")//创建resource选项
	cmd.Flags().StringArrayVar(&o.ResourceNames, "resource-name", o.ResourceNames, "Resource in the white list that the rule applies to, repeat this flag for multiple items")//创建resource-name选项

	return cmd
}
//准备函数
func (o *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
	name, err := NameFromCommandArgs(cmd, args)//获取名称
	if err != nil {
		return err
	}
	o.Name = name//设置名称

	// Remove duplicate verbs.
	verbs := []string{}
	for _, v := range o.Verbs {//遍历verb
		// VerbAll respresents all kinds of verbs.
		if v == "*" {
			verbs = []string{"*"}//*跳出循环
			break
		}
		if !arrayContains(verbs, v) {//verb去重
			verbs = append(verbs, v)
		}
	}
	o.Verbs = verbs//设置verb

	// Support resource.group pattern. If no API Group specified, use "" as core API Group.
	// e.g. --resource=pods,deployments.extensions
	resources := cmdutil.GetFlagStringSlice(cmd, "resource")//获取资源
	for _, r := range resources {//遍历资源
		sections := strings.SplitN(r, "/", 2)//用/分割

		resource := &ResourceOptions{}
		if len(sections) == 2 {//设置子资源
			resource.SubResource = sections[1]
		}

		parts := strings.SplitN(sections[0], ".", 2)//用.分割
		if len(parts) == 2 {//设置group
			resource.Group = parts[1]
		}
		resource.Resource = parts[0]//设置resource

		if resource.Resource == "*" && len(parts) == 1 && len(sections) == 1 {
			o.Resources = []ResourceOptions{*resource}//如果是*,跳出循环
			break
		}

		o.Resources = append(o.Resources, *resource)//追加资源
	}

	// Remove duplicate resource names.
	resourceNames := []string{}
	for _, n := range o.ResourceNames {//遍历resource-name
		if !arrayContains(resourceNames, n) {//resource-name去重
			resourceNames = append(resourceNames, n)
		}
	}
	o.ResourceNames = resourceNames//设置resource-name

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

	o.DryRun = cmdutil.GetDryRunFlag(cmd)//设置dry-run
	o.OutputFormat = cmdutil.GetFlagString(cmd, "output")//设置output

	if o.DryRun {
		o.PrintFlags.Complete("%s (dry run)")//dry-run准备函数
	}
	printer, err := o.PrintFlags.ToPrinter()//printflag转printer
	if err != nil {
		return err
	}
	o.PrintObj = func(obj runtime.Object) error {//设置printObj函数
		return printer.PrintObj(obj, o.Out)
	}

	o.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()获取namespace
	if err != nil {
		return err
	}

	clientset, err := f.KubernetesClientSet()//获取clientset
	if err != nil {
		return err
	}
	o.Client = clientset.RbacV1()//设置client

	return nil
}
//校验参数
func (o *CreateRoleOptions) Validate() error {
	if o.Name == "" {//名称为空报错
		return fmt.Errorf("name must be specified")
	}

	// validate verbs.
	if len(o.Verbs) == 0 {//动作为空报错
		return fmt.Errorf("at least one verb must be specified")
	}

	for _, v := range o.Verbs {//遍历动作
		if !arrayContains(validResourceVerbs, v) {//判断动作是否有效
			return fmt.Errorf("invalid verb: '%s'", v)
		}
	}

	// validate resources.
	if len(o.Resources) == 0 {//资源为空报错
		return fmt.Errorf("at least one resource must be specified")
	}

	return o.validateResource()//校验资源
}
//校验资源
func (o *CreateRoleOptions) validateResource() error {
	for _, r := range o.Resources {//遍历资源
		if len(r.Resource) == 0 {// 资源名称为空报错
			return fmt.Errorf("resource must be specified if apiGroup/subresource specified")
		}
		if r.Resource == "*" {//资源为*直接返回
			return nil
		}

		resource := schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}
		groupVersionResource, err := o.Mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group})//获取groupversionresource
		if err == nil {
			resource = groupVersionResource
		}

		for _, v := range o.Verbs {//遍历动作
			if groupResources, ok := specialVerbs[v]; ok {//判断是否特殊动作
				match := false
				for _, extra := range groupResources {//如果是特殊动作,遍历特殊动作的资源
					if resource.Resource == extra.Resource && resource.Group == extra.Group {
						match = true//如果特殊动作资源包含需校验的资源则match为true
						err = nil
						break
					}
				}
				if !match {//不match报错
					return fmt.Errorf("can not perform '%s' on '%s' in group '%s'", v, resource.Resource, resource.Group)
				}
			}
		}

		if err != nil {
			return err
		}
	}
	return nil
}
//运行命令
func (o *CreateRoleOptions) RunCreateRole() error {
	role := &rbacv1.Role{//构造role对象
		// this is ok because we know exactly how we want to be serialized
		TypeMeta: metav1.TypeMeta{APIVersion: rbacv1.SchemeGroupVersion.String(), Kind: "Role"},
	}
	role.Name = o.Name//设置名称
	rules, err := generateResourcePolicyRules(o.Mapper, o.Verbs, o.Resources, o.ResourceNames, []string{})//生成policyroles
	if err != nil {
		return err
	}
	role.Rules = rules//设置PolicyRules

	// Create role.
	if !o.DryRun {//非干跑
		role, err = o.Client.Roles(o.Namespace).Create(role)//创建role对象
		if err != nil {
			return err
		}
	}

	return o.PrintObj(role)//打印结果
}
//创建PolicyRoles
func generateResourcePolicyRules(mapper meta.RESTMapper, verbs []string, resources []ResourceOptions, resourceNames []string, nonResourceURLs []string) ([]rbacv1.PolicyRule, error) {
	// groupResourceMapping is a apigroup-resource map. The key of this map is api group, while the value
	// is a string array of resources under this api group.
	// E.g.  groupResourceMapping = {"extensions": ["replicasets", "deployments"], "batch":["jobs"]}
	groupResourceMapping := map[string][]string{}//构造map

	// This loop does the following work:
	// 1. Constructs groupResourceMapping based on input resources.
	// 2. Prevents pointing to non-existent resources.
	// 3. Transfers resource short name to long name. E.g. rs.extensions is transferred to replicasets.extensions
	for _, r := range resources {//遍历resource
		resource := schema.GroupVersionResource{Resource: r.Resource, Group: r.Group}
		groupVersionResource, err := mapper.ResourceFor(schema.GroupVersionResource{Resource: r.Resource, Group: r.Group})//获取groupversionresource
		if err == nil {
			resource = groupVersionResource
		}

		if len(r.SubResource) > 0 {//如果有子资源,则资源加子资源
			resource.Resource = resource.Resource + "/" + r.SubResource
		}
		if !arrayContains(groupResourceMapping[resource.Group], resource.Resource) {
			groupResourceMapping[resource.Group] = append(groupResourceMapping[resource.Group], resource.Resource)//如果map的group不包含资源,则添加
		}
	}

	// Create separate rule for each of the api group.
	rules := []rbacv1.PolicyRule{}//创建PolicyRule slice
	for _, g := range sets.StringKeySet(groupResourceMapping).List() {//遍历map的key
		rule := rbacv1.PolicyRule{}//创建PolicyRule
		rule.Verbs = verbs//设置动作
		rule.Resources = groupResourceMapping[g]//设置资源
		rule.APIGroups = []string{g}//设置apigroup
		rule.ResourceNames = resourceNames//设置资源名称
		rules = append(rules, rule)//追加
	}

	if len(nonResourceURLs) > 0 {//如果non-resource-url有值
		rule := rbacv1.PolicyRule{}//创建PolicyRule
		rule.Verbs = verbs// 设置动作
		rule.NonResourceURLs = nonResourceURLs//设置non-resource-url
		rules = append(rules, rule)
	}

	return rules, nil//返回rules
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

hxpjava1

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

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

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

打赏作者

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

抵扣说明:

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

余额充值