2019-01-12 04:58:27 +00:00
/ *
Copyright 2016 The Kubernetes Authors .
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
You may obtain a copy of the License at
http : //www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing , software
distributed under the License is distributed on an "AS IS" BASIS ,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
See the License for the specific language governing permissions and
limitations under the License .
* /
package create
import (
2020-12-01 01:06:26 +00:00
"context"
"fmt"
"strings"
2019-01-12 04:58:27 +00:00
"github.com/spf13/cobra"
2020-12-01 01:06:26 +00:00
rbacv1 "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
2019-01-12 04:58:27 +00:00
"k8s.io/cli-runtime/pkg/genericclioptions"
2020-12-01 01:06:26 +00:00
"k8s.io/cli-runtime/pkg/resource"
rbacclientv1 "k8s.io/client-go/kubernetes/typed/rbac/v1"
2019-09-27 21:51:53 +00:00
cmdutil "k8s.io/kubectl/pkg/cmd/util"
2020-12-01 01:06:26 +00:00
"k8s.io/kubectl/pkg/scheme"
"k8s.io/kubectl/pkg/util"
2019-09-27 21:51:53 +00:00
"k8s.io/kubectl/pkg/util/i18n"
"k8s.io/kubectl/pkg/util/templates"
2019-01-12 04:58:27 +00:00
)
var (
roleBindingLong = templates . LongDesc ( i18n . T ( `
2021-07-02 08:43:15 +00:00
Create a role binding for a particular role or cluster role . ` ) )
2019-01-12 04:58:27 +00:00
roleBindingExample = templates . Examples ( i18n . T ( `
2021-07-02 08:43:15 +00:00
# Create a role binding for user1 , user2 , and group1 using the admin cluster role
2019-01-12 04:58:27 +00:00
kubectl create rolebinding admin -- clusterrole = admin -- user = user1 -- user = user2 -- group = group1 ` ) )
)
2021-03-18 22:40:29 +00:00
// RoleBindingOptions holds the options for 'create rolebinding' sub command
2020-12-01 01:06:26 +00:00
type RoleBindingOptions struct {
PrintFlags * genericclioptions . PrintFlags
PrintObj func ( obj runtime . Object ) error
Name string
Namespace string
EnforceNamespace bool
ClusterRole string
Role string
Users [ ] string
Groups [ ] string
ServiceAccounts [ ] string
FieldManager string
CreateAnnotation bool
Client rbacclientv1 . RbacV1Interface
DryRunStrategy cmdutil . DryRunStrategy
DryRunVerifier * resource . DryRunVerifier
genericclioptions . IOStreams
}
// NewRoleBindingOptions creates a new *RoleBindingOptions with sane defaults
func NewRoleBindingOptions ( ioStreams genericclioptions . IOStreams ) * RoleBindingOptions {
return & RoleBindingOptions {
Users : [ ] string { } ,
Groups : [ ] string { } ,
ServiceAccounts : [ ] string { } ,
PrintFlags : genericclioptions . NewPrintFlags ( "created" ) . WithTypeSetter ( scheme . Scheme ) ,
IOStreams : ioStreams ,
}
2019-01-12 04:58:27 +00:00
}
2019-04-07 17:07:55 +00:00
// NewCmdCreateRoleBinding returns an initialized Command instance for 'create rolebinding' sub command
2019-01-12 04:58:27 +00:00
func NewCmdCreateRoleBinding ( f cmdutil . Factory , ioStreams genericclioptions . IOStreams ) * cobra . Command {
2020-12-01 01:06:26 +00:00
o := NewRoleBindingOptions ( ioStreams )
2019-01-12 04:58:27 +00:00
cmd := & cobra . Command {
2020-03-26 21:07:15 +00:00
Use : "rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run=server|client|none]" ,
2019-01-12 04:58:27 +00:00
DisableFlagsInUseLine : true ,
2021-07-02 08:43:15 +00:00
Short : i18n . T ( "Create a role binding for a particular role or cluster role" ) ,
2019-01-12 04:58:27 +00:00
Long : roleBindingLong ,
Example : roleBindingExample ,
Run : func ( cmd * cobra . Command , args [ ] string ) {
2019-04-07 17:07:55 +00:00
cmdutil . CheckErr ( o . Complete ( f , cmd , args ) )
2020-12-01 01:06:26 +00:00
cmdutil . CheckErr ( o . Validate ( ) )
2019-04-07 17:07:55 +00:00
cmdutil . CheckErr ( o . Run ( ) )
2019-01-12 04:58:27 +00:00
} ,
}
2020-12-01 01:06:26 +00:00
o . PrintFlags . AddFlags ( cmd )
2019-01-12 04:58:27 +00:00
cmdutil . AddApplyAnnotationFlags ( cmd )
cmdutil . AddValidateFlags ( cmd )
2020-12-01 01:06:26 +00:00
cmdutil . AddDryRunFlag ( cmd )
cmd . Flags ( ) . StringVar ( & o . ClusterRole , "clusterrole" , "" , i18n . T ( "ClusterRole this RoleBinding should reference" ) )
cmd . Flags ( ) . StringVar ( & o . Role , "role" , "" , i18n . T ( "Role this RoleBinding should reference" ) )
cmd . Flags ( ) . StringArrayVar ( & o . Users , "user" , o . Users , "Usernames to bind to the role" )
cmd . Flags ( ) . StringArrayVar ( & o . Groups , "group" , o . Groups , "Groups to bind to the role" )
cmd . Flags ( ) . StringArrayVar ( & o . ServiceAccounts , "serviceaccount" , o . ServiceAccounts , "Service accounts to bind to the role, in the format <namespace>:<name>" )
cmdutil . AddFieldManagerFlagVar ( cmd , & o . FieldManager , "kubectl-create" )
2019-01-12 04:58:27 +00:00
return cmd
}
2019-04-07 17:07:55 +00:00
// Complete completes all the required options
2020-12-01 01:06:26 +00:00
func ( o * RoleBindingOptions ) Complete ( f cmdutil . Factory , cmd * cobra . Command , args [ ] string ) error {
var err error
o . Name , err = NameFromCommandArgs ( cmd , args )
if err != nil {
return err
}
clientConfig , err := f . ToRESTConfig ( )
if err != nil {
return err
}
o . Client , err = rbacclientv1 . NewForConfig ( clientConfig )
2019-01-12 04:58:27 +00:00
if err != nil {
return err
}
2020-12-01 01:06:26 +00:00
o . Namespace , o . EnforceNamespace , err = f . ToRawKubeConfigLoader ( ) . Namespace ( )
if err != nil {
return err
2019-01-12 04:58:27 +00:00
}
2020-12-01 01:06:26 +00:00
o . CreateAnnotation = cmdutil . GetFlagBool ( cmd , cmdutil . ApplyAnnotationsFlag )
o . DryRunStrategy , err = cmdutil . GetDryRunStrategy ( cmd )
if err != nil {
return err
}
dynamicCient , err := f . DynamicClient ( )
if err != nil {
return err
}
2021-03-18 22:40:29 +00:00
o . DryRunVerifier = resource . NewDryRunVerifier ( dynamicCient , f . OpenAPIGetter ( ) )
2020-12-01 01:06:26 +00:00
cmdutil . PrintFlagsWithDryRunStrategy ( o . PrintFlags , o . DryRunStrategy )
printer , err := o . PrintFlags . ToPrinter ( )
if err != nil {
return err
}
o . PrintObj = func ( obj runtime . Object ) error {
return printer . PrintObj ( obj , o . Out )
}
return nil
2019-01-12 04:58:27 +00:00
}
2020-12-01 01:06:26 +00:00
// Validate validates required fields are set
func ( o * RoleBindingOptions ) Validate ( ) error {
if len ( o . Name ) == 0 {
return fmt . Errorf ( "name must be specified" )
}
if ( len ( o . ClusterRole ) == 0 ) == ( len ( o . Role ) == 0 ) {
return fmt . Errorf ( "exactly one of clusterrole or role must be specified" )
}
return nil
}
// Run performs the execution of 'create rolebinding' sub command
func ( o * RoleBindingOptions ) Run ( ) error {
roleBinding , err := o . createRoleBinding ( )
if err != nil {
return err
}
if err := util . CreateOrUpdateAnnotation ( o . CreateAnnotation , roleBinding , scheme . DefaultJSONEncoder ( ) ) ; err != nil {
return err
}
if o . DryRunStrategy != cmdutil . DryRunClient {
createOptions := metav1 . CreateOptions { }
if o . FieldManager != "" {
createOptions . FieldManager = o . FieldManager
}
if o . DryRunStrategy == cmdutil . DryRunServer {
if err := o . DryRunVerifier . HasSupport ( roleBinding . GroupVersionKind ( ) ) ; err != nil {
return err
}
createOptions . DryRun = [ ] string { metav1 . DryRunAll }
}
roleBinding , err = o . Client . RoleBindings ( o . Namespace ) . Create ( context . TODO ( ) , roleBinding , createOptions )
if err != nil {
return fmt . Errorf ( "failed to create rolebinding: %v" , err )
}
}
return o . PrintObj ( roleBinding )
}
func ( o * RoleBindingOptions ) createRoleBinding ( ) ( * rbacv1 . RoleBinding , error ) {
namespace := ""
if o . EnforceNamespace {
namespace = o . Namespace
}
roleBinding := & rbacv1 . RoleBinding {
TypeMeta : metav1 . TypeMeta { APIVersion : rbacv1 . SchemeGroupVersion . String ( ) , Kind : "RoleBinding" } ,
ObjectMeta : metav1 . ObjectMeta {
Name : o . Name ,
Namespace : namespace ,
} ,
}
switch {
case len ( o . Role ) > 0 :
roleBinding . RoleRef = rbacv1 . RoleRef {
APIGroup : rbacv1 . GroupName ,
Kind : "Role" ,
Name : o . Role ,
}
case len ( o . ClusterRole ) > 0 :
roleBinding . RoleRef = rbacv1 . RoleRef {
APIGroup : rbacv1 . GroupName ,
Kind : "ClusterRole" ,
Name : o . ClusterRole ,
}
}
for _ , user := range o . Users {
roleBinding . Subjects = append ( roleBinding . Subjects , rbacv1 . Subject {
Kind : rbacv1 . UserKind ,
APIGroup : rbacv1 . GroupName ,
Name : user ,
} )
}
for _ , group := range o . Groups {
roleBinding . Subjects = append ( roleBinding . Subjects , rbacv1 . Subject {
Kind : rbacv1 . GroupKind ,
APIGroup : rbacv1 . GroupName ,
Name : group ,
} )
}
for _ , sa := range o . ServiceAccounts {
tokens := strings . Split ( sa , ":" )
if len ( tokens ) != 2 || tokens [ 0 ] == "" || tokens [ 1 ] == "" {
return nil , fmt . Errorf ( "serviceaccount must be <namespace>:<name>" )
}
roleBinding . Subjects = append ( roleBinding . Subjects , rbacv1 . Subject {
Kind : rbacv1 . ServiceAccountKind ,
APIGroup : "" ,
Namespace : tokens [ 0 ] ,
Name : tokens [ 1 ] ,
} )
}
return roleBinding , nil
2019-01-12 04:58:27 +00:00
}