...

Source file src/k8s.io/kubernetes/test/e2e/storage/utils/create.go

Documentation: k8s.io/kubernetes/test/e2e/storage/utils

     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  }
   714  

View as plain text