k8s.io/kubernetes@v1.29.3/test/utils/crd/crd_util.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 crd
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  
    23  	"k8s.io/utils/pointer"
    24  
    25  	apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
    26  	crdclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
    27  	"k8s.io/apiextensions-apiserver/test/integration/fixtures"
    28  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    29  	"k8s.io/apimachinery/pkg/runtime/schema"
    30  	"k8s.io/client-go/dynamic"
    31  	"k8s.io/kubernetes/test/e2e/framework"
    32  )
    33  
    34  // CleanCrdFn declares the clean up function needed to remove the CRD
    35  type CleanCrdFn func(ctx context.Context) error
    36  
    37  // TestCrd holds all the pieces needed to test with the CRD
    38  type TestCrd struct {
    39  	APIExtensionClient *crdclientset.Clientset
    40  	Crd                *apiextensionsv1.CustomResourceDefinition
    41  	DynamicClients     map[string]dynamic.ResourceInterface
    42  	CleanUp            CleanCrdFn
    43  }
    44  
    45  // Option is a modifier for a CRD object used to customize CreateMultiVersionTestCRD and CreateTestCRD.
    46  type Option func(crd *apiextensionsv1.CustomResourceDefinition)
    47  
    48  // CreateMultiVersionTestCRD creates a new CRD specifically for the calling test.
    49  func CreateMultiVersionTestCRD(f *framework.Framework, group string, opts ...Option) (*TestCrd, error) {
    50  	suffix := framework.RandomSuffix()
    51  	name := fmt.Sprintf("e2e-test-%s-%s-crd", f.BaseName, suffix)
    52  	kind := fmt.Sprintf("e2e-test-%s-%s-crd", f.BaseName, suffix)
    53  	testcrd := &TestCrd{}
    54  
    55  	// Creating a custom resource definition for use by assorted tests.
    56  	config, err := framework.LoadConfig()
    57  	if err != nil {
    58  		framework.Failf("failed to load config: %v", err)
    59  		return nil, err
    60  	}
    61  	apiExtensionClient, err := crdclientset.NewForConfig(config)
    62  	if err != nil {
    63  		framework.Failf("failed to initialize apiExtensionClient: %v", err)
    64  		return nil, err
    65  	}
    66  	dynamicClient, err := dynamic.NewForConfig(config)
    67  	if err != nil {
    68  		framework.Failf("failed to initialize dynamic client: %v", err)
    69  		return nil, err
    70  	}
    71  
    72  	crd := &apiextensionsv1.CustomResourceDefinition{
    73  		ObjectMeta: metav1.ObjectMeta{Name: name + "s." + group},
    74  		Spec: apiextensionsv1.CustomResourceDefinitionSpec{
    75  			Group: group,
    76  			Names: apiextensionsv1.CustomResourceDefinitionNames{
    77  				Plural:   name + "s",
    78  				Singular: name,
    79  				Kind:     kind,
    80  				ListKind: kind + "List",
    81  			},
    82  			Scope: apiextensionsv1.NamespaceScoped,
    83  		},
    84  	}
    85  	for _, opt := range opts {
    86  		opt(crd)
    87  	}
    88  	if len(crd.Spec.Versions) == 0 {
    89  		crd.Spec.Versions = []apiextensionsv1.CustomResourceDefinitionVersion{{
    90  			Served:  true,
    91  			Storage: true,
    92  			Name:    "v1",
    93  			Schema:  fixtures.AllowAllSchema(),
    94  		}}
    95  	}
    96  
    97  	//create CRD and waits for the resource to be recognized and available.
    98  	crd, err = fixtures.CreateNewV1CustomResourceDefinitionWatchUnsafe(crd, apiExtensionClient)
    99  	if err != nil {
   100  		framework.Failf("failed to create CustomResourceDefinition: %v", err)
   101  		return nil, err
   102  	}
   103  
   104  	resourceClients := map[string]dynamic.ResourceInterface{}
   105  	for _, v := range crd.Spec.Versions {
   106  		if v.Served {
   107  			gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: v.Name, Resource: crd.Spec.Names.Plural}
   108  			resourceClients[v.Name] = dynamicClient.Resource(gvr).Namespace(f.Namespace.Name)
   109  		}
   110  	}
   111  
   112  	testcrd.APIExtensionClient = apiExtensionClient
   113  	testcrd.Crd = crd
   114  	testcrd.DynamicClients = resourceClients
   115  	testcrd.CleanUp = func(ctx context.Context) error {
   116  		err := fixtures.DeleteV1CustomResourceDefinition(crd, apiExtensionClient)
   117  		if err != nil {
   118  			framework.Failf("failed to delete CustomResourceDefinition(%s): %v", name, err)
   119  		}
   120  		return err
   121  	}
   122  	return testcrd, nil
   123  }
   124  
   125  // CreateTestCRD creates a new CRD specifically for the calling test.
   126  func CreateTestCRD(f *framework.Framework, opts ...Option) (*TestCrd, error) {
   127  	group := fmt.Sprintf("%s.example.com", f.BaseName)
   128  	return CreateMultiVersionTestCRD(f, group, append([]Option{func(crd *apiextensionsv1.CustomResourceDefinition) {
   129  		crd.Spec.Versions = []apiextensionsv1.CustomResourceDefinitionVersion{
   130  			{
   131  				Name:    "v1",
   132  				Served:  true,
   133  				Storage: true,
   134  				Schema: &apiextensionsv1.CustomResourceValidation{
   135  					OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{
   136  						XPreserveUnknownFields: pointer.BoolPtr(true),
   137  						Type:                   "object",
   138  					},
   139  				},
   140  			},
   141  		}
   142  	}}, opts...)...)
   143  }