@@ -17,12 +17,21 @@ limitations under the License.
17
17
package create
18
18
19
19
import (
20
+ "context"
21
+ "fmt"
22
+ "strings"
23
+
20
24
"github.com/spf13/cobra"
21
25
26
+ rbacv1 "k8s.io/api/rbac/v1"
27
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
28
+ "k8s.io/apimachinery/pkg/runtime"
22
29
"k8s.io/cli-runtime/pkg/genericclioptions"
30
+ "k8s.io/cli-runtime/pkg/resource"
31
+ rbacclientv1 "k8s.io/client-go/kubernetes/typed/rbac/v1"
23
32
cmdutil "k8s.io/kubectl/pkg/cmd/util"
24
- "k8s.io/kubectl/pkg/generate "
25
- generateversioned "k8s.io/kubectl/pkg/generate/versioned "
33
+ "k8s.io/kubectl/pkg/scheme "
34
+ "k8s.io/kubectl/pkg/util "
26
35
"k8s.io/kubectl/pkg/util/i18n"
27
36
"k8s.io/kubectl/pkg/util/templates"
28
37
)
@@ -37,15 +46,42 @@ var (
37
46
)
38
47
39
48
// RoleBindingOpts holds the options for 'create rolebinding' sub command
40
- type RoleBindingOpts struct {
41
- CreateSubcommandOptions * CreateSubcommandOptions
49
+ type RoleBindingOptions struct {
50
+ PrintFlags * genericclioptions.PrintFlags
51
+ PrintObj func (obj runtime.Object ) error
52
+
53
+ Name string
54
+ Namespace string
55
+ EnforceNamespace bool
56
+ ClusterRole string
57
+ Role string
58
+ Users []string
59
+ Groups []string
60
+ ServiceAccounts []string
61
+ FieldManager string
62
+ CreateAnnotation bool
63
+
64
+ Client rbacclientv1.RbacV1Interface
65
+ DryRunStrategy cmdutil.DryRunStrategy
66
+ DryRunVerifier * resource.DryRunVerifier
67
+
68
+ genericclioptions.IOStreams
69
+ }
70
+
71
+ // NewRoleBindingOptions creates a new *RoleBindingOptions with sane defaults
72
+ func NewRoleBindingOptions (ioStreams genericclioptions.IOStreams ) * RoleBindingOptions {
73
+ return & RoleBindingOptions {
74
+ Users : []string {},
75
+ Groups : []string {},
76
+ ServiceAccounts : []string {},
77
+ PrintFlags : genericclioptions .NewPrintFlags ("created" ).WithTypeSetter (scheme .Scheme ),
78
+ IOStreams : ioStreams ,
79
+ }
42
80
}
43
81
44
82
// NewCmdCreateRoleBinding returns an initialized Command instance for 'create rolebinding' sub command
45
83
func NewCmdCreateRoleBinding (f cmdutil.Factory , ioStreams genericclioptions.IOStreams ) * cobra.Command {
46
- o := & RoleBindingOpts {
47
- CreateSubcommandOptions : NewCreateSubcommandOptions (ioStreams ),
48
- }
84
+ o := NewRoleBindingOptions (ioStreams )
49
85
50
86
cmd := & cobra.Command {
51
87
Use : "rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run=server|client|none]" ,
@@ -55,50 +91,167 @@ func NewCmdCreateRoleBinding(f cmdutil.Factory, ioStreams genericclioptions.IOSt
55
91
Example : roleBindingExample ,
56
92
Run : func (cmd * cobra.Command , args []string ) {
57
93
cmdutil .CheckErr (o .Complete (f , cmd , args ))
94
+ cmdutil .CheckErr (o .Validate ())
58
95
cmdutil .CheckErr (o .Run ())
59
96
},
60
97
}
61
98
62
- o .CreateSubcommandOptions . PrintFlags .AddFlags (cmd )
99
+ o .PrintFlags .AddFlags (cmd )
63
100
64
101
cmdutil .AddApplyAnnotationFlags (cmd )
65
102
cmdutil .AddValidateFlags (cmd )
66
- cmdutil .AddGeneratorFlags (cmd , generateversioned . RoleBindingV1GeneratorName )
67
- cmd .Flags ().String ( "clusterrole" , "" , i18n .T ("ClusterRole this RoleBinding should reference" ))
68
- cmd .Flags ().String ( "role" , "" , i18n .T ("Role this RoleBinding should reference" ))
69
- cmd .Flags ().StringArray ( "user" , [] string {} , "Usernames to bind to the role" )
70
- cmd .Flags ().StringArray ( "group" , [] string {} , "Groups to bind to the role" )
71
- cmd .Flags ().StringArray ( "serviceaccount" , [] string {} , "Service accounts to bind to the role, in the format <namespace>:<name>" )
72
- cmdutil .AddFieldManagerFlagVar (cmd , & o .CreateSubcommandOptions . FieldManager , "kubectl-create" )
103
+ cmdutil .AddDryRunFlag (cmd )
104
+ cmd .Flags ().StringVar ( & o . ClusterRole , "clusterrole" , "" , i18n .T ("ClusterRole this RoleBinding should reference" ))
105
+ cmd .Flags ().StringVar ( & o . Role , "role" , "" , i18n .T ("Role this RoleBinding should reference" ))
106
+ cmd .Flags ().StringArrayVar ( & o . Users , "user" , o . Users , "Usernames to bind to the role" )
107
+ cmd .Flags ().StringArrayVar ( & o . Groups , "group" , o . Groups , "Groups to bind to the role" )
108
+ cmd .Flags ().StringArrayVar ( & o . ServiceAccounts , "serviceaccount" , o . ServiceAccounts , "Service accounts to bind to the role, in the format <namespace>:<name>" )
109
+ cmdutil .AddFieldManagerFlagVar (cmd , & o .FieldManager , "kubectl-create" )
73
110
return cmd
74
111
}
75
112
76
113
// Complete completes all the required options
77
- func (o * RoleBindingOpts ) Complete (f cmdutil.Factory , cmd * cobra.Command , args []string ) error {
78
- name , err := NameFromCommandArgs (cmd , args )
114
+ func (o * RoleBindingOptions ) Complete (f cmdutil.Factory , cmd * cobra.Command , args []string ) error {
115
+ var err error
116
+ o .Name , err = NameFromCommandArgs (cmd , args )
117
+ if err != nil {
118
+ return err
119
+ }
120
+ clientConfig , err := f .ToRESTConfig ()
121
+ if err != nil {
122
+ return err
123
+ }
124
+ o .Client , err = rbacclientv1 .NewForConfig (clientConfig )
79
125
if err != nil {
80
126
return err
81
127
}
82
128
83
- var generator generate.StructuredGenerator
84
- switch generatorName := cmdutil .GetFlagString (cmd , "generator" ); generatorName {
85
- case generateversioned .RoleBindingV1GeneratorName :
86
- generator = & generateversioned.RoleBindingGeneratorV1 {
87
- Name : name ,
88
- ClusterRole : cmdutil .GetFlagString (cmd , "clusterrole" ),
89
- Role : cmdutil .GetFlagString (cmd , "role" ),
90
- Users : cmdutil .GetFlagStringArray (cmd , "user" ),
91
- Groups : cmdutil .GetFlagStringArray (cmd , "group" ),
92
- ServiceAccounts : cmdutil .GetFlagStringArray (cmd , "serviceaccount" ),
93
- }
94
- default :
95
- return errUnsupportedGenerator (cmd , generatorName )
129
+ o .Namespace , o .EnforceNamespace , err = f .ToRawKubeConfigLoader ().Namespace ()
130
+ if err != nil {
131
+ return err
96
132
}
97
133
98
- return o .CreateSubcommandOptions .Complete (f , cmd , args , generator )
134
+ o .CreateAnnotation = cmdutil .GetFlagBool (cmd , cmdutil .ApplyAnnotationsFlag )
135
+ o .DryRunStrategy , err = cmdutil .GetDryRunStrategy (cmd )
136
+ if err != nil {
137
+ return err
138
+ }
139
+ dynamicCient , err := f .DynamicClient ()
140
+ if err != nil {
141
+ return err
142
+ }
143
+ discoveryClient , err := f .ToDiscoveryClient ()
144
+ if err != nil {
145
+ return err
146
+ }
147
+ o .DryRunVerifier = resource .NewDryRunVerifier (dynamicCient , discoveryClient )
148
+ cmdutil .PrintFlagsWithDryRunStrategy (o .PrintFlags , o .DryRunStrategy )
149
+ printer , err := o .PrintFlags .ToPrinter ()
150
+ if err != nil {
151
+ return err
152
+ }
153
+ o .PrintObj = func (obj runtime.Object ) error {
154
+ return printer .PrintObj (obj , o .Out )
155
+ }
156
+ return nil
99
157
}
100
158
101
- // Run calls the CreateSubcommandOptions.Run in RoleBindingOpts instance
102
- func (o * RoleBindingOpts ) Run () error {
103
- return o .CreateSubcommandOptions .Run ()
159
+ // Validate validates required fields are set
160
+ func (o * RoleBindingOptions ) Validate () error {
161
+ if len (o .Name ) == 0 {
162
+ return fmt .Errorf ("name must be specified" )
163
+ }
164
+ if (len (o .ClusterRole ) == 0 ) == (len (o .Role ) == 0 ) {
165
+ return fmt .Errorf ("exactly one of clusterrole or role must be specified" )
166
+ }
167
+ return nil
168
+ }
169
+
170
+ // Run performs the execution of 'create rolebinding' sub command
171
+ func (o * RoleBindingOptions ) Run () error {
172
+ roleBinding , err := o .createRoleBinding ()
173
+ if err != nil {
174
+ return err
175
+ }
176
+ if err := util .CreateOrUpdateAnnotation (o .CreateAnnotation , roleBinding , scheme .DefaultJSONEncoder ()); err != nil {
177
+ return err
178
+ }
179
+
180
+ if o .DryRunStrategy != cmdutil .DryRunClient {
181
+ createOptions := metav1.CreateOptions {}
182
+ if o .FieldManager != "" {
183
+ createOptions .FieldManager = o .FieldManager
184
+ }
185
+ if o .DryRunStrategy == cmdutil .DryRunServer {
186
+ if err := o .DryRunVerifier .HasSupport (roleBinding .GroupVersionKind ()); err != nil {
187
+ return err
188
+ }
189
+ createOptions .DryRun = []string {metav1 .DryRunAll }
190
+ }
191
+ roleBinding , err = o .Client .RoleBindings (o .Namespace ).Create (context .TODO (), roleBinding , createOptions )
192
+ if err != nil {
193
+ return fmt .Errorf ("failed to create rolebinding: %v" , err )
194
+ }
195
+ }
196
+ return o .PrintObj (roleBinding )
197
+ }
198
+
199
+ func (o * RoleBindingOptions ) createRoleBinding () (* rbacv1.RoleBinding , error ) {
200
+ namespace := ""
201
+ if o .EnforceNamespace {
202
+ namespace = o .Namespace
203
+ }
204
+
205
+ roleBinding := & rbacv1.RoleBinding {
206
+ TypeMeta : metav1.TypeMeta {APIVersion : rbacv1 .SchemeGroupVersion .String (), Kind : "RoleBinding" },
207
+ ObjectMeta : metav1.ObjectMeta {
208
+ Name : o .Name ,
209
+ Namespace : namespace ,
210
+ },
211
+ }
212
+
213
+ switch {
214
+ case len (o .Role ) > 0 :
215
+ roleBinding .RoleRef = rbacv1.RoleRef {
216
+ APIGroup : rbacv1 .GroupName ,
217
+ Kind : "Role" ,
218
+ Name : o .Role ,
219
+ }
220
+ case len (o .ClusterRole ) > 0 :
221
+ roleBinding .RoleRef = rbacv1.RoleRef {
222
+ APIGroup : rbacv1 .GroupName ,
223
+ Kind : "ClusterRole" ,
224
+ Name : o .ClusterRole ,
225
+ }
226
+ }
227
+
228
+ for _ , user := range o .Users {
229
+ roleBinding .Subjects = append (roleBinding .Subjects , rbacv1.Subject {
230
+ Kind : rbacv1 .UserKind ,
231
+ APIGroup : rbacv1 .GroupName ,
232
+ Name : user ,
233
+ })
234
+ }
235
+
236
+ for _ , group := range o .Groups {
237
+ roleBinding .Subjects = append (roleBinding .Subjects , rbacv1.Subject {
238
+ Kind : rbacv1 .GroupKind ,
239
+ APIGroup : rbacv1 .GroupName ,
240
+ Name : group ,
241
+ })
242
+ }
243
+
244
+ for _ , sa := range o .ServiceAccounts {
245
+ tokens := strings .Split (sa , ":" )
246
+ if len (tokens ) != 2 || tokens [0 ] == "" || tokens [1 ] == "" {
247
+ return nil , fmt .Errorf ("serviceaccount must be <namespace>:<name>" )
248
+ }
249
+ roleBinding .Subjects = append (roleBinding .Subjects , rbacv1.Subject {
250
+ Kind : rbacv1 .ServiceAccountKind ,
251
+ APIGroup : "" ,
252
+ Namespace : tokens [0 ],
253
+ Name : tokens [1 ],
254
+ })
255
+ }
256
+ return roleBinding , nil
104
257
}
0 commit comments