@@ -17,14 +17,19 @@ limitations under the License.
17
17
package apiutil_test
18
18
19
19
import (
20
+ "context"
20
21
"net/http"
21
22
"testing"
22
23
23
24
_ "github.com/onsi/ginkgo/v2"
24
25
gmg "github.com/onsi/gomega"
25
26
27
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
26
28
"k8s.io/apimachinery/pkg/runtime/schema"
29
+ "k8s.io/apimachinery/pkg/types"
30
+ "k8s.io/client-go/kubernetes/scheme"
27
31
"k8s.io/client-go/rest"
32
+ "sigs.k8s.io/controller-runtime/pkg/client"
28
33
"sigs.k8s.io/controller-runtime/pkg/client/apiutil"
29
34
"sigs.k8s.io/controller-runtime/pkg/envtest"
30
35
)
@@ -83,10 +88,7 @@ func TestLazyRestMapperProvider(t *testing.T) {
83
88
t .Run ("LazyRESTMapper should fetch data based on the request" , func (t * testing.T ) {
84
89
g := gmg .NewWithT (t )
85
90
86
- // To initialize mapper does 2 requests:
87
- // GET https://host/api
88
- // GET https://host/apis
89
- // Then, for each new group it performs just one request to the API server:
91
+ // For each new group it performs just one request to the API server:
90
92
// GET https://host/apis/<group>/<version>
91
93
92
94
httpClient , err := rest .HTTPClientFor (restCfg )
@@ -101,38 +103,38 @@ func TestLazyRestMapperProvider(t *testing.T) {
101
103
// There are no requests before any call
102
104
g .Expect (crt .GetRequestCount ()).To (gmg .Equal (0 ))
103
105
104
- mapping , err := lazyRestMapper .RESTMapping (schema.GroupKind {Group : "apps" , Kind : "deployment" })
106
+ mapping , err := lazyRestMapper .RESTMapping (schema.GroupKind {Group : "apps" , Kind : "deployment" }, "v1" )
105
107
g .Expect (err ).NotTo (gmg .HaveOccurred ())
106
108
g .Expect (mapping .GroupVersionKind .Kind ).To (gmg .Equal ("deployment" ))
107
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (3 ))
109
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (1 ))
108
110
109
- mappings , err := lazyRestMapper .RESTMappings (schema.GroupKind {Group : "" , Kind : "pod" })
111
+ mappings , err := lazyRestMapper .RESTMappings (schema.GroupKind {Group : "" , Kind : "pod" }, "v1" )
110
112
g .Expect (err ).NotTo (gmg .HaveOccurred ())
111
113
g .Expect (len (mappings )).To (gmg .Equal (1 ))
112
114
g .Expect (mappings [0 ].GroupVersionKind .Kind ).To (gmg .Equal ("pod" ))
113
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (4 ))
115
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (2 ))
114
116
115
117
kind , err := lazyRestMapper .KindFor (schema.GroupVersionResource {Group : "networking.k8s.io" , Version : "v1" , Resource : "ingresses" })
116
118
g .Expect (err ).NotTo (gmg .HaveOccurred ())
117
119
g .Expect (kind .Kind ).To (gmg .Equal ("Ingress" ))
118
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (5 ))
120
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (3 ))
119
121
120
122
kinds , err := lazyRestMapper .KindsFor (schema.GroupVersionResource {Group : "authentication.k8s.io" , Version : "v1" , Resource : "tokenreviews" })
121
123
g .Expect (err ).NotTo (gmg .HaveOccurred ())
122
124
g .Expect (len (kinds )).To (gmg .Equal (1 ))
123
125
g .Expect (kinds [0 ].Kind ).To (gmg .Equal ("TokenReview" ))
124
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (6 ))
126
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (4 ))
125
127
126
128
resource , err := lazyRestMapper .ResourceFor (schema.GroupVersionResource {Group : "scheduling.k8s.io" , Version : "v1" , Resource : "priorityclasses" })
127
129
g .Expect (err ).NotTo (gmg .HaveOccurred ())
128
130
g .Expect (resource .Resource ).To (gmg .Equal ("priorityclasses" ))
129
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (7 ))
131
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (5 ))
130
132
131
133
resources , err := lazyRestMapper .ResourcesFor (schema.GroupVersionResource {Group : "policy" , Version : "v1" , Resource : "poddisruptionbudgets" })
132
134
g .Expect (err ).NotTo (gmg .HaveOccurred ())
133
135
g .Expect (len (resources )).To (gmg .Equal (1 ))
134
136
g .Expect (resources [0 ].Resource ).To (gmg .Equal ("poddisruptionbudgets" ))
135
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (8 ))
137
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (6 ))
136
138
})
137
139
138
140
t .Run ("LazyRESTMapper should cache fetched data and doesn't perform any additional requests" , func (t * testing.T ) {
@@ -327,7 +329,7 @@ func TestLazyRestMapperProvider(t *testing.T) {
327
329
t .Run ("LazyRESTMapper should return an error if a resource doesn't exist" , func (t * testing.T ) {
328
330
g := gmg .NewWithT (t )
329
331
330
- // After initialization for each invalid resource the mapper performs just 1 request to the API server.
332
+ // For each invalid resource the mapper performs just 1 request to the API server.
331
333
332
334
httpClient , err := rest .HTTPClientFor (restCfg )
333
335
g .Expect (err ).NotTo (gmg .HaveOccurred ())
@@ -338,29 +340,29 @@ func TestLazyRestMapperProvider(t *testing.T) {
338
340
lazyRestMapper , err := apiutil .NewDynamicRESTMapper (restCfg , httpClient , apiutil .WithExperimentalLazyMapper )
339
341
g .Expect (err ).NotTo (gmg .HaveOccurred ())
340
342
341
- _ , err = lazyRestMapper .RESTMapping (schema.GroupKind {Group : "apps" , Kind : "INVALID" })
343
+ _ , err = lazyRestMapper .RESTMapping (schema.GroupKind {Group : "apps" , Kind : "INVALID" }, "v1" )
342
344
g .Expect (err ).To (gmg .HaveOccurred ())
343
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (3 ))
345
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (1 ))
344
346
345
- _ , err = lazyRestMapper .RESTMappings (schema.GroupKind {Group : "" , Kind : "INVALID" })
347
+ _ , err = lazyRestMapper .RESTMappings (schema.GroupKind {Group : "" , Kind : "INVALID" }, "v1" )
346
348
g .Expect (err ).To (gmg .HaveOccurred ())
347
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (4 ))
349
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (2 ))
348
350
349
351
_ , err = lazyRestMapper .KindFor (schema.GroupVersionResource {Group : "networking.k8s.io" , Version : "v1" , Resource : "INVALID" })
350
352
g .Expect (err ).To (gmg .HaveOccurred ())
351
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (5 ))
353
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (3 ))
352
354
353
355
_ , err = lazyRestMapper .KindsFor (schema.GroupVersionResource {Group : "authentication.k8s.io" , Version : "v1" , Resource : "INVALID" })
354
356
g .Expect (err ).To (gmg .HaveOccurred ())
355
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (6 ))
357
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (4 ))
356
358
357
359
_ , err = lazyRestMapper .ResourceFor (schema.GroupVersionResource {Group : "scheduling.k8s.io" , Version : "v1" , Resource : "INVALID" })
358
360
g .Expect (err ).To (gmg .HaveOccurred ())
359
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (7 ))
361
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (5 ))
360
362
361
363
_ , err = lazyRestMapper .ResourcesFor (schema.GroupVersionResource {Group : "policy" , Version : "v1" , Resource : "INVALID" })
362
364
g .Expect (err ).To (gmg .HaveOccurred ())
363
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (8 ))
365
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (6 ))
364
366
})
365
367
366
368
t .Run ("LazyRESTMapper should return an error if the version doesn't exist" , func (t * testing.T ) {
@@ -401,4 +403,81 @@ func TestLazyRestMapperProvider(t *testing.T) {
401
403
g .Expect (err ).To (gmg .HaveOccurred ())
402
404
g .Expect (crt .GetRequestCount ()).To (gmg .Equal (6 ))
403
405
})
406
+
407
+ t .Run ("LazyRESTMapper can fetch CRDs if they were created at runtime" , func (t * testing.T ) {
408
+ g := gmg .NewWithT (t )
409
+
410
+ // To fetch all versions mapper does 2 requests:
411
+ // GET https://host/api
412
+ // GET https://host/apis
413
+ // Then, for each version it performs just one request to the API server as usual:
414
+ // GET https://host/apis/<group>/<version>
415
+
416
+ httpClient , err := rest .HTTPClientFor (restCfg )
417
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
418
+
419
+ crt := newCountingRoundTripper (httpClient .Transport )
420
+ httpClient .Transport = crt
421
+
422
+ lazyRestMapper , err := apiutil .NewDynamicRESTMapper (restCfg , httpClient , apiutil .WithExperimentalLazyMapper )
423
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
424
+
425
+ // There are no requests before any call
426
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (0 ))
427
+
428
+ // Since we don't specify what version we expect, restmapper will fetch them all and search there.
429
+ // To fetch a list of available versions
430
+ // #1: GET https://host/api
431
+ // #2: GET https://host/apis
432
+ // Then, for each currently registered version:
433
+ // #3: GET https://host/apis/crew.example.com/v1
434
+ // #4: GET https://host/apis/crew.example.com/v2
435
+ mapping , err := lazyRestMapper .RESTMapping (schema.GroupKind {Group : "crew.example.com" , Kind : "driver" })
436
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
437
+ g .Expect (mapping .GroupVersionKind .Kind ).To (gmg .Equal ("driver" ))
438
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (4 ))
439
+
440
+ s := scheme .Scheme
441
+ err = apiextensionsv1 .AddToScheme (s )
442
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
443
+
444
+ c , err := client .New (restCfg , client.Options {Scheme : s })
445
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
446
+
447
+ // Register another CRD in runtime - "riders.crew.example.com".
448
+
449
+ crd := & apiextensionsv1.CustomResourceDefinition {}
450
+ err = c .Get (context .TODO (), types.NamespacedName {Name : "drivers.crew.example.com" }, crd )
451
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
452
+ g .Expect (crd .Spec .Names .Kind ).To (gmg .Equal ("Driver" ))
453
+
454
+ newCRD := & apiextensionsv1.CustomResourceDefinition {}
455
+ crd .DeepCopyInto (newCRD )
456
+ newCRD .Name = "riders.crew.example.com"
457
+ newCRD .Spec .Names = apiextensionsv1.CustomResourceDefinitionNames {
458
+ Kind : "Rider" ,
459
+ Plural : "riders" ,
460
+ }
461
+ newCRD .ResourceVersion = ""
462
+
463
+ // Create the new CRD.
464
+ g .Expect (c .Create (context .TODO (), newCRD )).To (gmg .Succeed ())
465
+
466
+ // Wait a bit until the CRD is registered.
467
+ g .Eventually (func () error {
468
+ _ , err := lazyRestMapper .RESTMapping (schema.GroupKind {Group : "crew.example.com" , Kind : "rider" })
469
+ return err
470
+ }).Should (gmg .Succeed ())
471
+
472
+ // Since we don't specify what version we expect, restmapper will fetch them all and search there.
473
+ // To fetch a list of available versions
474
+ // #1: GET https://host/api
475
+ // #2: GET https://host/apis
476
+ // Then, for each currently registered version:
477
+ // #3: GET https://host/apis/crew.example.com/v1
478
+ // #4: GET https://host/apis/crew.example.com/v2
479
+ mapping , err = lazyRestMapper .RESTMapping (schema.GroupKind {Group : "crew.example.com" , Kind : "rider" })
480
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
481
+ g .Expect (mapping .GroupVersionKind .Kind ).To (gmg .Equal ("rider" ))
482
+ })
404
483
}
0 commit comments