@@ -21,6 +21,7 @@ import (
21
21
"path/filepath"
22
22
"reflect"
23
23
"slices"
24
+ "strings"
24
25
"testing"
25
26
26
27
"github.com/google/go-cmp/cmp"
@@ -31,6 +32,8 @@ import (
31
32
"k8s.io/apimachinery/pkg/api/meta"
32
33
"k8s.io/apimachinery/pkg/runtime"
33
34
"k8s.io/apimachinery/pkg/util/sets"
35
+ "k8s.io/apiserver/pkg/util/feature"
36
+ featuregatetesting "k8s.io/component-base/featuregate/testing"
34
37
"k8s.io/component-helpers/auth/rbac/validation"
35
38
"k8s.io/kubernetes/pkg/api/legacyscheme"
36
39
api "k8s.io/kubernetes/pkg/apis/core"
@@ -175,6 +178,154 @@ func TestBootstrapClusterRoles(t *testing.T) {
175
178
testObjects (t , list , "cluster-roles.yaml" )
176
179
}
177
180
181
+ func TestBootstrapClusterRolesWithFeatureGateEnabled (t * testing.T ) {
182
+ expectedDiff := map [string ]string {
183
+ "system:monitoring" : ` &v1.ClusterRole{
184
+ TypeMeta: {},
185
+ ObjectMeta: {Name: "system:monitoring", Labels: {"kubernetes.io/bootstrapping": "rbac-defaults"}, Annotations: {"rbac.authorization.kubernetes.io/autoupdate": "true"}},
186
+ Rules: []v1.PolicyRule{
187
+ {Verbs: {"get"}, NonResourceURLs: {"/healthz", "/healthz/*", "/livez", "/livez/*", ...}},
188
+ + {Verbs: []string{"get"}, NonResourceURLs: []string{"/flagz"}},
189
+ + {Verbs: []string{"get"}, NonResourceURLs: []string{"/statusz"}},
190
+ },
191
+ AggregationRule: nil,
192
+ }` ,
193
+ "system:aggregate-to-view" : ` &v1.ClusterRole{
194
+ TypeMeta: {},
195
+ ObjectMeta: {Name: "system:aggregate-to-view", Labels: {"kubernetes.io/bootstrapping": "rbac-defaults", "rbac.authorization.k8s.io/aggregate-to-view": "true"}, Annotations: {"rbac.authorization.kubernetes.io/autoupdate": "true"}},
196
+ Rules: []v1.PolicyRule{
197
+ ... // 8 identical elements
198
+ {Verbs: {"get", "list", "watch"}, APIGroups: {"policy"}, Resources: {"poddisruptionbudgets", "poddisruptionbudgets/status"}},
199
+ {Verbs: {"get", "list", "watch"}, APIGroups: {"networking.k8s.io"}, Resources: {"ingresses", "ingresses/status", "networkpolicies"}},
200
+ + {
201
+ + Verbs: []string{"get", "list", "watch"},
202
+ + APIGroups: []string{"resource.k8s.io"},
203
+ + Resources: []string{"resourceclaims", "resourceclaims/status", "resourceclaimtemplates"},
204
+ + },
205
+ },
206
+ AggregationRule: nil,
207
+ }
208
+ ` ,
209
+ "system:aggregate-to-edit" : `&v1.ClusterRole{
210
+ TypeMeta: {},
211
+ ObjectMeta: {Name: "system:aggregate-to-edit", Labels: {"kubernetes.io/bootstrapping": "rbac-defaults", "rbac.authorization.k8s.io/aggregate-to-edit": "true"}, Annotations: {"rbac.authorization.kubernetes.io/autoupdate": "true"}},
212
+ Rules: []v1.PolicyRule{
213
+ ... // 11 identical elements
214
+ {Verbs: {"create", "delete", "deletecollection", "patch", ...}, APIGroups: {"networking.k8s.io"}, Resources: {"ingresses", "networkpolicies"}},
215
+ {Verbs: {"create", "delete", "deletecollection", "get", ...}, APIGroups: {"coordination.k8s.io"}, Resources: {"leases"}},
216
+ + {
217
+ + Verbs: []string{"create", "delete", "deletecollection", "patch", "update"},
218
+ + APIGroups: []string{"resource.k8s.io"},
219
+ + Resources: []string{"resourceclaims", "resourceclaimtemplates"},
220
+ + },
221
+ },
222
+ AggregationRule: nil,
223
+ }
224
+ ` ,
225
+ "system:node" : ` &v1.ClusterRole{
226
+ TypeMeta: {},
227
+ ObjectMeta: {Name: "system:node", Labels: {"kubernetes.io/bootstrapping": "rbac-defaults"}, Annotations: {"rbac.authorization.kubernetes.io/autoupdate": "true"}},
228
+ Rules: []v1.PolicyRule{
229
+ ... // 20 identical elements
230
+ {Verbs: {"create", "delete", "get", "patch", ...}, APIGroups: {"storage.k8s.io"}, Resources: {"csinodes"}},
231
+ {Verbs: {"get", "list", "watch"}, APIGroups: {"node.k8s.io"}, Resources: {"runtimeclasses"}},
232
+ + {
233
+ + Verbs: []string{"get"},
234
+ + APIGroups: []string{"resource.k8s.io"},
235
+ + Resources: []string{"resourceclaims"},
236
+ + },
237
+ + {
238
+ + Verbs: []string{"deletecollection"},
239
+ + APIGroups: []string{"resource.k8s.io"},
240
+ + Resources: []string{"resourceslices"},
241
+ + },
242
+ + {
243
+ + Verbs: []string{"get", "list", "watch"},
244
+ + APIGroups: []string{"certificates.k8s.io"},
245
+ + Resources: []string{"clustertrustbundles"},
246
+ + },
247
+ },
248
+ AggregationRule: nil,
249
+ }
250
+ ` ,
251
+ "system:kube-scheduler" : ` &v1.ClusterRole{
252
+ TypeMeta: {},
253
+ ObjectMeta: {Name: "system:kube-scheduler", Labels: {"kubernetes.io/bootstrapping": "rbac-defaults"}, Annotations: {"rbac.authorization.kubernetes.io/autoupdate": "true"}},
254
+ Rules: []v1.PolicyRule{
255
+ ... // 18 identical elements
256
+ {Verbs: {"get", "list", "watch"}, APIGroups: {"storage.k8s.io"}, Resources: {"csidrivers"}},
257
+ {Verbs: {"get", "list", "watch"}, APIGroups: {"storage.k8s.io"}, Resources: {"csistoragecapacities"}},
258
+ + {
259
+ + Verbs: []string{"get", "list", "watch"},
260
+ + APIGroups: []string{"resource.k8s.io"},
261
+ + Resources: []string{"deviceclasses"},
262
+ + },
263
+ + {
264
+ + Verbs: []string{"get", "list", "patch", "update", "watch"},
265
+ + APIGroups: []string{"resource.k8s.io"},
266
+ + Resources: []string{"resourceclaims"},
267
+ + },
268
+ + {
269
+ + Verbs: []string{"get", "list", "patch", "update", "watch"},
270
+ + APIGroups: []string{"resource.k8s.io"},
271
+ + Resources: []string{"resourceclaims/status"},
272
+ + },
273
+ + {
274
+ + Verbs: []string{"get", "list", "patch", "update", "watch"},
275
+ + APIGroups: []string{""},
276
+ + Resources: []string{"pods/finalizers"},
277
+ + },
278
+ + {
279
+ + Verbs: []string{"get", "list", "watch"},
280
+ + APIGroups: []string{"resource.k8s.io"},
281
+ + Resources: []string{"resourceslices"},
282
+ + },
283
+ },
284
+ AggregationRule: nil,
285
+ }
286
+ ` ,
287
+ "system:cluster-trust-bundle-discovery" : ` any(
288
+ + s"&ClusterRole{ObjectMeta:{system:cluster-trust-bundle-discovery 0 0001-01-01 00:00:00 +0000 UTC <nil> <nil> map[kubernetes.io/bootstrapping:rbac-defaults] map[rbac.authorization.kubernetes.io/autoupdate:true] [] [] []},Rules:[]PolicyRule{PolicyRule{Ver"...,
289
+ )
290
+ ` ,
291
+ }
292
+
293
+ names := sets .NewString ()
294
+ roles := map [string ]runtime.Object {}
295
+ bootstrapRoles := bootstrappolicy .ClusterRoles ()
296
+ for i := range bootstrapRoles {
297
+ role := bootstrapRoles [i ]
298
+ names .Insert (role .Name )
299
+ roles [role .Name ] = & role
300
+ }
301
+
302
+ featuregatetesting .SetFeatureGateDuringTest (t , feature .DefaultFeatureGate , "AllAlpha" , true )
303
+ featuregatetesting .SetFeatureGateDuringTest (t , feature .DefaultFeatureGate , "AllBeta" , true )
304
+
305
+ bootstrapRoles = bootstrappolicy .ClusterRoles ()
306
+ featureGateList := & api.List {}
307
+ featureGateNames := sets .NewString ()
308
+ featureGateRoles := map [string ]runtime.Object {}
309
+ for i := range bootstrapRoles {
310
+ role := bootstrapRoles [i ]
311
+ featureGateNames .Insert (role .Name )
312
+ featureGateRoles [role .Name ] = & role
313
+ actualDiff := cmp .Diff (roles [role .Name ], featureGateRoles [role .Name ])
314
+ //normalize whitespace
315
+ expectedDiffNormalized := strings .Join (strings .Fields (expectedDiff [role .Name ]), " " )
316
+ actualDiffNormalized := strings .Join (strings .Fields (actualDiff ), " " )
317
+ if expectedDiffNormalized != actualDiffNormalized {
318
+ t .Errorf ("RoleName '%s', diff between regular and feature gate. Expected: [%s], Actual: [%s]" , role .Name , expectedDiff [role .Name ], actualDiff )
319
+ }
320
+ }
321
+ for _ , featureGateName := range featureGateNames .List () {
322
+ featureGateList .Items = append (featureGateList .Items , featureGateRoles [featureGateName ])
323
+ }
324
+
325
+ testObjects (t , featureGateList , "cluster-roles-featuregates.yaml" )
326
+
327
+ }
328
+
178
329
func TestBootstrapClusterRoleBindings (t * testing.T ) {
179
330
list := & api.List {}
180
331
names := sets .NewString ()
0 commit comments