@@ -19,21 +19,23 @@ package envtest
19
19
import (
20
20
"bufio"
21
21
"bytes"
22
+ "context"
22
23
"io"
23
24
"io/ioutil"
24
25
"os"
25
26
"path/filepath"
26
27
"time"
27
28
28
- apiextensionsv1beta1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
29
29
"k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset"
30
30
apierrors "k8s.io/apimachinery/pkg/api/errors"
31
- metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
32
+ "k8s.io/apimachinery/pkg/runtime"
32
33
"k8s.io/apimachinery/pkg/runtime/schema"
33
34
"k8s.io/apimachinery/pkg/util/sets"
34
35
"k8s.io/apimachinery/pkg/util/wait"
35
36
k8syaml "k8s.io/apimachinery/pkg/util/yaml"
36
37
"k8s.io/client-go/rest"
38
+ "sigs.k8s.io/controller-runtime/pkg/client"
37
39
"sigs.k8s.io/yaml"
38
40
)
39
41
@@ -43,7 +45,7 @@ type CRDInstallOptions struct {
43
45
Paths []string
44
46
45
47
// CRDs is a list of CRDs to install
46
- CRDs []* apiextensionsv1beta1. CustomResourceDefinition
48
+ CRDs []runtime. Object
47
49
48
50
// ErrorIfPathMissing will cause an error if a Path does not exist
49
51
ErrorIfPathMissing bool
@@ -64,7 +66,7 @@ const defaultPollInterval = 100 * time.Millisecond
64
66
const defaultMaxWait = 10 * time .Second
65
67
66
68
// InstallCRDs installs a collection of CRDs into a cluster by reading the crd yaml files from a directory
67
- func InstallCRDs (config * rest.Config , options CRDInstallOptions ) ([]* apiextensionsv1beta1. CustomResourceDefinition , error ) {
69
+ func InstallCRDs (config * rest.Config , options CRDInstallOptions ) ([]runtime. Object , error ) {
68
70
defaultCRDOptions (& options )
69
71
70
72
// Read the CRD yamls into options.CRDs
@@ -109,27 +111,57 @@ func defaultCRDOptions(o *CRDInstallOptions) {
109
111
}
110
112
111
113
// WaitForCRDs waits for the CRDs to appear in discovery
112
- func WaitForCRDs (config * rest.Config , crds []* apiextensionsv1beta1. CustomResourceDefinition , options CRDInstallOptions ) error {
114
+ func WaitForCRDs (config * rest.Config , crds []runtime. Object , options CRDInstallOptions ) error {
113
115
// Add each CRD to a map of GroupVersion to Resource
114
116
waitingFor := map [schema.GroupVersion ]* sets.String {}
115
- for _ , crd := range crds {
117
+ for _ , crd := range runtimeListToUnstructured ( crds ) {
116
118
gvs := []schema.GroupVersion {}
117
- if crd .Spec .Version != "" {
118
- gvs = append (gvs , schema.GroupVersion {Group : crd .Spec .Group , Version : crd .Spec .Version })
119
+ crdGroup , _ , err := unstructured .NestedString (crd .Object , "spec" , "group" )
120
+ if err != nil {
121
+ return err
122
+ }
123
+ crdPlural , _ , err := unstructured .NestedString (crd .Object , "spec" , "names" , "plural" )
124
+ if err != nil {
125
+ return err
126
+ }
127
+ crdVersion , _ , err := unstructured .NestedString (crd .Object , "spec" , "version" )
128
+ if err != nil {
129
+ return err
119
130
}
120
- for _ , ver := range crd .Spec .Versions {
121
- if ver .Served {
122
- gvs = append (gvs , schema.GroupVersion {Group : crd .Spec .Group , Version : ver .Name })
131
+ if crdVersion != "" {
132
+ gvs = append (gvs , schema.GroupVersion {Group : crdGroup , Version : crdVersion })
133
+ }
134
+
135
+ versions , _ , err := unstructured .NestedSlice (crd .Object , "spec" , "versions" )
136
+ if err != nil {
137
+ return err
138
+ }
139
+ for _ , version := range versions {
140
+ versionMap , ok := version .(map [string ]interface {})
141
+ if ! ok {
142
+ continue
143
+ }
144
+ served , _ , err := unstructured .NestedBool (versionMap , "served" )
145
+ if err != nil {
146
+ return err
147
+ }
148
+ if served {
149
+ versionName , _ , err := unstructured .NestedString (versionMap , "name" )
150
+ if err != nil {
151
+ return err
152
+ }
153
+ gvs = append (gvs , schema.GroupVersion {Group : crdGroup , Version : versionName })
123
154
}
124
155
}
156
+
125
157
for _ , gv := range gvs {
126
158
log .V (1 ).Info ("adding API in waitlist" , "GV" , gv )
127
159
if _ , found := waitingFor [gv ]; ! found {
128
160
// Initialize the set
129
161
waitingFor [gv ] = & sets.String {}
130
162
}
131
163
// Add the Resource
132
- waitingFor [gv ].Insert (crd . Spec . Names . Plural )
164
+ waitingFor [gv ].Insert (crdPlural )
133
165
}
134
166
}
135
167
@@ -192,15 +224,15 @@ func UninstallCRDs(config *rest.Config, options CRDInstallOptions) error {
192
224
}
193
225
194
226
// Delete the CRDs from the apiserver
195
- cs , err := clientset . NewForConfig (config )
227
+ cs , err := client . New (config , client. Options {} )
196
228
if err != nil {
197
229
return err
198
230
}
199
231
200
232
// Uninstall each CRD
201
- for _ , crd := range options .CRDs {
202
- log .V (1 ).Info ("uninstalling CRD" , "crd" , crd .Name )
203
- if err := cs .ApiextensionsV1beta1 (). CustomResourceDefinitions (). Delete ( crd . Name , & metav1. DeleteOptions {} ); err != nil {
233
+ for _ , crd := range runtimeListToUnstructured ( options .CRDs ) {
234
+ log .V (1 ).Info ("uninstalling CRD" , "crd" , crd .GetName () )
235
+ if err := cs .Delete ( context . TODO (), crd ); err != nil {
204
236
// If CRD is not found, we can consider success
205
237
if ! apierrors .IsNotFound (err ) {
206
238
return err
@@ -212,26 +244,28 @@ func UninstallCRDs(config *rest.Config, options CRDInstallOptions) error {
212
244
}
213
245
214
246
// CreateCRDs creates the CRDs
215
- func CreateCRDs (config * rest.Config , crds []* apiextensionsv1beta1. CustomResourceDefinition ) error {
216
- cs , err := clientset . NewForConfig (config )
247
+ func CreateCRDs (config * rest.Config , crds []runtime. Object ) error {
248
+ cs , err := client . New (config , client. Options {} )
217
249
if err != nil {
218
250
return err
219
251
}
220
252
221
253
// Create each CRD
222
- for _ , crd := range crds {
223
- log .V (1 ).Info ("installing CRD" , "crd" , crd .Name )
224
- if existingCrd , err := cs .ApiextensionsV1beta1 ().CustomResourceDefinitions ().Get (crd .Name , metav1.GetOptions {}); err != nil {
225
- if ! apierrors .IsNotFound (err ) {
254
+ for _ , crd := range runtimeListToUnstructured (crds ) {
255
+ log .V (1 ).Info ("installing CRD" , "crd" , crd .GetName ())
256
+ existingCrd := crd .DeepCopy ()
257
+ err := cs .Get (context .TODO (), client.ObjectKey {Name : crd .GetName ()}, existingCrd )
258
+ switch {
259
+ case apierrors .IsNotFound (err ):
260
+ if err := cs .Create (context .TODO (), crd ); err != nil {
226
261
return err
227
262
}
228
- if _ , err := cs .ApiextensionsV1beta1 ().CustomResourceDefinitions ().Create (crd ); err != nil {
229
- return err
230
- }
231
- } else {
232
- log .V (1 ).Info ("CRD already exists, updating" , "crd" , crd .Name )
233
- crd .ResourceVersion = existingCrd .ResourceVersion
234
- if _ , err := cs .ApiextensionsV1beta1 ().CustomResourceDefinitions ().Update (crd ); err != nil {
263
+ case err != nil :
264
+ return err
265
+ default :
266
+ log .V (1 ).Info ("CRD already exists, updating" , "crd" , crd .GetName ())
267
+ crd .SetResourceVersion (existingCrd .GetResourceVersion ())
268
+ if err := cs .Update (context .TODO (), crd ); err != nil {
235
269
return err
236
270
}
237
271
}
@@ -240,11 +274,11 @@ func CreateCRDs(config *rest.Config, crds []*apiextensionsv1beta1.CustomResource
240
274
}
241
275
242
276
// renderCRDs iterate through options.Paths and extract all CRD files.
243
- func renderCRDs (options * CRDInstallOptions ) ([]* apiextensionsv1beta1. CustomResourceDefinition , error ) {
277
+ func renderCRDs (options * CRDInstallOptions ) ([]runtime. Object , error ) {
244
278
var (
245
279
err error
246
280
info os.FileInfo
247
- crds []* apiextensionsv1beta1. CustomResourceDefinition
281
+ crds []* unstructured. Unstructured
248
282
files []os.FileInfo
249
283
)
250
284
@@ -274,18 +308,18 @@ func renderCRDs(options *CRDInstallOptions) ([]*apiextensionsv1beta1.CustomResou
274
308
}
275
309
276
310
// If CRD already in the list, skip it.
277
- if existsCRDs (crds , crdList ) {
311
+ if existsUnstructured (crds , crdList ) {
278
312
continue
279
313
}
280
314
crds = append (crds , crdList ... )
281
315
}
282
316
283
- return crds , nil
317
+ return unstructuredListToRuntime ( crds ) , nil
284
318
}
285
319
286
320
// readCRDs reads the CRDs from files and Unmarshals them into structs
287
- func readCRDs (basePath string , files []os.FileInfo ) ([]* apiextensionsv1beta1. CustomResourceDefinition , error ) {
288
- var crds []* apiextensionsv1beta1. CustomResourceDefinition
321
+ func readCRDs (basePath string , files []os.FileInfo ) ([]* unstructured. Unstructured , error ) {
322
+ var crds []* unstructured. Unstructured
289
323
290
324
// White list the file extensions that may contain CRDs
291
325
crdExts := sets .NewString (".json" , ".yaml" , ".yml" )
@@ -303,13 +337,22 @@ func readCRDs(basePath string, files []os.FileInfo) ([]*apiextensionsv1beta1.Cus
303
337
}
304
338
305
339
for _ , doc := range docs {
306
- crd := & apiextensionsv1beta1. CustomResourceDefinition {}
340
+ crd := & unstructured. Unstructured {}
307
341
if err = yaml .Unmarshal (doc , crd ); err != nil {
308
342
return nil , err
309
343
}
310
344
311
345
// Check that it is actually a CRD
312
- if crd .Spec .Names .Kind == "" || crd .Spec .Group == "" {
346
+ crdKind , _ , err := unstructured .NestedString (crd .Object , "spec" , "names" , "kind" )
347
+ if err != nil {
348
+ return nil , err
349
+ }
350
+ crdGroup , _ , err := unstructured .NestedString (crd .Object , "spec" , "group" )
351
+ if err != nil {
352
+ return nil , err
353
+ }
354
+
355
+ if crd .GetKind () != "CustomResourceDefinition" || crdKind == "" || crdGroup == "" {
313
356
continue
314
357
}
315
358
crds = append (crds , crd )
0 commit comments