1/* 2Copyright 2018 The Kubernetes Authors. 3 4Licensed under the Apache License, Version 2.0 (the "License"); 5you may not use this file except in compliance with the License. 6You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10Unless required by applicable law or agreed to in writing, software 11distributed under the License is distributed on an "AS IS" BASIS, 12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13See the License for the specific language governing permissions and 14limitations under the License. 15*/ 16 17package crd 18 19import ( 20 "fmt" 21 22 "k8s.io/utils/pointer" 23 24 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" 25 crdclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" 26 "k8s.io/apiextensions-apiserver/test/integration/fixtures" 27 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 28 "k8s.io/apimachinery/pkg/runtime/schema" 29 "k8s.io/client-go/dynamic" 30 "k8s.io/kubernetes/test/e2e/framework" 31) 32 33// CleanCrdFn declares the clean up function needed to remove the CRD 34type CleanCrdFn func() error 35 36// TestCrd holds all the pieces needed to test with the CRD 37type TestCrd struct { 38 APIExtensionClient *crdclientset.Clientset 39 Crd *apiextensionsv1.CustomResourceDefinition 40 DynamicClients map[string]dynamic.ResourceInterface 41 CleanUp CleanCrdFn 42} 43 44// Option is a modifier for a CRD object used to customize CreateMultiVersionTestCRD and CreateTestCRD. 45type Option func(crd *apiextensionsv1.CustomResourceDefinition) 46 47// CreateMultiVersionTestCRD creates a new CRD specifically for the calling test. 48func CreateMultiVersionTestCRD(f *framework.Framework, group string, opts ...Option) (*TestCrd, error) { 49 suffix := framework.RandomSuffix() 50 name := fmt.Sprintf("e2e-test-%s-%s-crd", f.BaseName, suffix) 51 kind := fmt.Sprintf("e2e-test-%s-%s-crd", f.BaseName, suffix) 52 testcrd := &TestCrd{} 53 54 // Creating a custom resource definition for use by assorted tests. 55 config, err := framework.LoadConfig() 56 if err != nil { 57 framework.Failf("failed to load config: %v", err) 58 return nil, err 59 } 60 apiExtensionClient, err := crdclientset.NewForConfig(config) 61 if err != nil { 62 framework.Failf("failed to initialize apiExtensionClient: %v", err) 63 return nil, err 64 } 65 dynamicClient, err := dynamic.NewForConfig(config) 66 if err != nil { 67 framework.Failf("failed to initialize dynamic client: %v", err) 68 return nil, err 69 } 70 71 crd := &apiextensionsv1.CustomResourceDefinition{ 72 ObjectMeta: metav1.ObjectMeta{Name: name + "s." + group}, 73 Spec: apiextensionsv1.CustomResourceDefinitionSpec{ 74 Group: group, 75 Names: apiextensionsv1.CustomResourceDefinitionNames{ 76 Plural: name + "s", 77 Singular: name, 78 Kind: kind, 79 ListKind: kind + "List", 80 }, 81 Scope: apiextensionsv1.NamespaceScoped, 82 }, 83 } 84 for _, opt := range opts { 85 opt(crd) 86 } 87 if len(crd.Spec.Versions) == 0 { 88 crd.Spec.Versions = []apiextensionsv1.CustomResourceDefinitionVersion{{ 89 Served: true, 90 Storage: true, 91 Name: "v1", 92 Schema: fixtures.AllowAllSchema(), 93 }} 94 } 95 96 //create CRD and waits for the resource to be recognized and available. 97 crd, err = fixtures.CreateNewV1CustomResourceDefinitionWatchUnsafe(crd, apiExtensionClient) 98 if err != nil { 99 framework.Failf("failed to create CustomResourceDefinition: %v", err) 100 return nil, err 101 } 102 103 resourceClients := map[string]dynamic.ResourceInterface{} 104 for _, v := range crd.Spec.Versions { 105 if v.Served { 106 gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: v.Name, Resource: crd.Spec.Names.Plural} 107 resourceClients[v.Name] = dynamicClient.Resource(gvr).Namespace(f.Namespace.Name) 108 } 109 } 110 111 testcrd.APIExtensionClient = apiExtensionClient 112 testcrd.Crd = crd 113 testcrd.DynamicClients = resourceClients 114 testcrd.CleanUp = func() error { 115 err := fixtures.DeleteV1CustomResourceDefinition(crd, apiExtensionClient) 116 if err != nil { 117 framework.Failf("failed to delete CustomResourceDefinition(%s): %v", name, err) 118 } 119 return err 120 } 121 return testcrd, nil 122} 123 124// CreateTestCRD creates a new CRD specifically for the calling test. 125func CreateTestCRD(f *framework.Framework, opts ...Option) (*TestCrd, error) { 126 group := fmt.Sprintf("%s.example.com", f.BaseName) 127 return CreateMultiVersionTestCRD(f, group, append([]Option{func(crd *apiextensionsv1.CustomResourceDefinition) { 128 crd.Spec.Versions = []apiextensionsv1.CustomResourceDefinitionVersion{ 129 { 130 Name: "v1", 131 Served: true, 132 Storage: true, 133 Schema: &apiextensionsv1.CustomResourceValidation{ 134 OpenAPIV3Schema: &apiextensionsv1.JSONSchemaProps{ 135 XPreserveUnknownFields: pointer.BoolPtr(true), 136 Type: "object", 137 }, 138 }, 139 }, 140 } 141 }}, opts...)...) 142} 143