...

Source file src/k8s.io/kubectl/pkg/cmd/create/create_rolebinding.go

Documentation: k8s.io/kubectl/pkg/cmd/create

     1  /*
     2  Copyright 2016 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package create
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  
    24  	"github.com/spf13/cobra"
    25  
    26  	rbacv1 "k8s.io/api/rbac/v1"
    27  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    28  	"k8s.io/apimachinery/pkg/runtime"
    29  	"k8s.io/cli-runtime/pkg/genericclioptions"
    30  	"k8s.io/cli-runtime/pkg/genericiooptions"
    31  	rbacclientv1 "k8s.io/client-go/kubernetes/typed/rbac/v1"
    32  	cmdutil "k8s.io/kubectl/pkg/cmd/util"
    33  	"k8s.io/kubectl/pkg/scheme"
    34  	"k8s.io/kubectl/pkg/util"
    35  	"k8s.io/kubectl/pkg/util/i18n"
    36  	"k8s.io/kubectl/pkg/util/templates"
    37  )
    38  
    39  var (
    40  	roleBindingLong = templates.LongDesc(i18n.T(`
    41  		Create a role binding for a particular role or cluster role.`))
    42  
    43  	roleBindingExample = templates.Examples(i18n.T(`
    44  		# Create a role binding for user1, user2, and group1 using the admin cluster role
    45  		kubectl create rolebinding admin --clusterrole=admin --user=user1 --user=user2 --group=group1
    46  
    47  		# Create a role binding for serviceaccount monitoring:sa-dev using the admin role
    48  		kubectl create rolebinding admin-binding --role=admin --serviceaccount=monitoring:sa-dev`))
    49  )
    50  
    51  // RoleBindingOptions holds the options for 'create rolebinding' sub command
    52  type RoleBindingOptions struct {
    53  	PrintFlags *genericclioptions.PrintFlags
    54  	PrintObj   func(obj runtime.Object) error
    55  
    56  	Name             string
    57  	Namespace        string
    58  	EnforceNamespace bool
    59  	ClusterRole      string
    60  	Role             string
    61  	Users            []string
    62  	Groups           []string
    63  	ServiceAccounts  []string
    64  	FieldManager     string
    65  	CreateAnnotation bool
    66  
    67  	Client              rbacclientv1.RbacV1Interface
    68  	DryRunStrategy      cmdutil.DryRunStrategy
    69  	ValidationDirective string
    70  
    71  	genericiooptions.IOStreams
    72  }
    73  
    74  // NewRoleBindingOptions creates a new *RoleBindingOptions with sane defaults
    75  func NewRoleBindingOptions(ioStreams genericiooptions.IOStreams) *RoleBindingOptions {
    76  	return &RoleBindingOptions{
    77  		Users:           []string{},
    78  		Groups:          []string{},
    79  		ServiceAccounts: []string{},
    80  		PrintFlags:      genericclioptions.NewPrintFlags("created").WithTypeSetter(scheme.Scheme),
    81  		IOStreams:       ioStreams,
    82  	}
    83  }
    84  
    85  // NewCmdCreateRoleBinding returns an initialized Command instance for 'create rolebinding' sub command
    86  func NewCmdCreateRoleBinding(f cmdutil.Factory, ioStreams genericiooptions.IOStreams) *cobra.Command {
    87  	o := NewRoleBindingOptions(ioStreams)
    88  
    89  	cmd := &cobra.Command{
    90  		Use:                   "rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run=server|client|none]",
    91  		DisableFlagsInUseLine: true,
    92  		Short:                 i18n.T("Create a role binding for a particular role or cluster role"),
    93  		Long:                  roleBindingLong,
    94  		Example:               roleBindingExample,
    95  		Run: func(cmd *cobra.Command, args []string) {
    96  			cmdutil.CheckErr(o.Complete(f, cmd, args))
    97  			cmdutil.CheckErr(o.Validate())
    98  			cmdutil.CheckErr(o.Run())
    99  		},
   100  	}
   101  
   102  	o.PrintFlags.AddFlags(cmd)
   103  
   104  	cmdutil.AddApplyAnnotationFlags(cmd)
   105  	cmdutil.AddValidateFlags(cmd)
   106  	cmdutil.AddDryRunFlag(cmd)
   107  	cmd.Flags().StringVar(&o.ClusterRole, "clusterrole", "", i18n.T("ClusterRole this RoleBinding should reference"))
   108  	cmd.Flags().StringVar(&o.Role, "role", "", i18n.T("Role this RoleBinding should reference"))
   109  	cmd.Flags().StringArrayVar(&o.Users, "user", o.Users, "Usernames to bind to the role. The flag can be repeated to add multiple users.")
   110  	cmd.Flags().StringArrayVar(&o.Groups, "group", o.Groups, "Groups to bind to the role. The flag can be repeated to add multiple groups.")
   111  	cmd.Flags().StringArrayVar(&o.ServiceAccounts, "serviceaccount", o.ServiceAccounts, "Service accounts to bind to the role, in the format <namespace>:<name>. The flag can be repeated to add multiple service accounts.")
   112  	cmdutil.AddFieldManagerFlagVar(cmd, &o.FieldManager, "kubectl-create")
   113  	return cmd
   114  }
   115  
   116  // Complete completes all the required options
   117  func (o *RoleBindingOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
   118  	var err error
   119  	o.Name, err = NameFromCommandArgs(cmd, args)
   120  	if err != nil {
   121  		return err
   122  	}
   123  	clientConfig, err := f.ToRESTConfig()
   124  	if err != nil {
   125  		return err
   126  	}
   127  	o.Client, err = rbacclientv1.NewForConfig(clientConfig)
   128  	if err != nil {
   129  		return err
   130  	}
   131  
   132  	o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
   133  	if err != nil {
   134  		return err
   135  	}
   136  
   137  	o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag)
   138  	o.DryRunStrategy, err = cmdutil.GetDryRunStrategy(cmd)
   139  	if err != nil {
   140  		return err
   141  	}
   142  	cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy)
   143  	printer, err := o.PrintFlags.ToPrinter()
   144  	if err != nil {
   145  		return err
   146  	}
   147  	o.PrintObj = func(obj runtime.Object) error {
   148  		return printer.PrintObj(obj, o.Out)
   149  	}
   150  
   151  	o.ValidationDirective, err = cmdutil.GetValidationDirective(cmd)
   152  	return err
   153  }
   154  
   155  // Validate validates required fields are set
   156  func (o *RoleBindingOptions) Validate() error {
   157  	if len(o.Name) == 0 {
   158  		return fmt.Errorf("name must be specified")
   159  	}
   160  	if (len(o.ClusterRole) == 0) == (len(o.Role) == 0) {
   161  		return fmt.Errorf("exactly one of clusterrole or role must be specified")
   162  	}
   163  	return nil
   164  }
   165  
   166  // Run performs the execution of 'create rolebinding' sub command
   167  func (o *RoleBindingOptions) Run() error {
   168  	roleBinding, err := o.createRoleBinding()
   169  	if err != nil {
   170  		return err
   171  	}
   172  	if err := util.CreateOrUpdateAnnotation(o.CreateAnnotation, roleBinding, scheme.DefaultJSONEncoder()); err != nil {
   173  		return err
   174  	}
   175  
   176  	if o.DryRunStrategy != cmdutil.DryRunClient {
   177  		createOptions := metav1.CreateOptions{}
   178  		if o.FieldManager != "" {
   179  			createOptions.FieldManager = o.FieldManager
   180  		}
   181  		createOptions.FieldValidation = o.ValidationDirective
   182  		if o.DryRunStrategy == cmdutil.DryRunServer {
   183  			createOptions.DryRun = []string{metav1.DryRunAll}
   184  		}
   185  		roleBinding, err = o.Client.RoleBindings(o.Namespace).Create(context.TODO(), roleBinding, createOptions)
   186  		if err != nil {
   187  			return fmt.Errorf("failed to create rolebinding: %v", err)
   188  		}
   189  	}
   190  	return o.PrintObj(roleBinding)
   191  }
   192  
   193  func (o *RoleBindingOptions) createRoleBinding() (*rbacv1.RoleBinding, error) {
   194  	namespace := ""
   195  	if o.EnforceNamespace {
   196  		namespace = o.Namespace
   197  	}
   198  
   199  	roleBinding := &rbacv1.RoleBinding{
   200  		TypeMeta: metav1.TypeMeta{APIVersion: rbacv1.SchemeGroupVersion.String(), Kind: "RoleBinding"},
   201  		ObjectMeta: metav1.ObjectMeta{
   202  			Name:      o.Name,
   203  			Namespace: namespace,
   204  		},
   205  	}
   206  
   207  	switch {
   208  	case len(o.Role) > 0:
   209  		roleBinding.RoleRef = rbacv1.RoleRef{
   210  			APIGroup: rbacv1.GroupName,
   211  			Kind:     "Role",
   212  			Name:     o.Role,
   213  		}
   214  	case len(o.ClusterRole) > 0:
   215  		roleBinding.RoleRef = rbacv1.RoleRef{
   216  			APIGroup: rbacv1.GroupName,
   217  			Kind:     "ClusterRole",
   218  			Name:     o.ClusterRole,
   219  		}
   220  	}
   221  
   222  	for _, user := range o.Users {
   223  		roleBinding.Subjects = append(roleBinding.Subjects, rbacv1.Subject{
   224  			Kind:     rbacv1.UserKind,
   225  			APIGroup: rbacv1.GroupName,
   226  			Name:     user,
   227  		})
   228  	}
   229  
   230  	for _, group := range o.Groups {
   231  		roleBinding.Subjects = append(roleBinding.Subjects, rbacv1.Subject{
   232  			Kind:     rbacv1.GroupKind,
   233  			APIGroup: rbacv1.GroupName,
   234  			Name:     group,
   235  		})
   236  	}
   237  
   238  	for _, sa := range o.ServiceAccounts {
   239  		tokens := strings.Split(sa, ":")
   240  		if len(tokens) != 2 || tokens[0] == "" || tokens[1] == "" {
   241  			return nil, fmt.Errorf("serviceaccount must be <namespace>:<name>")
   242  		}
   243  		roleBinding.Subjects = append(roleBinding.Subjects, rbacv1.Subject{
   244  			Kind:      rbacv1.ServiceAccountKind,
   245  			APIGroup:  "",
   246  			Namespace: tokens[0],
   247  			Name:      tokens[1],
   248  		})
   249  	}
   250  	return roleBinding, nil
   251  }
   252  

View as plain text