@@ -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
)
@@ -36,16 +45,40 @@ var (
36
45
kubectl create clusterrolebinding cluster-admin --clusterrole=cluster-admin --user=user1 --user=user2 --group=group1` ))
37
46
)
38
47
39
- // ClusterRoleBindingOpts is returned by NewCmdCreateClusterRoleBinding
40
- type ClusterRoleBindingOpts struct {
41
- CreateSubcommandOptions * CreateSubcommandOptions
48
+ // ClusterRoleBindingOptions is returned by NewCmdCreateClusterRoleBinding
49
+ type ClusterRoleBindingOptions struct {
50
+ PrintFlags * genericclioptions.PrintFlags
51
+ PrintObj func (obj runtime.Object ) error
52
+
53
+ Name string
54
+ ClusterRole string
55
+ Users []string
56
+ Groups []string
57
+ ServiceAccounts []string
58
+ FieldManager string
59
+ CreateAnnotation bool
60
+
61
+ Client rbacclientv1.RbacV1Interface
62
+ DryRunStrategy cmdutil.DryRunStrategy
63
+ DryRunVerifier * resource.DryRunVerifier
64
+
65
+ genericclioptions.IOStreams
66
+ }
67
+
68
+ // NewClusterRoleBindingOptions creates a new *ClusterRoleBindingOptions with sane defaults
69
+ func NewClusterRoleBindingOptions (ioStreams genericclioptions.IOStreams ) * ClusterRoleBindingOptions {
70
+ return & ClusterRoleBindingOptions {
71
+ Users : []string {},
72
+ Groups : []string {},
73
+ ServiceAccounts : []string {},
74
+ PrintFlags : genericclioptions .NewPrintFlags ("created" ).WithTypeSetter (scheme .Scheme ),
75
+ IOStreams : ioStreams ,
76
+ }
42
77
}
43
78
44
79
// NewCmdCreateClusterRoleBinding returns an initialized command instance of ClusterRoleBinding
45
80
func NewCmdCreateClusterRoleBinding (f cmdutil.Factory , ioStreams genericclioptions.IOStreams ) * cobra.Command {
46
- o := & ClusterRoleBindingOpts {
47
- CreateSubcommandOptions : NewCreateSubcommandOptions (ioStreams ),
48
- }
81
+ o := NewClusterRoleBindingOptions (ioStreams )
49
82
50
83
cmd := & cobra.Command {
51
84
Use : "clusterrolebinding NAME --clusterrole=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run=server|client|none]" ,
@@ -59,45 +92,136 @@ func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, ioStreams genericclioptio
59
92
},
60
93
}
61
94
62
- o .CreateSubcommandOptions . PrintFlags .AddFlags (cmd )
95
+ o .PrintFlags .AddFlags (cmd )
63
96
64
97
cmdutil .AddApplyAnnotationFlags (cmd )
65
98
cmdutil .AddValidateFlags (cmd )
66
- cmdutil .AddGeneratorFlags (cmd , generateversioned .ClusterRoleBindingV1GeneratorName )
67
- cmd .Flags ().String ("clusterrole" , "" , i18n .T ("ClusterRole this ClusterRoleBinding should reference" ))
99
+ cmdutil .AddDryRunFlag (cmd )
100
+ cmd .Flags ().StringVar (& o .ClusterRole , "clusterrole" , "" , i18n .T ("ClusterRole this ClusterRoleBinding should reference" ))
101
+ cmd .MarkFlagRequired ("clusterrole" )
68
102
cmd .MarkFlagCustom ("clusterrole" , "__kubectl_get_resource_clusterrole" )
69
- cmd .Flags ().StringArray ( "user" , [] string {} , "Usernames to bind to the clusterrole" )
70
- cmd .Flags ().StringArray ( "group" , [] string {} , "Groups to bind to the clusterrole" )
71
- cmd .Flags ().StringArray ( "serviceaccount" , [] string {} , "Service accounts to bind to the clusterrole, in the format <namespace>:<name>" )
72
- cmdutil .AddFieldManagerFlagVar (cmd , & o .CreateSubcommandOptions . FieldManager , "kubectl-create" )
103
+ cmd .Flags ().StringArrayVar ( & o . Users , "user" , o . Users , "Usernames to bind to the clusterrole" )
104
+ cmd .Flags ().StringArrayVar ( & o . Groups , "group" , o . Groups , "Groups to bind to the clusterrole" )
105
+ cmd .Flags ().StringArrayVar ( & o . ServiceAccounts , "serviceaccount" , o . ServiceAccounts , "Service accounts to bind to the clusterrole, in the format <namespace>:<name>" )
106
+ cmdutil .AddFieldManagerFlagVar (cmd , & o .FieldManager , "kubectl-create" )
73
107
return cmd
74
108
}
75
109
76
110
// Complete completes all the required options
77
- func (o * ClusterRoleBindingOpts ) Complete (f cmdutil.Factory , cmd * cobra.Command , args []string ) error {
78
- name , err := NameFromCommandArgs (cmd , args )
111
+ func (o * ClusterRoleBindingOptions ) Complete (f cmdutil.Factory , cmd * cobra.Command , args []string ) error {
112
+ var err error
113
+ o .Name , err = NameFromCommandArgs (cmd , args )
114
+ if err != nil {
115
+ return err
116
+ }
117
+
118
+ cs , err := f .KubernetesClientSet ()
119
+ if err != nil {
120
+ return err
121
+ }
122
+ o .Client = cs .RbacV1 ()
123
+
124
+ o .CreateAnnotation = cmdutil .GetFlagBool (cmd , cmdutil .ApplyAnnotationsFlag )
125
+
126
+ o .DryRunStrategy , err = cmdutil .GetDryRunStrategy (cmd )
127
+ if err != nil {
128
+ return err
129
+ }
130
+ dynamicClient , err := f .DynamicClient ()
131
+ if err != nil {
132
+ return err
133
+ }
134
+ discoveryClient , err := f .ToDiscoveryClient ()
135
+ if err != nil {
136
+ return err
137
+ }
138
+ o .DryRunVerifier = resource .NewDryRunVerifier (dynamicClient , discoveryClient )
139
+ cmdutil .PrintFlagsWithDryRunStrategy (o .PrintFlags , o .DryRunStrategy )
140
+
141
+ printer , err := o .PrintFlags .ToPrinter ()
79
142
if err != nil {
80
143
return err
81
144
}
145
+ o .PrintObj = func (obj runtime.Object ) error {
146
+ return printer .PrintObj (obj , o .Out )
147
+ }
82
148
83
- var generator generate.StructuredGenerator
84
- switch generatorName := cmdutil .GetFlagString (cmd , "generator" ); generatorName {
85
- case generateversioned .ClusterRoleBindingV1GeneratorName :
86
- generator = & generateversioned.ClusterRoleBindingGeneratorV1 {
87
- Name : name ,
88
- ClusterRole : cmdutil .GetFlagString (cmd , "clusterrole" ),
89
- Users : cmdutil .GetFlagStringArray (cmd , "user" ),
90
- Groups : cmdutil .GetFlagStringArray (cmd , "group" ),
91
- ServiceAccounts : cmdutil .GetFlagStringArray (cmd , "serviceaccount" ),
149
+ return nil
150
+ }
151
+
152
+ // Run calls the CreateSubcommandOptions.Run in ClusterRoleBindingOptions instance
153
+ func (o * ClusterRoleBindingOptions ) Run () error {
154
+ clusterRoleBinding , err := o .createClusterRoleBinding ()
155
+ if err != nil {
156
+ return err
157
+ }
158
+
159
+ if err := util .CreateOrUpdateAnnotation (o .CreateAnnotation , clusterRoleBinding , scheme .DefaultJSONEncoder ()); err != nil {
160
+ return err
161
+ }
162
+
163
+ if o .DryRunStrategy != cmdutil .DryRunClient {
164
+ createOptions := metav1.CreateOptions {}
165
+ if o .FieldManager != "" {
166
+ createOptions .FieldManager = o .FieldManager
167
+ }
168
+ if o .DryRunStrategy == cmdutil .DryRunServer {
169
+ if err := o .DryRunVerifier .HasSupport (clusterRoleBinding .GroupVersionKind ()); err != nil {
170
+ return err
171
+ }
172
+ createOptions .DryRun = []string {metav1 .DryRunAll }
173
+ }
174
+ var err error
175
+ clusterRoleBinding , err = o .Client .ClusterRoleBindings ().Create (context .TODO (), clusterRoleBinding , createOptions )
176
+ if err != nil {
177
+ return fmt .Errorf ("failed to create clusterrolebinding: %v" , err )
92
178
}
93
- default :
94
- return errUnsupportedGenerator (cmd , generatorName )
95
179
}
96
180
97
- return o .CreateSubcommandOptions . Complete ( f , cmd , args , generator )
181
+ return o .PrintObj ( clusterRoleBinding )
98
182
}
99
183
100
- // Run calls the CreateSubcommandOptions.Run in ClusterRoleBindingOpts instance
101
- func (o * ClusterRoleBindingOpts ) Run () error {
102
- return o .CreateSubcommandOptions .Run ()
184
+ func (o * ClusterRoleBindingOptions ) createClusterRoleBinding () (* rbacv1.ClusterRoleBinding , error ) {
185
+ clusterRoleBinding := & rbacv1.ClusterRoleBinding {
186
+ TypeMeta : metav1.TypeMeta {APIVersion : rbacv1 .SchemeGroupVersion .String (), Kind : "ClusterRoleBinding" },
187
+ ObjectMeta : metav1.ObjectMeta {
188
+ Name : o .Name ,
189
+ },
190
+ RoleRef : rbacv1.RoleRef {
191
+ APIGroup : rbacv1 .GroupName ,
192
+ Kind : "ClusterRole" ,
193
+ Name : o .ClusterRole ,
194
+ },
195
+ }
196
+
197
+ for _ , user := range o .Users {
198
+ clusterRoleBinding .Subjects = append (clusterRoleBinding .Subjects , rbacv1.Subject {
199
+ Kind : rbacv1 .UserKind ,
200
+ APIGroup : rbacv1 .GroupName ,
201
+ Name : user ,
202
+ })
203
+ }
204
+
205
+ for _ , group := range o .Groups {
206
+ clusterRoleBinding .Subjects = append (clusterRoleBinding .Subjects , rbacv1.Subject {
207
+ Kind : rbacv1 .GroupKind ,
208
+ APIGroup : rbacv1 .GroupName ,
209
+ Name : group ,
210
+ })
211
+ }
212
+
213
+ for _ , sa := range o .ServiceAccounts {
214
+ tokens := strings .Split (sa , ":" )
215
+ if len (tokens ) != 2 || tokens [0 ] == "" || tokens [1 ] == "" {
216
+ return nil , fmt .Errorf ("serviceaccount must be <namespace>:<name>" )
217
+ }
218
+ clusterRoleBinding .Subjects = append (clusterRoleBinding .Subjects , rbacv1.Subject {
219
+ Kind : rbacv1 .ServiceAccountKind ,
220
+ APIGroup : "" ,
221
+ Namespace : tokens [0 ],
222
+ Name : tokens [1 ],
223
+ })
224
+ }
225
+
226
+ return clusterRoleBinding , nil
103
227
}
0 commit comments