1
16
17 package utils
18
19 import (
20 "bytes"
21 "context"
22 "encoding/json"
23 "errors"
24 "fmt"
25
26 "github.com/onsi/ginkgo/v2"
27
28 appsv1 "k8s.io/api/apps/v1"
29 v1 "k8s.io/api/core/v1"
30 rbacv1 "k8s.io/api/rbac/v1"
31 storagev1 "k8s.io/api/storage/v1"
32 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
33 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
34 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
35 "k8s.io/apimachinery/pkg/runtime"
36 "k8s.io/apimachinery/pkg/runtime/schema"
37 "k8s.io/client-go/kubernetes/scheme"
38 "k8s.io/client-go/tools/cache"
39 "k8s.io/kubernetes/test/e2e/framework"
40 e2etestfiles "k8s.io/kubernetes/test/e2e/framework/testfiles"
41 imageutils "k8s.io/kubernetes/test/utils/image"
42 )
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57 func LoadFromManifests(files ...string) ([]interface{}, error) {
58 var items []interface{}
59 err := visitManifests(func(data []byte) error {
60
61 var what What
62 if err := runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), data, &what); err != nil {
63 return fmt.Errorf("decode TypeMeta: %w", err)
64 }
65
66 if what.Kind == "" {
67 return nil
68 }
69
70 factory := factories[what]
71 if factory == nil {
72 return fmt.Errorf("item of type %+v not supported", what)
73 }
74
75 object := factory.New()
76 if err := runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), data, object); err != nil {
77 return fmt.Errorf("decode %+v: %w", what, err)
78 }
79 items = append(items, object)
80 return nil
81 }, files...)
82
83 return items, err
84 }
85
86 func visitManifests(cb func([]byte) error, files ...string) error {
87 for _, fileName := range files {
88 data, err := e2etestfiles.Read(fileName)
89 if err != nil {
90 framework.Failf("reading manifest file: %v", err)
91 }
92
93
94
95
96
97
98
99
100
101 items := bytes.Split(data, []byte("\n---"))
102
103 for _, item := range items {
104 if err := cb(item); err != nil {
105 return fmt.Errorf("%s: %w", fileName, err)
106 }
107 }
108 }
109 return nil
110 }
111
112
113
114
115
116
117
118
119
120
121
122
123 func PatchItems(f *framework.Framework, driverNamespace *v1.Namespace, items ...interface{}) error {
124 for _, item := range items {
125
126
127 if err := patchItemRecursively(f, driverNamespace, item); err != nil {
128 return err
129 }
130 }
131 return nil
132 }
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148 func CreateItems(ctx context.Context, f *framework.Framework, ns *v1.Namespace, items ...interface{}) error {
149 var result error
150 for _, item := range items {
151
152 done := false
153 description := describeItem(item)
154
155
156 framework.Logf("creating %s", description)
157 for _, factory := range factories {
158 destructor, err := factory.Create(ctx, f, ns, item)
159 if destructor != nil {
160 ginkgo.DeferCleanup(framework.IgnoreNotFound(destructor), framework.AnnotatedLocation(fmt.Sprintf("deleting %s", description)))
161 }
162 if err == nil {
163 done = true
164 break
165 } else if !errors.Is(err, errorItemNotSupported) {
166 result = err
167 break
168 }
169 }
170 if result == nil && !done {
171 result = fmt.Errorf("item of type %T not supported", item)
172 break
173 }
174 }
175
176 return result
177 }
178
179
180
181
182 func CreateFromManifests(ctx context.Context, f *framework.Framework, driverNamespace *v1.Namespace, patch func(item interface{}) error, files ...string) error {
183 items, err := LoadFromManifests(files...)
184 if err != nil {
185 return fmt.Errorf("CreateFromManifests: %w", err)
186 }
187 if err := PatchItems(f, driverNamespace, items...); err != nil {
188 return err
189 }
190 if patch != nil {
191 for _, item := range items {
192 if err := patch(item); err != nil {
193 return err
194 }
195 }
196 }
197 return CreateItems(ctx, f, driverNamespace, items...)
198 }
199
200
201
202 type What struct {
203 Kind string `json:"kind"`
204 }
205
206
207 func (in *What) DeepCopy() *What {
208 return &What{Kind: in.Kind}
209 }
210
211
212 func (in *What) DeepCopyInto(out *What) {
213 out.Kind = in.Kind
214 }
215
216
217 func (in *What) DeepCopyObject() runtime.Object {
218 return &What{Kind: in.Kind}
219 }
220
221
222 func (in *What) GetObjectKind() schema.ObjectKind {
223 return nil
224 }
225
226
227
228
229 type ItemFactory interface {
230
231 New() runtime.Object
232
233
234
235
236
237 Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, item interface{}) (func(ctx context.Context) error, error)
238 }
239
240
241
242
243
244 func describeItem(item interface{}) string {
245 key, err := cache.MetaNamespaceKeyFunc(item)
246 if err == nil && key != "" {
247 return fmt.Sprintf("%T: %s", item, key)
248 }
249 return fmt.Sprintf("%T: %s", item, item)
250 }
251
252
253
254 var errorItemNotSupported = errors.New("not supported")
255
256 var factories = map[What]ItemFactory{
257 {"ClusterRole"}: &clusterRoleFactory{},
258 {"ClusterRoleBinding"}: &clusterRoleBindingFactory{},
259 {"CSIDriver"}: &csiDriverFactory{},
260 {"DaemonSet"}: &daemonSetFactory{},
261 {"ReplicaSet"}: &replicaSetFactory{},
262 {"Role"}: &roleFactory{},
263 {"RoleBinding"}: &roleBindingFactory{},
264 {"Secret"}: &secretFactory{},
265 {"Service"}: &serviceFactory{},
266 {"ServiceAccount"}: &serviceAccountFactory{},
267 {"StatefulSet"}: &statefulSetFactory{},
268 {"Deployment"}: &deploymentFactory{},
269 {"StorageClass"}: &storageClassFactory{},
270 {"CustomResourceDefinition"}: &customResourceDefinitionFactory{},
271 }
272
273
274
275 func PatchName(f *framework.Framework, item *string) {
276 if *item != "" {
277 *item = *item + "-" + f.UniqueName
278 }
279 }
280
281
282
283
284 func PatchNamespace(f *framework.Framework, driverNamespace *v1.Namespace, item *string) {
285 if driverNamespace != nil {
286 *item = driverNamespace.GetName()
287 return
288 }
289
290 if f.Namespace != nil {
291 *item = f.Namespace.GetName()
292 }
293 }
294
295 func patchItemRecursively(f *framework.Framework, driverNamespace *v1.Namespace, item interface{}) error {
296 switch item := item.(type) {
297 case *rbacv1.Subject:
298 PatchNamespace(f, driverNamespace, &item.Namespace)
299 case *rbacv1.RoleRef:
300
301
302
303
304 if item.Name != "e2e-test-privileged-psp" {
305 PatchName(f, &item.Name)
306 }
307 case *rbacv1.ClusterRole:
308 PatchName(f, &item.Name)
309 case *rbacv1.Role:
310 PatchNamespace(f, driverNamespace, &item.Namespace)
311
312
313
314 PatchName(f, &item.Name)
315 case *storagev1.StorageClass:
316 PatchName(f, &item.Name)
317 case *storagev1.CSIDriver:
318 PatchName(f, &item.Name)
319 case *v1.ServiceAccount:
320 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace)
321 case *v1.Secret:
322 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace)
323 case *rbacv1.ClusterRoleBinding:
324 PatchName(f, &item.Name)
325 for i := range item.Subjects {
326 if err := patchItemRecursively(f, driverNamespace, &item.Subjects[i]); err != nil {
327 return fmt.Errorf("%T: %w", f, err)
328 }
329 }
330 if err := patchItemRecursively(f, driverNamespace, &item.RoleRef); err != nil {
331 return fmt.Errorf("%T: %w", f, err)
332 }
333 case *rbacv1.RoleBinding:
334 PatchNamespace(f, driverNamespace, &item.Namespace)
335 for i := range item.Subjects {
336 if err := patchItemRecursively(f, driverNamespace, &item.Subjects[i]); err != nil {
337 return fmt.Errorf("%T: %w", f, err)
338 }
339 }
340 if err := patchItemRecursively(f, driverNamespace, &item.RoleRef); err != nil {
341 return fmt.Errorf("%T: %w", f, err)
342 }
343 case *v1.Service:
344 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace)
345 case *appsv1.StatefulSet:
346 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace)
347 if err := patchContainerImages(item.Spec.Template.Spec.Containers); err != nil {
348 return err
349 }
350 if err := patchContainerImages(item.Spec.Template.Spec.InitContainers); err != nil {
351 return err
352 }
353 case *appsv1.Deployment:
354 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace)
355 if err := patchContainerImages(item.Spec.Template.Spec.Containers); err != nil {
356 return err
357 }
358 if err := patchContainerImages(item.Spec.Template.Spec.InitContainers); err != nil {
359 return err
360 }
361 case *appsv1.DaemonSet:
362 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace)
363 if err := patchContainerImages(item.Spec.Template.Spec.Containers); err != nil {
364 return err
365 }
366 if err := patchContainerImages(item.Spec.Template.Spec.InitContainers); err != nil {
367 return err
368 }
369 case *appsv1.ReplicaSet:
370 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace)
371 if err := patchContainerImages(item.Spec.Template.Spec.Containers); err != nil {
372 return err
373 }
374 if err := patchContainerImages(item.Spec.Template.Spec.InitContainers); err != nil {
375 return err
376 }
377 case *apiextensionsv1.CustomResourceDefinition:
378
379 default:
380 return fmt.Errorf("missing support for patching item of type %T", item)
381 }
382 return nil
383 }
384
385
386
387
388
389
390 type serviceAccountFactory struct{}
391
392 func (f *serviceAccountFactory) New() runtime.Object {
393 return &v1.ServiceAccount{}
394 }
395
396 func (*serviceAccountFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
397 item, ok := i.(*v1.ServiceAccount)
398 if !ok {
399 return nil, errorItemNotSupported
400 }
401 client := f.ClientSet.CoreV1().ServiceAccounts(ns.Name)
402 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
403 return nil, fmt.Errorf("create ServiceAccount: %w", err)
404 }
405 return func(ctx context.Context) error {
406 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
407 }, nil
408 }
409
410 type clusterRoleFactory struct{}
411
412 func (f *clusterRoleFactory) New() runtime.Object {
413 return &rbacv1.ClusterRole{}
414 }
415
416 func (*clusterRoleFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
417 item, ok := i.(*rbacv1.ClusterRole)
418 if !ok {
419 return nil, errorItemNotSupported
420 }
421
422 framework.Logf("Define cluster role %v", item.GetName())
423 client := f.ClientSet.RbacV1().ClusterRoles()
424 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
425 return nil, fmt.Errorf("create ClusterRole: %w", err)
426 }
427 return func(ctx context.Context) error {
428 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
429 }, nil
430 }
431
432 type clusterRoleBindingFactory struct{}
433
434 func (f *clusterRoleBindingFactory) New() runtime.Object {
435 return &rbacv1.ClusterRoleBinding{}
436 }
437
438 func (*clusterRoleBindingFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
439 item, ok := i.(*rbacv1.ClusterRoleBinding)
440 if !ok {
441 return nil, errorItemNotSupported
442 }
443
444 client := f.ClientSet.RbacV1().ClusterRoleBindings()
445 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
446 return nil, fmt.Errorf("create ClusterRoleBinding: %w", err)
447 }
448 return func(ctx context.Context) error {
449 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
450 }, nil
451 }
452
453 type roleFactory struct{}
454
455 func (f *roleFactory) New() runtime.Object {
456 return &rbacv1.Role{}
457 }
458
459 func (*roleFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
460 item, ok := i.(*rbacv1.Role)
461 if !ok {
462 return nil, errorItemNotSupported
463 }
464
465 client := f.ClientSet.RbacV1().Roles(ns.Name)
466 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
467 return nil, fmt.Errorf("create Role: %w", err)
468 }
469 return func(ctx context.Context) error {
470 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
471 }, nil
472 }
473
474 type roleBindingFactory struct{}
475
476 func (f *roleBindingFactory) New() runtime.Object {
477 return &rbacv1.RoleBinding{}
478 }
479
480 func (*roleBindingFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
481 item, ok := i.(*rbacv1.RoleBinding)
482 if !ok {
483 return nil, errorItemNotSupported
484 }
485
486 client := f.ClientSet.RbacV1().RoleBindings(ns.Name)
487 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
488 return nil, fmt.Errorf("create RoleBinding: %w", err)
489 }
490 return func(ctx context.Context) error {
491 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
492 }, nil
493 }
494
495 type serviceFactory struct{}
496
497 func (f *serviceFactory) New() runtime.Object {
498 return &v1.Service{}
499 }
500
501 func (*serviceFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
502 item, ok := i.(*v1.Service)
503 if !ok {
504 return nil, errorItemNotSupported
505 }
506
507 client := f.ClientSet.CoreV1().Services(ns.Name)
508 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
509 return nil, fmt.Errorf("create Service: %w", err)
510 }
511 return func(ctx context.Context) error {
512 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
513 }, nil
514 }
515
516 type statefulSetFactory struct{}
517
518 func (f *statefulSetFactory) New() runtime.Object {
519 return &appsv1.StatefulSet{}
520 }
521
522 func (*statefulSetFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
523 item, ok := i.(*appsv1.StatefulSet)
524 if !ok {
525 return nil, errorItemNotSupported
526 }
527
528 client := f.ClientSet.AppsV1().StatefulSets(ns.Name)
529 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
530 return nil, fmt.Errorf("create StatefulSet: %w", err)
531 }
532 return func(ctx context.Context) error {
533 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
534 }, nil
535 }
536
537 type deploymentFactory struct{}
538
539 func (f *deploymentFactory) New() runtime.Object {
540 return &appsv1.Deployment{}
541 }
542
543 func (*deploymentFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
544 item, ok := i.(*appsv1.Deployment)
545 if !ok {
546 return nil, errorItemNotSupported
547 }
548
549 client := f.ClientSet.AppsV1().Deployments(ns.Name)
550 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
551 return nil, fmt.Errorf("create Deployment: %w", err)
552 }
553 return func(ctx context.Context) error {
554 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
555 }, nil
556 }
557
558 type daemonSetFactory struct{}
559
560 func (f *daemonSetFactory) New() runtime.Object {
561 return &appsv1.DaemonSet{}
562 }
563
564 func (*daemonSetFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
565 item, ok := i.(*appsv1.DaemonSet)
566 if !ok {
567 return nil, errorItemNotSupported
568 }
569
570 client := f.ClientSet.AppsV1().DaemonSets(ns.Name)
571 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
572 return nil, fmt.Errorf("create DaemonSet: %w", err)
573 }
574 return func(ctx context.Context) error {
575 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
576 }, nil
577 }
578
579 type replicaSetFactory struct{}
580
581 func (f *replicaSetFactory) New() runtime.Object {
582 return &appsv1.ReplicaSet{}
583 }
584
585 func (*replicaSetFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
586 item, ok := i.(*appsv1.ReplicaSet)
587 if !ok {
588 return nil, errorItemNotSupported
589 }
590
591 client := f.ClientSet.AppsV1().ReplicaSets(ns.Name)
592 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
593 return nil, fmt.Errorf("create ReplicaSet: %w", err)
594 }
595 return func(ctx context.Context) error {
596 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
597 }, nil
598 }
599
600 type storageClassFactory struct{}
601
602 func (f *storageClassFactory) New() runtime.Object {
603 return &storagev1.StorageClass{}
604 }
605
606 func (*storageClassFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
607 item, ok := i.(*storagev1.StorageClass)
608 if !ok {
609 return nil, errorItemNotSupported
610 }
611
612 client := f.ClientSet.StorageV1().StorageClasses()
613 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
614 return nil, fmt.Errorf("create StorageClass: %w", err)
615 }
616 return func(ctx context.Context) error {
617 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
618 }, nil
619 }
620
621 type csiDriverFactory struct{}
622
623 func (f *csiDriverFactory) New() runtime.Object {
624 return &storagev1.CSIDriver{}
625 }
626
627 func (*csiDriverFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
628 item, ok := i.(*storagev1.CSIDriver)
629 if !ok {
630 return nil, errorItemNotSupported
631 }
632
633 client := f.ClientSet.StorageV1().CSIDrivers()
634 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
635 return nil, fmt.Errorf("create CSIDriver: %w", err)
636 }
637 return func(ctx context.Context) error {
638 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
639 }, nil
640 }
641
642 type secretFactory struct{}
643
644 func (f *secretFactory) New() runtime.Object {
645 return &v1.Secret{}
646 }
647
648 func (*secretFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
649 item, ok := i.(*v1.Secret)
650 if !ok {
651 return nil, errorItemNotSupported
652 }
653
654 client := f.ClientSet.CoreV1().Secrets(ns.Name)
655 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil {
656 return nil, fmt.Errorf("create Secret: %w", err)
657 }
658 return func(ctx context.Context) error {
659 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{})
660 }, nil
661 }
662
663 type customResourceDefinitionFactory struct{}
664
665 func (f *customResourceDefinitionFactory) New() runtime.Object {
666 return &apiextensionsv1.CustomResourceDefinition{}
667 }
668
669 func (*customResourceDefinitionFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) {
670 var err error
671 unstructCRD := &unstructured.Unstructured{}
672 gvr := schema.GroupVersionResource{Group: "apiextensions.k8s.io", Version: "v1", Resource: "customresourcedefinitions"}
673
674 item, ok := i.(*apiextensionsv1.CustomResourceDefinition)
675 if !ok {
676 return nil, errorItemNotSupported
677 }
678
679 unstructCRD.Object, err = runtime.DefaultUnstructuredConverter.ToUnstructured(i)
680 if err != nil {
681 return nil, err
682 }
683
684 if _, err = f.DynamicClient.Resource(gvr).Create(ctx, unstructCRD, metav1.CreateOptions{}); err != nil {
685 return nil, fmt.Errorf("create CustomResourceDefinition: %w", err)
686 }
687 return func(ctx context.Context) error {
688 return f.DynamicClient.Resource(gvr).Delete(ctx, item.GetName(), metav1.DeleteOptions{})
689 }, nil
690 }
691
692
693 func PrettyPrint(item interface{}) string {
694 data, err := json.MarshalIndent(item, "", " ")
695 if err == nil {
696 return string(data)
697 }
698 return fmt.Sprintf("%+v", item)
699 }
700
701
702
703 func patchContainerImages(containers []v1.Container) error {
704 var err error
705 for i, c := range containers {
706 containers[i].Image, err = imageutils.ReplaceRegistryInImageURL(c.Image)
707 if err != nil {
708 return err
709 }
710 }
711
712 return nil
713 }
714
View as plain text