k8s.io/kubernetes@v1.29.3/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 66 factory := factories[what] 67 if factory == nil { 68 return fmt.Errorf("item of type %+v not supported", what) 69 } 70 71 object := factory.New() 72 if err := runtime.DecodeInto(scheme.Codecs.UniversalDecoder(), data, object); err != nil { 73 return fmt.Errorf("decode %+v: %w", what, err) 74 } 75 items = append(items, object) 76 return nil 77 }, files...) 78 79 return items, err 80 } 81 82 func visitManifests(cb func([]byte) error, files ...string) error { 83 for _, fileName := range files { 84 data, err := e2etestfiles.Read(fileName) 85 if err != nil { 86 framework.Failf("reading manifest file: %v", err) 87 } 88 89 // Split at the "---" separator before working on 90 // individual item. Only works for .yaml. 91 // 92 // We need to split ourselves because we need access 93 // to each original chunk of data for 94 // runtime.DecodeInto. kubectl has its own 95 // infrastructure for this, but that is a lot of code 96 // with many dependencies. 97 items := bytes.Split(data, []byte("\n---")) 98 99 for _, item := range items { 100 if err := cb(item); err != nil { 101 return fmt.Errorf("%s: %w", fileName, err) 102 } 103 } 104 } 105 return nil 106 } 107 108 // PatchItems modifies the given items in place such that each test 109 // gets its own instances, to avoid conflicts between different tests 110 // and between tests and normal deployments. 111 // 112 // This is done by: 113 // - creating namespaced items inside the test's namespace 114 // - changing the name of non-namespaced items like ClusterRole 115 // 116 // PatchItems has some limitations: 117 // - only some common items are supported, unknown ones trigger an error 118 // - only the latest stable API version for each item is supported 119 func PatchItems(f *framework.Framework, driverNamespace *v1.Namespace, items ...interface{}) error { 120 for _, item := range items { 121 // Uncomment when debugging the loading and patching of items. 122 // Logf("patching original content of %T:\n%s", item, PrettyPrint(item)) 123 if err := patchItemRecursively(f, driverNamespace, item); err != nil { 124 return err 125 } 126 } 127 return nil 128 } 129 130 // CreateItems creates the items. Each of them must be an API object 131 // of a type that is registered in Factory. 132 // 133 // It returns either a cleanup function or an error, but never both. 134 // 135 // Cleaning up after a test can be triggered in two ways: 136 // - the test invokes the returned cleanup function, 137 // usually in an AfterEach 138 // - the test suite terminates, potentially after 139 // skipping the test's AfterEach (https://github.com/onsi/ginkgo/issues/222) 140 // 141 // PatchItems has the some limitations as LoadFromManifests: 142 // - only some common items are supported, unknown ones trigger an error 143 // - only the latest stable API version for each item is supported 144 func CreateItems(ctx context.Context, f *framework.Framework, ns *v1.Namespace, items ...interface{}) error { 145 var result error 146 for _, item := range items { 147 // Each factory knows which item(s) it supports, so try each one. 148 done := false 149 description := describeItem(item) 150 // Uncomment this line to get a full dump of the entire item. 151 // description = fmt.Sprintf("%s:\n%s", description, PrettyPrint(item)) 152 framework.Logf("creating %s", description) 153 for _, factory := range factories { 154 destructor, err := factory.Create(ctx, f, ns, item) 155 if destructor != nil { 156 ginkgo.DeferCleanup(framework.IgnoreNotFound(destructor), framework.AnnotatedLocation(fmt.Sprintf("deleting %s", description))) 157 } 158 if err == nil { 159 done = true 160 break 161 } else if !errors.Is(err, errorItemNotSupported) { 162 result = err 163 break 164 } 165 } 166 if result == nil && !done { 167 result = fmt.Errorf("item of type %T not supported", item) 168 break 169 } 170 } 171 172 return result 173 } 174 175 // CreateFromManifests is a combination of LoadFromManifests, 176 // PatchItems, patching with an optional custom function, 177 // and CreateItems. 178 func CreateFromManifests(ctx context.Context, f *framework.Framework, driverNamespace *v1.Namespace, patch func(item interface{}) error, files ...string) error { 179 items, err := LoadFromManifests(files...) 180 if err != nil { 181 return fmt.Errorf("CreateFromManifests: %w", err) 182 } 183 if err := PatchItems(f, driverNamespace, items...); err != nil { 184 return err 185 } 186 if patch != nil { 187 for _, item := range items { 188 if err := patch(item); err != nil { 189 return err 190 } 191 } 192 } 193 return CreateItems(ctx, f, driverNamespace, items...) 194 } 195 196 // What is a subset of metav1.TypeMeta which (in contrast to 197 // metav1.TypeMeta itself) satisfies the runtime.Object interface. 198 type What struct { 199 Kind string `json:"kind"` 200 } 201 202 // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new What. 203 func (in *What) DeepCopy() *What { 204 return &What{Kind: in.Kind} 205 } 206 207 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. 208 func (in *What) DeepCopyInto(out *What) { 209 out.Kind = in.Kind 210 } 211 212 // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. 213 func (in *What) DeepCopyObject() runtime.Object { 214 return &What{Kind: in.Kind} 215 } 216 217 // GetObjectKind returns the ObjectKind schema 218 func (in *What) GetObjectKind() schema.ObjectKind { 219 return nil 220 } 221 222 // ItemFactory provides support for creating one particular item. 223 // The type gets exported because other packages might want to 224 // extend the set of pre-defined factories. 225 type ItemFactory interface { 226 // New returns a new empty item. 227 New() runtime.Object 228 229 // Create is responsible for creating the item. It returns an 230 // error or a cleanup function for the created item. 231 // If the item is of an unsupported type, it must return 232 // an error that has errorItemNotSupported as cause. 233 Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, item interface{}) (func(ctx context.Context) error, error) 234 } 235 236 // describeItem always returns a string that describes the item, 237 // usually by calling out to cache.MetaNamespaceKeyFunc which 238 // concatenates namespace (if set) and name. If that fails, the entire 239 // item gets converted to a string. 240 func describeItem(item interface{}) string { 241 key, err := cache.MetaNamespaceKeyFunc(item) 242 if err == nil && key != "" { 243 return fmt.Sprintf("%T: %s", item, key) 244 } 245 return fmt.Sprintf("%T: %s", item, item) 246 } 247 248 // errorItemNotSupported is the error that Create methods 249 // must return or wrap when they don't support the given item. 250 var errorItemNotSupported = errors.New("not supported") 251 252 var factories = map[What]ItemFactory{ 253 {"ClusterRole"}: &clusterRoleFactory{}, 254 {"ClusterRoleBinding"}: &clusterRoleBindingFactory{}, 255 {"CSIDriver"}: &csiDriverFactory{}, 256 {"DaemonSet"}: &daemonSetFactory{}, 257 {"ReplicaSet"}: &replicaSetFactory{}, 258 {"Role"}: &roleFactory{}, 259 {"RoleBinding"}: &roleBindingFactory{}, 260 {"Secret"}: &secretFactory{}, 261 {"Service"}: &serviceFactory{}, 262 {"ServiceAccount"}: &serviceAccountFactory{}, 263 {"StatefulSet"}: &statefulSetFactory{}, 264 {"Deployment"}: &deploymentFactory{}, 265 {"StorageClass"}: &storageClassFactory{}, 266 {"CustomResourceDefinition"}: &customResourceDefinitionFactory{}, 267 } 268 269 // PatchName makes the name of some item unique by appending the 270 // generated unique name. 271 func PatchName(f *framework.Framework, item *string) { 272 if *item != "" { 273 *item = *item + "-" + f.UniqueName 274 } 275 } 276 277 // PatchNamespace moves the item into the test's namespace. Not 278 // all items can be namespaced. For those, the name also needs to be 279 // patched. 280 func PatchNamespace(f *framework.Framework, driverNamespace *v1.Namespace, item *string) { 281 if driverNamespace != nil { 282 *item = driverNamespace.GetName() 283 return 284 } 285 286 if f.Namespace != nil { 287 *item = f.Namespace.GetName() 288 } 289 } 290 291 func patchItemRecursively(f *framework.Framework, driverNamespace *v1.Namespace, item interface{}) error { 292 switch item := item.(type) { 293 case *rbacv1.Subject: 294 PatchNamespace(f, driverNamespace, &item.Namespace) 295 case *rbacv1.RoleRef: 296 // TODO: avoid hard-coding this special name. Perhaps add a Framework.PredefinedRoles 297 // which contains all role names that are defined cluster-wide before the test starts? 298 // All those names are exempt from renaming. That list could be populated by querying 299 // and get extended by tests. 300 if item.Name != "e2e-test-privileged-psp" { 301 PatchName(f, &item.Name) 302 } 303 case *rbacv1.ClusterRole: 304 PatchName(f, &item.Name) 305 case *rbacv1.Role: 306 PatchNamespace(f, driverNamespace, &item.Namespace) 307 // Roles are namespaced, but because for RoleRef above we don't 308 // know whether the referenced role is a ClusterRole or Role 309 // and therefore always renames, we have to do the same here. 310 PatchName(f, &item.Name) 311 case *storagev1.StorageClass: 312 PatchName(f, &item.Name) 313 case *storagev1.CSIDriver: 314 PatchName(f, &item.Name) 315 case *v1.ServiceAccount: 316 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace) 317 case *v1.Secret: 318 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace) 319 case *rbacv1.ClusterRoleBinding: 320 PatchName(f, &item.Name) 321 for i := range item.Subjects { 322 if err := patchItemRecursively(f, driverNamespace, &item.Subjects[i]); err != nil { 323 return fmt.Errorf("%T: %w", f, err) 324 } 325 } 326 if err := patchItemRecursively(f, driverNamespace, &item.RoleRef); err != nil { 327 return fmt.Errorf("%T: %w", f, err) 328 } 329 case *rbacv1.RoleBinding: 330 PatchNamespace(f, driverNamespace, &item.Namespace) 331 for i := range item.Subjects { 332 if err := patchItemRecursively(f, driverNamespace, &item.Subjects[i]); err != nil { 333 return fmt.Errorf("%T: %w", f, err) 334 } 335 } 336 if err := patchItemRecursively(f, driverNamespace, &item.RoleRef); err != nil { 337 return fmt.Errorf("%T: %w", f, err) 338 } 339 case *v1.Service: 340 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace) 341 case *appsv1.StatefulSet: 342 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace) 343 if err := patchContainerImages(item.Spec.Template.Spec.Containers); err != nil { 344 return err 345 } 346 if err := patchContainerImages(item.Spec.Template.Spec.InitContainers); err != nil { 347 return err 348 } 349 case *appsv1.Deployment: 350 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace) 351 if err := patchContainerImages(item.Spec.Template.Spec.Containers); err != nil { 352 return err 353 } 354 if err := patchContainerImages(item.Spec.Template.Spec.InitContainers); err != nil { 355 return err 356 } 357 case *appsv1.DaemonSet: 358 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace) 359 if err := patchContainerImages(item.Spec.Template.Spec.Containers); err != nil { 360 return err 361 } 362 if err := patchContainerImages(item.Spec.Template.Spec.InitContainers); err != nil { 363 return err 364 } 365 case *appsv1.ReplicaSet: 366 PatchNamespace(f, driverNamespace, &item.ObjectMeta.Namespace) 367 if err := patchContainerImages(item.Spec.Template.Spec.Containers); err != nil { 368 return err 369 } 370 if err := patchContainerImages(item.Spec.Template.Spec.InitContainers); err != nil { 371 return err 372 } 373 case *apiextensionsv1.CustomResourceDefinition: 374 // Do nothing. Patching name to all CRDs won't always be the expected behavior. 375 default: 376 return fmt.Errorf("missing support for patching item of type %T", item) 377 } 378 return nil 379 } 380 381 // The individual factories all follow the same template, but with 382 // enough differences in types and functions that copy-and-paste 383 // looked like the least dirty approach. Perhaps one day Go will have 384 // generics. 385 386 type serviceAccountFactory struct{} 387 388 func (f *serviceAccountFactory) New() runtime.Object { 389 return &v1.ServiceAccount{} 390 } 391 392 func (*serviceAccountFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 393 item, ok := i.(*v1.ServiceAccount) 394 if !ok { 395 return nil, errorItemNotSupported 396 } 397 client := f.ClientSet.CoreV1().ServiceAccounts(ns.Name) 398 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 399 return nil, fmt.Errorf("create ServiceAccount: %w", err) 400 } 401 return func(ctx context.Context) error { 402 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 403 }, nil 404 } 405 406 type clusterRoleFactory struct{} 407 408 func (f *clusterRoleFactory) New() runtime.Object { 409 return &rbacv1.ClusterRole{} 410 } 411 412 func (*clusterRoleFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 413 item, ok := i.(*rbacv1.ClusterRole) 414 if !ok { 415 return nil, errorItemNotSupported 416 } 417 418 framework.Logf("Define cluster role %v", item.GetName()) 419 client := f.ClientSet.RbacV1().ClusterRoles() 420 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 421 return nil, fmt.Errorf("create ClusterRole: %w", err) 422 } 423 return func(ctx context.Context) error { 424 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 425 }, nil 426 } 427 428 type clusterRoleBindingFactory struct{} 429 430 func (f *clusterRoleBindingFactory) New() runtime.Object { 431 return &rbacv1.ClusterRoleBinding{} 432 } 433 434 func (*clusterRoleBindingFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 435 item, ok := i.(*rbacv1.ClusterRoleBinding) 436 if !ok { 437 return nil, errorItemNotSupported 438 } 439 440 client := f.ClientSet.RbacV1().ClusterRoleBindings() 441 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 442 return nil, fmt.Errorf("create ClusterRoleBinding: %w", err) 443 } 444 return func(ctx context.Context) error { 445 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 446 }, nil 447 } 448 449 type roleFactory struct{} 450 451 func (f *roleFactory) New() runtime.Object { 452 return &rbacv1.Role{} 453 } 454 455 func (*roleFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 456 item, ok := i.(*rbacv1.Role) 457 if !ok { 458 return nil, errorItemNotSupported 459 } 460 461 client := f.ClientSet.RbacV1().Roles(ns.Name) 462 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 463 return nil, fmt.Errorf("create Role: %w", err) 464 } 465 return func(ctx context.Context) error { 466 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 467 }, nil 468 } 469 470 type roleBindingFactory struct{} 471 472 func (f *roleBindingFactory) New() runtime.Object { 473 return &rbacv1.RoleBinding{} 474 } 475 476 func (*roleBindingFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 477 item, ok := i.(*rbacv1.RoleBinding) 478 if !ok { 479 return nil, errorItemNotSupported 480 } 481 482 client := f.ClientSet.RbacV1().RoleBindings(ns.Name) 483 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 484 return nil, fmt.Errorf("create RoleBinding: %w", err) 485 } 486 return func(ctx context.Context) error { 487 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 488 }, nil 489 } 490 491 type serviceFactory struct{} 492 493 func (f *serviceFactory) New() runtime.Object { 494 return &v1.Service{} 495 } 496 497 func (*serviceFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 498 item, ok := i.(*v1.Service) 499 if !ok { 500 return nil, errorItemNotSupported 501 } 502 503 client := f.ClientSet.CoreV1().Services(ns.Name) 504 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 505 return nil, fmt.Errorf("create Service: %w", err) 506 } 507 return func(ctx context.Context) error { 508 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 509 }, nil 510 } 511 512 type statefulSetFactory struct{} 513 514 func (f *statefulSetFactory) New() runtime.Object { 515 return &appsv1.StatefulSet{} 516 } 517 518 func (*statefulSetFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 519 item, ok := i.(*appsv1.StatefulSet) 520 if !ok { 521 return nil, errorItemNotSupported 522 } 523 524 client := f.ClientSet.AppsV1().StatefulSets(ns.Name) 525 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 526 return nil, fmt.Errorf("create StatefulSet: %w", err) 527 } 528 return func(ctx context.Context) error { 529 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 530 }, nil 531 } 532 533 type deploymentFactory struct{} 534 535 func (f *deploymentFactory) New() runtime.Object { 536 return &appsv1.Deployment{} 537 } 538 539 func (*deploymentFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 540 item, ok := i.(*appsv1.Deployment) 541 if !ok { 542 return nil, errorItemNotSupported 543 } 544 545 client := f.ClientSet.AppsV1().Deployments(ns.Name) 546 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 547 return nil, fmt.Errorf("create Deployment: %w", err) 548 } 549 return func(ctx context.Context) error { 550 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 551 }, nil 552 } 553 554 type daemonSetFactory struct{} 555 556 func (f *daemonSetFactory) New() runtime.Object { 557 return &appsv1.DaemonSet{} 558 } 559 560 func (*daemonSetFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 561 item, ok := i.(*appsv1.DaemonSet) 562 if !ok { 563 return nil, errorItemNotSupported 564 } 565 566 client := f.ClientSet.AppsV1().DaemonSets(ns.Name) 567 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 568 return nil, fmt.Errorf("create DaemonSet: %w", err) 569 } 570 return func(ctx context.Context) error { 571 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 572 }, nil 573 } 574 575 type replicaSetFactory struct{} 576 577 func (f *replicaSetFactory) New() runtime.Object { 578 return &appsv1.ReplicaSet{} 579 } 580 581 func (*replicaSetFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 582 item, ok := i.(*appsv1.ReplicaSet) 583 if !ok { 584 return nil, errorItemNotSupported 585 } 586 587 client := f.ClientSet.AppsV1().ReplicaSets(ns.Name) 588 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 589 return nil, fmt.Errorf("create ReplicaSet: %w", err) 590 } 591 return func(ctx context.Context) error { 592 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 593 }, nil 594 } 595 596 type storageClassFactory struct{} 597 598 func (f *storageClassFactory) New() runtime.Object { 599 return &storagev1.StorageClass{} 600 } 601 602 func (*storageClassFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 603 item, ok := i.(*storagev1.StorageClass) 604 if !ok { 605 return nil, errorItemNotSupported 606 } 607 608 client := f.ClientSet.StorageV1().StorageClasses() 609 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 610 return nil, fmt.Errorf("create StorageClass: %w", err) 611 } 612 return func(ctx context.Context) error { 613 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 614 }, nil 615 } 616 617 type csiDriverFactory struct{} 618 619 func (f *csiDriverFactory) New() runtime.Object { 620 return &storagev1.CSIDriver{} 621 } 622 623 func (*csiDriverFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 624 item, ok := i.(*storagev1.CSIDriver) 625 if !ok { 626 return nil, errorItemNotSupported 627 } 628 629 client := f.ClientSet.StorageV1().CSIDrivers() 630 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 631 return nil, fmt.Errorf("create CSIDriver: %w", err) 632 } 633 return func(ctx context.Context) error { 634 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 635 }, nil 636 } 637 638 type secretFactory struct{} 639 640 func (f *secretFactory) New() runtime.Object { 641 return &v1.Secret{} 642 } 643 644 func (*secretFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 645 item, ok := i.(*v1.Secret) 646 if !ok { 647 return nil, errorItemNotSupported 648 } 649 650 client := f.ClientSet.CoreV1().Secrets(ns.Name) 651 if _, err := client.Create(ctx, item, metav1.CreateOptions{}); err != nil { 652 return nil, fmt.Errorf("create Secret: %w", err) 653 } 654 return func(ctx context.Context) error { 655 return client.Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 656 }, nil 657 } 658 659 type customResourceDefinitionFactory struct{} 660 661 func (f *customResourceDefinitionFactory) New() runtime.Object { 662 return &apiextensionsv1.CustomResourceDefinition{} 663 } 664 665 func (*customResourceDefinitionFactory) Create(ctx context.Context, f *framework.Framework, ns *v1.Namespace, i interface{}) (func(ctx context.Context) error, error) { 666 var err error 667 unstructCRD := &unstructured.Unstructured{} 668 gvr := schema.GroupVersionResource{Group: "apiextensions.k8s.io", Version: "v1", Resource: "customresourcedefinitions"} 669 670 item, ok := i.(*apiextensionsv1.CustomResourceDefinition) 671 if !ok { 672 return nil, errorItemNotSupported 673 } 674 675 unstructCRD.Object, err = runtime.DefaultUnstructuredConverter.ToUnstructured(i) 676 if err != nil { 677 return nil, err 678 } 679 680 if _, err = f.DynamicClient.Resource(gvr).Create(ctx, unstructCRD, metav1.CreateOptions{}); err != nil { 681 return nil, fmt.Errorf("create CustomResourceDefinition: %w", err) 682 } 683 return func(ctx context.Context) error { 684 return f.DynamicClient.Resource(gvr).Delete(ctx, item.GetName(), metav1.DeleteOptions{}) 685 }, nil 686 } 687 688 // PrettyPrint returns a human-readable representation of an item. 689 func PrettyPrint(item interface{}) string { 690 data, err := json.MarshalIndent(item, "", " ") 691 if err == nil { 692 return string(data) 693 } 694 return fmt.Sprintf("%+v", item) 695 } 696 697 // patchContainerImages replaces the specified Container Registry with a custom 698 // one provided via the KUBE_TEST_REPO_LIST env variable 699 func patchContainerImages(containers []v1.Container) error { 700 var err error 701 for i, c := range containers { 702 containers[i].Image, err = imageutils.ReplaceRegistryInImageURL(c.Image) 703 if err != nil { 704 return err 705 } 706 } 707 708 return nil 709 }