@@ -52,6 +52,10 @@ type Rule struct {
52
52
Verbs []string
53
53
// URL specifies the non-resource URLs that this rule encompasses.
54
54
URLs []string `marker:"urls,optional"`
55
+ // Namespace specifies the scope of the Rule.
56
+ // If not set, the Rule belongs to the generated ClusterRole.
57
+ // If set, the Rule belongs to a Role, whose namespace is specified by this field.
58
+ Namespace string `marker:",optional"`
55
59
}
56
60
57
61
// ruleKey represents the resources and non-resources a Rule applies.
@@ -146,69 +150,109 @@ func (Generator) RegisterMarkers(into *markers.Registry) error {
146
150
return nil
147
151
}
148
152
149
- // GenerateClusterRole generates a rbacv1.ClusterRole object
150
- func GenerateClusterRole (ctx * genall.GenerationContext , roleName string ) (* rbacv1.ClusterRole , error ) {
151
- rules := make (map [ruleKey ]* Rule )
153
+ // GenerateRoles generate a slice of objs representing either a ClusterRole or a Role object
154
+ // The order of the objs in the returned slice is stable and determined by their namespaces.
155
+ func GenerateRoles (ctx * genall.GenerationContext , roleName string ) ([]interface {}, error ) {
156
+ rulesByNS := make (map [string ][]* Rule )
152
157
for _ , root := range ctx .Roots {
153
158
markerSet , err := markers .PackageMarkers (ctx .Collector , root )
154
159
if err != nil {
155
160
root .AddError (err )
156
161
}
157
162
158
- // all the Rules having the same ruleKey will be merged into the first Rule
163
+ // group RBAC markers by namespace
159
164
for _ , markerValue := range markerSet [RuleDefinition .Name ] {
160
165
rule := markerValue .(Rule )
166
+ namespace := rule .Namespace
167
+ if _ , ok := rulesByNS [namespace ]; ! ok {
168
+ rules := make ([]* Rule , 0 )
169
+ rulesByNS [namespace ] = rules
170
+ }
171
+ rulesByNS [namespace ] = append (rulesByNS [namespace ], & rule )
172
+ }
173
+ }
174
+
175
+ // NormalizeRules merge Rule with the same ruleKey and sort the Rules
176
+ NormalizeRules := func (rules []* Rule ) []rbacv1.PolicyRule {
177
+ ruleMap := make (map [ruleKey ]* Rule )
178
+ // all the Rules having the same ruleKey will be merged into the first Rule
179
+ for _ , rule := range rules {
161
180
key := rule .key ()
162
- if _ , ok := rules [key ]; ! ok {
163
- rules [key ] = & rule
181
+ if _ , ok := ruleMap [key ]; ! ok {
182
+ ruleMap [key ] = rule
164
183
continue
165
184
}
166
- rules [key ].addVerbs (rule .Verbs )
185
+ ruleMap [key ].addVerbs (rule .Verbs )
167
186
}
168
- }
169
187
170
- if len (rules ) == 0 {
171
- return nil , nil
172
- }
188
+ // sort the Rules in rules according to their ruleKeys
189
+ keys := make ([]ruleKey , 0 , len (ruleMap ))
190
+ for key := range ruleMap {
191
+ keys = append (keys , key )
192
+ }
193
+ sort .Sort (ruleKeys (keys ))
173
194
174
- // sort the Rules in rules according to their ruleKeys
175
- keys := make ([]ruleKey , 0 )
176
- for key := range rules {
177
- keys = append (keys , key )
178
- }
179
- sort .Sort (ruleKeys (keys ))
195
+ var policyRules []rbacv1.PolicyRule
196
+ for _ , key := range keys {
197
+ policyRules = append (policyRules , ruleMap [key ].ToRule ())
180
198
181
- var policyRules []rbacv1. PolicyRule
182
- for _ , key := range keys {
183
- policyRules = append ( policyRules , rules [ key ]. ToRule ())
199
+ }
200
+ return policyRules
201
+ }
184
202
203
+ // collect all the namespaces and sort them
204
+ var namespaces []string
205
+ for ns := range rulesByNS {
206
+ namespaces = append (namespaces , ns )
207
+ }
208
+ sort .Strings (namespaces )
209
+
210
+ // process the items in rulesByNS by the order specified in `namespaces` to make sure that the Role order is stable
211
+ var objs []interface {}
212
+ for _ , ns := range namespaces {
213
+ rules := rulesByNS [ns ]
214
+ policyRules := NormalizeRules (rules )
215
+ if len (policyRules ) == 0 {
216
+ continue
217
+ }
218
+ if ns == "" {
219
+ objs = append (objs , rbacv1.ClusterRole {
220
+ TypeMeta : metav1.TypeMeta {
221
+ Kind : "ClusterRole" ,
222
+ APIVersion : rbacv1 .SchemeGroupVersion .String (),
223
+ },
224
+ ObjectMeta : metav1.ObjectMeta {
225
+ Name : roleName ,
226
+ },
227
+ Rules : policyRules ,
228
+ })
229
+ } else {
230
+ objs = append (objs , rbacv1.Role {
231
+ TypeMeta : metav1.TypeMeta {
232
+ Kind : "Role" ,
233
+ APIVersion : rbacv1 .SchemeGroupVersion .String (),
234
+ },
235
+ ObjectMeta : metav1.ObjectMeta {
236
+ Name : roleName ,
237
+ Namespace : ns ,
238
+ },
239
+ Rules : policyRules ,
240
+ })
241
+ }
185
242
}
186
243
187
- return & rbacv1.ClusterRole {
188
- TypeMeta : metav1.TypeMeta {
189
- Kind : "ClusterRole" ,
190
- APIVersion : rbacv1 .SchemeGroupVersion .String (),
191
- },
192
- ObjectMeta : metav1.ObjectMeta {
193
- Name : roleName ,
194
- },
195
- Rules : policyRules ,
196
- }, nil
244
+ return objs , nil
197
245
}
198
246
199
247
func (g Generator ) Generate (ctx * genall.GenerationContext ) error {
200
- clusterRole , err := GenerateClusterRole (ctx , g .RoleName )
248
+ objs , err := GenerateRoles (ctx , g .RoleName )
201
249
if err != nil {
202
250
return err
203
251
}
204
252
205
- if clusterRole == nil {
253
+ if len ( objs ) == 0 {
206
254
return nil
207
255
}
208
256
209
- if err := ctx .WriteYAML ("role.yaml" , * clusterRole ); err != nil {
210
- return err
211
- }
212
-
213
- return nil
257
+ return ctx .WriteYAML ("role.yaml" , objs ... )
214
258
}
0 commit comments