1
16
17 package integration
18
19 import (
20 "context"
21 "fmt"
22 "testing"
23
24 apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
25 "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
26 "k8s.io/apimachinery/pkg/api/errors"
27 "k8s.io/apimachinery/pkg/api/meta"
28 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
29 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
30 "k8s.io/apimachinery/pkg/runtime/schema"
31 "k8s.io/client-go/dynamic"
32 _ "k8s.io/component-base/logs/testinit"
33 )
34
35 var swaggerMetadataDescriptions = metav1.ObjectMeta{}.SwaggerDoc()
36
37 func instantiateCustomResource(t *testing.T, instanceToCreate *unstructured.Unstructured, client dynamic.ResourceInterface, definition *apiextensionsv1.CustomResourceDefinition) (*unstructured.Unstructured, error) {
38 return instantiateVersionedCustomResource(t, instanceToCreate, client, definition, definition.Spec.Versions[0].Name)
39 }
40
41 func instantiateVersionedCustomResource(t *testing.T, instanceToCreate *unstructured.Unstructured, client dynamic.ResourceInterface, definition *apiextensionsv1.CustomResourceDefinition, version string) (*unstructured.Unstructured, error) {
42 createdInstance, err := client.Create(context.TODO(), instanceToCreate, metav1.CreateOptions{})
43 if err != nil {
44 t.Logf("%#v", createdInstance)
45 return nil, err
46 }
47 createdObjectMeta, err := meta.Accessor(createdInstance)
48 if err != nil {
49 t.Fatal(err)
50 }
51
52 if len(createdObjectMeta.GetUID()) == 0 {
53 t.Errorf("missing uuid: %#v", createdInstance)
54 }
55 createdTypeMeta, err := meta.TypeAccessor(createdInstance)
56 if err != nil {
57 t.Fatal(err)
58 }
59 if e, a := definition.Spec.Group+"/"+version, createdTypeMeta.GetAPIVersion(); e != a {
60 t.Errorf("expected %v, got %v", e, a)
61 }
62 if e, a := definition.Spec.Names.Kind, createdTypeMeta.GetKind(); e != a {
63 t.Errorf("expected %v, got %v", e, a)
64 }
65 return createdInstance, nil
66 }
67
68 func newNamespacedCustomResourceVersionedClient(ns string, client dynamic.Interface, crd *apiextensionsv1.CustomResourceDefinition, version string) dynamic.ResourceInterface {
69 gvr := schema.GroupVersionResource{Group: crd.Spec.Group, Version: version, Resource: crd.Spec.Names.Plural}
70
71 if crd.Spec.Scope != apiextensionsv1.ClusterScoped {
72 return client.Resource(gvr).Namespace(ns)
73 }
74 return client.Resource(gvr)
75 }
76
77 func newNamespacedCustomResourceClient(ns string, client dynamic.Interface, crd *apiextensionsv1.CustomResourceDefinition) dynamic.ResourceInterface {
78 return newNamespacedCustomResourceVersionedClient(ns, client, crd, crd.Spec.Versions[0].Name)
79 }
80
81
82 func UpdateCustomResourceDefinitionWithRetry(client clientset.Interface, name string, update func(*apiextensionsv1.CustomResourceDefinition)) (*apiextensionsv1.CustomResourceDefinition, error) {
83 for i := 0; i < 5; i++ {
84 crd, err := client.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{})
85 if err != nil {
86 return nil, fmt.Errorf("failed to get CustomResourceDefinition %q: %v", name, err)
87 }
88 update(crd)
89 crd, err = client.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
90 if err == nil {
91 return crd, nil
92 }
93 if !errors.IsConflict(err) {
94 return nil, fmt.Errorf("failed to update CustomResourceDefinition %q: %v", name, err)
95 }
96 }
97 return nil, fmt.Errorf("too many retries after conflicts updating CustomResourceDefinition %q", name)
98 }
99
100
101 func UpdateV1CustomResourceDefinitionWithRetry(client clientset.Interface, name string, update func(*apiextensionsv1.CustomResourceDefinition)) (*apiextensionsv1.CustomResourceDefinition, error) {
102 for i := 0; i < 5; i++ {
103 crd, err := client.ApiextensionsV1().CustomResourceDefinitions().Get(context.TODO(), name, metav1.GetOptions{})
104 if err != nil {
105 return nil, fmt.Errorf("failed to get CustomResourceDefinition %q: %v", name, err)
106 }
107 update(crd)
108 crd, err = client.ApiextensionsV1().CustomResourceDefinitions().Update(context.TODO(), crd, metav1.UpdateOptions{})
109 if err == nil {
110 return crd, nil
111 }
112 if !errors.IsConflict(err) {
113 return nil, fmt.Errorf("failed to update CustomResourceDefinition %q: %v", name, err)
114 }
115 }
116 return nil, fmt.Errorf("too many retries after conflicts updating CustomResourceDefinition %q", name)
117 }
118
119
120 func getSchemaForVersion(crd *apiextensionsv1.CustomResourceDefinition, version string) (*apiextensionsv1.CustomResourceValidation, error) {
121 for _, v := range crd.Spec.Versions {
122 if version == v.Name {
123 return v.Schema, nil
124 }
125 }
126 return nil, fmt.Errorf("version %s not found in CustomResourceDefinition: %v", version, crd.Name)
127 }
128
129
130 func getSubresourcesForVersion(crd *apiextensionsv1.CustomResourceDefinition, version string) (*apiextensionsv1.CustomResourceSubresources, error) {
131 for _, v := range crd.Spec.Versions {
132 if version == v.Name {
133 return v.Subresources, nil
134 }
135 }
136 return nil, fmt.Errorf("version %s not found in CustomResourceDefinition: %v", version, crd.Name)
137 }
138
139
140
141
142
143 func getColumnsForVersion(crd *apiextensionsv1.CustomResourceDefinition, version string) ([]apiextensionsv1.CustomResourceColumnDefinition, error) {
144 for _, v := range crd.Spec.Versions {
145 if version == v.Name {
146 return serveDefaultColumnsIfEmpty(v.AdditionalPrinterColumns), nil
147 }
148 }
149 return nil, fmt.Errorf("version %s not found in CustomResourceDefinition: %v", version, crd.Name)
150 }
151
152
153
154
155
156 func serveDefaultColumnsIfEmpty(columns []apiextensionsv1.CustomResourceColumnDefinition) []apiextensionsv1.CustomResourceColumnDefinition {
157 if len(columns) > 0 {
158 return columns
159 }
160 return []apiextensionsv1.CustomResourceColumnDefinition{
161 {Name: "Age", Type: "date", Description: swaggerMetadataDescriptions["creationTimestamp"], JSONPath: ".metadata.creationTimestamp"},
162 }
163 }
164
View as plain text