k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/test/e2e/storage/utils/create.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 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 // LoadFromManifests loads .yaml or .json manifest files and returns 45 // all items that it finds in them. It supports all items for which 46 // there is a factory registered in factories and .yaml files with 47 // multiple items separated by "---". Files are accessed via the 48 // "testfiles" package, which means they can come from a file system 49 // or be built into the binary. 50 // 51 // LoadFromManifests has some limitations: 52 // - aliases are not supported (i.e. use serviceAccountName instead of the deprecated serviceAccount, 53 // https://kubernetes.io/docs/reference/kubernetes-api/workload-resources/pod-v1) 54 // and silently ignored 55 // - the latest stable API version for each item is used, regardless of what 56 // is specified in the manifest files 57 func LoadFromManifests(files ...string) ([]interface{}, error) { 58 var items []interface{} 59 err := visitManifests(func(data []byte) error { 60 // Ignore any additional fields for now, just determine what we have. 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 // Ignore empty documents. 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 // Split at the "---" separator before working on 94 // individual item. Only works for .yaml. 95 // 96 // We need to split ourselves because we need access 97 // to each original chunk of data for 98 // runtime.DecodeInto. kubectl has its own 99 // infrastructure for this, but that is a lot of code 100 // with many dependencies. 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 // PatchItems modifies the given items in place such that each test 113 // gets its own instances, to avoid conflicts between different tests 114 // and between tests and normal deployments. 115 // 116 // This is done by: 117 // - creating namespaced items inside the test's namespace 118 // - changing the name of non-namespaced items like ClusterRole 119 // 120 // PatchItems has some limitations: 121 // - only some common items are supported, unknown ones trigger an error 122 // - only the latest stable API version for each item is supported 123 func PatchItems(f *framework.Framework, driverNamespace *v1.Namespace, items ...interface{}) error { 124 for _, item := range items { 125 // Uncomment when debugging the loading and patching of items. 126 // Logf("patching original content of %T:\n%s", item, PrettyPrint(item)) 127 if err := patchItemRecursively(f, driverNamespace, item); err != nil { 128 return err 129 } 130 } 131 return nil 132 } 133 134 // CreateItems creates the items. Each of them must be an API object 135 // of a type that is registered in Factory. 136 // 137 // It returns either a cleanup function or an error, but never both. 138 // 139 // Cleaning up after a test can be triggered in two ways: 140 // - the test invokes the returned cleanup function, 141 // usually in an AfterEach 142 // - the test suite terminates, potentially after 143 // skipping the test's AfterEach (https://github.com/onsi/ginkgo/issues/222) 144 // 145 // PatchItems has the some limitations as LoadFromManifests: 146 // - only some common items are supported, unknown ones trigger an error 147 // - only the latest stable API version for each item is supported 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 // Each factory knows which item(s) it supports, so try each one. 152 done := false 153 description := describeItem(item) 154 // Uncomment this line to get a full dump of the entire item. 155 // description = fmt.Sprintf("%s:\n%s", description, PrettyPrint(item)) 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 // CreateFromManifests is a combination of LoadFromManifests, 180 // PatchItems, patching with an optional custom function, 181 // and CreateItems. 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 // What is a subset of metav1.TypeMeta which (in contrast to 201 // metav1.TypeMeta itself) satisfies the runtime.Object interface. 202 type What struct { 203 Kind string `json:"kind"` 204 } 205 206 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new What. 207 func (in *What) DeepCopy() *What { 208 return &What{Kind: in.Kind} 209 } 210 211 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. 212 func (in *What) DeepCopyInto(out *What) { 213 out.Kind = in.Kind 214 } 215 216 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 217 func (in *What) DeepCopyObject() runtime.Object { 218 return &What{Kind: in.Kind} 219 } 220 221 // GetObjectKind returns the ObjectKind schema 222 func (in *What) GetObjectKind() schema.ObjectKind { 223 return nil 224 } 225 226 // ItemFactory provides support for creating one particular item. 227 // The type gets exported because other packages might want to 228 // extend the set of pre-defined factories. 229 type ItemFactory interface { 230 // New returns a new empty item. 231 New() runtime.Object 232 233 // Create is responsible for creating the item. It returns an 234 // error or a cleanup function for the created item. 235 // If the item is of an unsupported type, it must return 236 // an error that has errorItemNotSupported as cause. 237 Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, item interface{}) (func(ctx context.Context) error, error) 238 } 239 240 // describeItem always returns a string that describes the item, 241 // usually by calling out to cache.MetaNamespaceKeyFunc which 242 // concatenates namespace (if set) and name. If that fails, the entire 243 // item gets converted to a string. 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 // errorItemNotSupported is the error that Create methods 253 // must return or wrap when they don't support the given item. 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 // PatchName makes the name of some item unique by appending the 274 // generated unique name. 275 func PatchName(f *framework.Framework, item *string) { 276 if *item != "" { 277 *item = *item + "-" + f.UniqueName 278 } 279 } 280 281 // PatchNamespace moves the item into the test's namespace. Not 282 // all items can be namespaced. For those, the name also needs to be 283 // patched. 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 // TODO: avoid hard-coding this special name. Perhaps add a Framework.PredefinedRoles 301 // which contains all role names that are defined cluster-wide before the test starts? 302 // All those names are exempt from renaming. That list could be populated by querying 303 // and get extended by tests. 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 // Roles are namespaced, but because for RoleRef above we don't 312 // know whether the referenced role is a ClusterRole or Role 313 // and therefore always renames, we have to do the same here. 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 // Do nothing. Patching name to all CRDs won't always be the expected behavior. 379 default: 380 return fmt.Errorf("missing support for patching item of type %T", item) 381 } 382 return nil 383 } 384 385 // The individual factories all follow the same template, but with 386 // enough differences in types and functions that copy-and-paste 387 // looked like the least dirty approach. Perhaps one day Go will have 388 // generics. 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 // PrettyPrint returns a human-readable representation of an item. 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 // patchContainerImages replaces the specified Container Registry with a custom 702 // one provided via the KUBE_TEST_REPO_LIST env variable 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 }