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  }