@@ -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
)
@@ -102,38 +107,38 @@ func TestLazyRestMapperProvider(t *testing.T) {
102
107
// There are no requests before any call
103
108
g .Expect (crt .GetRequestCount ()).To (gmg .Equal (0 ))
104
109
105
- mapping , err := lazyRestMapper .RESTMapping (schema.GroupKind {Group : "apps" , Kind : "deployment" })
110
+ mapping , err := lazyRestMapper .RESTMapping (schema.GroupKind {Group : "apps" , Kind : "deployment" }, "v1" )
106
111
g .Expect (err ).NotTo (gmg .HaveOccurred ())
107
112
g .Expect (mapping .GroupVersionKind .Kind ).To (gmg .Equal ("deployment" ))
108
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (3 ))
113
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (1 ))
109
114
110
- mappings , err := lazyRestMapper .RESTMappings (schema.GroupKind {Group : "" , Kind : "pod" })
115
+ mappings , err := lazyRestMapper .RESTMappings (schema.GroupKind {Group : "" , Kind : "pod" }, "v1" )
111
116
g .Expect (err ).NotTo (gmg .HaveOccurred ())
112
117
g .Expect (len (mappings )).To (gmg .Equal (1 ))
113
118
g .Expect (mappings [0 ].GroupVersionKind .Kind ).To (gmg .Equal ("pod" ))
114
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (4 ))
119
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (2 ))
115
120
116
121
kind , err := lazyRestMapper .KindFor (schema.GroupVersionResource {Group : "networking.k8s.io" , Version : "v1" , Resource : "ingresses" })
117
122
g .Expect (err ).NotTo (gmg .HaveOccurred ())
118
123
g .Expect (kind .Kind ).To (gmg .Equal ("Ingress" ))
119
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (5 ))
124
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (3 ))
120
125
121
126
kinds , err := lazyRestMapper .KindsFor (schema.GroupVersionResource {Group : "authentication.k8s.io" , Version : "v1" , Resource : "tokenreviews" })
122
127
g .Expect (err ).NotTo (gmg .HaveOccurred ())
123
128
g .Expect (len (kinds )).To (gmg .Equal (1 ))
124
129
g .Expect (kinds [0 ].Kind ).To (gmg .Equal ("TokenReview" ))
125
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (6 ))
130
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (4 ))
126
131
127
132
resource , err := lazyRestMapper .ResourceFor (schema.GroupVersionResource {Group : "scheduling.k8s.io" , Version : "v1" , Resource : "priorityclasses" })
128
133
g .Expect (err ).NotTo (gmg .HaveOccurred ())
129
134
g .Expect (resource .Resource ).To (gmg .Equal ("priorityclasses" ))
130
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (7 ))
135
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (5 ))
131
136
132
137
resources , err := lazyRestMapper .ResourcesFor (schema.GroupVersionResource {Group : "policy" , Version : "v1" , Resource : "poddisruptionbudgets" })
133
138
g .Expect (err ).NotTo (gmg .HaveOccurred ())
134
139
g .Expect (len (resources )).To (gmg .Equal (1 ))
135
140
g .Expect (resources [0 ].Resource ).To (gmg .Equal ("poddisruptionbudgets" ))
136
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (8 ))
141
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (6 ))
137
142
})
138
143
139
144
t .Run ("LazyRESTMapper should cache fetched data and doesn't perform any additional requests" , func (t * testing.T ) {
@@ -344,29 +349,29 @@ func TestLazyRestMapperProvider(t *testing.T) {
344
349
lazyRestMapper , err := apiutil .NewDynamicRESTMapper (restCfg , apiutil .WithExperimentalLazyMapper )
345
350
g .Expect (err ).NotTo (gmg .HaveOccurred ())
346
351
347
- _ , err = lazyRestMapper .RESTMapping (schema.GroupKind {Group : "apps" , Kind : "INVALID" })
352
+ _ , err = lazyRestMapper .RESTMapping (schema.GroupKind {Group : "apps" , Kind : "INVALID" }, "v1" )
348
353
g .Expect (err ).To (gmg .HaveOccurred ())
349
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (3 ))
354
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (1 ))
350
355
351
- _ , err = lazyRestMapper .RESTMappings (schema.GroupKind {Group : "" , Kind : "INVALID" })
356
+ _ , err = lazyRestMapper .RESTMappings (schema.GroupKind {Group : "" , Kind : "INVALID" }, "v1" )
352
357
g .Expect (err ).To (gmg .HaveOccurred ())
353
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (4 ))
358
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (2 ))
354
359
355
360
_ , err = lazyRestMapper .KindFor (schema.GroupVersionResource {Group : "networking.k8s.io" , Version : "v1" , Resource : "INVALID" })
356
361
g .Expect (err ).To (gmg .HaveOccurred ())
357
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (5 ))
362
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (3 ))
358
363
359
364
_ , err = lazyRestMapper .KindsFor (schema.GroupVersionResource {Group : "authentication.k8s.io" , Version : "v1" , Resource : "INVALID" })
360
365
g .Expect (err ).To (gmg .HaveOccurred ())
361
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (6 ))
366
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (4 ))
362
367
363
368
_ , err = lazyRestMapper .ResourceFor (schema.GroupVersionResource {Group : "scheduling.k8s.io" , Version : "v1" , Resource : "INVALID" })
364
369
g .Expect (err ).To (gmg .HaveOccurred ())
365
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (7 ))
370
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (5 ))
366
371
367
372
_ , err = lazyRestMapper .ResourcesFor (schema.GroupVersionResource {Group : "policy" , Version : "v1" , Resource : "INVALID" })
368
373
g .Expect (err ).To (gmg .HaveOccurred ())
369
- g .Expect (crt .GetRequestCount ()).To (gmg .Equal (8 ))
374
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (6 ))
370
375
})
371
376
372
377
t .Run ("LazyRESTMapper should return an error if the version doesn't exist" , func (t * testing.T ) {
@@ -407,4 +412,87 @@ func TestLazyRestMapperProvider(t *testing.T) {
407
412
g .Expect (err ).To (gmg .HaveOccurred ())
408
413
g .Expect (crt .GetRequestCount ()).To (gmg .Equal (6 ))
409
414
})
415
+
416
+ t .Run ("LazyRESTMapper can fetch CRDs if they were created at runtime" , func (t * testing.T ) {
417
+ g := gmg .NewWithT (t )
418
+
419
+ // To fetch all versions mapper does 2 requests:
420
+ // GET https://host/api
421
+ // GET https://host/apis
422
+ // Then, for each version it performs just one request to the API server as usual:
423
+ // GET https://host/apis/<group>/<version>
424
+
425
+ // Note: We have to use a separate restCfg for the Client, otherwise we
426
+ // get a race condition on the counting round tripper between the Client
427
+ // and the lazy restmapper.
428
+ clientRestCfg := rest .CopyConfig (restCfg )
429
+
430
+ var crt * countingRoundTripper
431
+ restCfg := rest .CopyConfig (restCfg )
432
+ restCfg .WrapTransport = func (rt http.RoundTripper ) http.RoundTripper {
433
+ crt = newCountingRoundTripper (rt )
434
+ return crt
435
+ }
436
+
437
+ lazyRestMapper , err := apiutil .NewDynamicRESTMapper (restCfg , apiutil .WithExperimentalLazyMapper )
438
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
439
+
440
+ // There are no requests before any call
441
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (0 ))
442
+
443
+ // Since we don't specify what version we expect, restmapper will fetch them all and search there.
444
+ // To fetch a list of available versions
445
+ // #1: GET https://host/api
446
+ // #2: GET https://host/apis
447
+ // Then, for each currently registered version:
448
+ // #3: GET https://host/apis/crew.example.com/v1
449
+ // #4: GET https://host/apis/crew.example.com/v2
450
+ mapping , err := lazyRestMapper .RESTMapping (schema.GroupKind {Group : "crew.example.com" , Kind : "driver" })
451
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
452
+ g .Expect (mapping .GroupVersionKind .Kind ).To (gmg .Equal ("driver" ))
453
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (4 ))
454
+
455
+ s := scheme .Scheme
456
+ err = apiextensionsv1 .AddToScheme (s )
457
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
458
+
459
+ c , err := client .New (clientRestCfg , client.Options {Scheme : s })
460
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
461
+
462
+ // Register another CRD in runtime - "riders.crew.example.com".
463
+
464
+ crd := & apiextensionsv1.CustomResourceDefinition {}
465
+ err = c .Get (context .TODO (), types.NamespacedName {Name : "drivers.crew.example.com" }, crd )
466
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
467
+ g .Expect (crd .Spec .Names .Kind ).To (gmg .Equal ("Driver" ))
468
+
469
+ newCRD := & apiextensionsv1.CustomResourceDefinition {}
470
+ crd .DeepCopyInto (newCRD )
471
+ newCRD .Name = "riders.crew.example.com"
472
+ newCRD .Spec .Names = apiextensionsv1.CustomResourceDefinitionNames {
473
+ Kind : "Rider" ,
474
+ Plural : "riders" ,
475
+ }
476
+ newCRD .ResourceVersion = ""
477
+
478
+ // Create the new CRD.
479
+ g .Expect (c .Create (context .TODO (), newCRD )).To (gmg .Succeed ())
480
+
481
+ // Wait a bit until the CRD is registered.
482
+ g .Eventually (func () error {
483
+ _ , err := lazyRestMapper .RESTMapping (schema.GroupKind {Group : "crew.example.com" , Kind : "rider" })
484
+ return err
485
+ }).Should (gmg .Succeed ())
486
+
487
+ // Since we don't specify what version we expect, restmapper will fetch them all and search there.
488
+ // To fetch a list of available versions
489
+ // #1: GET https://host/api
490
+ // #2: GET https://host/apis
491
+ // Then, for each currently registered version:
492
+ // #3: GET https://host/apis/crew.example.com/v1
493
+ // #4: GET https://host/apis/crew.example.com/v2
494
+ mapping , err = lazyRestMapper .RESTMapping (schema.GroupKind {Group : "crew.example.com" , Kind : "rider" })
495
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
496
+ g .Expect (mapping .GroupVersionKind .Kind ).To (gmg .Equal ("rider" ))
497
+ })
410
498
}
0 commit comments