@@ -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,82 @@ 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
+ var crt * countingRoundTripper
426
+ restCfg := rest .CopyConfig (restCfg )
427
+ restCfg .WrapTransport = func (rt http.RoundTripper ) http.RoundTripper {
428
+ crt = newCountingRoundTripper (rt )
429
+ return crt
430
+ }
431
+
432
+ lazyRestMapper , err := apiutil .NewDynamicRESTMapper (restCfg , apiutil .WithExperimentalLazyMapper )
433
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
434
+
435
+ // There are no requests before any call
436
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (0 ))
437
+
438
+ // Since we don't specify what version we expect, restmapper will fetch them all and search there.
439
+ // To fetch a list of available versions
440
+ // #1: GET https://host/api
441
+ // #2: GET https://host/apis
442
+ // Then, for each currently registered version:
443
+ // #3: GET https://host/apis/crew.example.com/v1
444
+ // #4: GET https://host/apis/crew.example.com/v2
445
+ mapping , err := lazyRestMapper .RESTMapping (schema.GroupKind {Group : "crew.example.com" , Kind : "driver" })
446
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
447
+ g .Expect (mapping .GroupVersionKind .Kind ).To (gmg .Equal ("driver" ))
448
+ g .Expect (crt .GetRequestCount ()).To (gmg .Equal (4 ))
449
+
450
+ s := scheme .Scheme
451
+ err = apiextensionsv1 .AddToScheme (s )
452
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
453
+
454
+ c , err := client .New (restCfg , client.Options {Scheme : s })
455
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
456
+
457
+ // Register another CRD in runtime - "riders.crew.example.com".
458
+
459
+ crd := & apiextensionsv1.CustomResourceDefinition {}
460
+ err = c .Get (context .TODO (), types.NamespacedName {Name : "drivers.crew.example.com" }, crd )
461
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
462
+ g .Expect (crd .Spec .Names .Kind ).To (gmg .Equal ("Driver" ))
463
+
464
+ newCRD := & apiextensionsv1.CustomResourceDefinition {}
465
+ crd .DeepCopyInto (newCRD )
466
+ newCRD .Name = "riders.crew.example.com"
467
+ newCRD .Spec .Names = apiextensionsv1.CustomResourceDefinitionNames {
468
+ Kind : "Rider" ,
469
+ Plural : "riders" ,
470
+ }
471
+ newCRD .ResourceVersion = ""
472
+
473
+ // Create the new CRD.
474
+ g .Expect (c .Create (context .TODO (), newCRD )).To (gmg .Succeed ())
475
+
476
+ // Wait a bit until the CRD is registered.
477
+ g .Eventually (func () error {
478
+ _ , err := lazyRestMapper .RESTMapping (schema.GroupKind {Group : "crew.example.com" , Kind : "rider" })
479
+ return err
480
+ }).Should (gmg .Succeed ())
481
+
482
+ // Since we don't specify what version we expect, restmapper will fetch them all and search there.
483
+ // To fetch a list of available versions
484
+ // #1: GET https://host/api
485
+ // #2: GET https://host/apis
486
+ // Then, for each currently registered version:
487
+ // #3: GET https://host/apis/crew.example.com/v1
488
+ // #4: GET https://host/apis/crew.example.com/v2
489
+ mapping , err = lazyRestMapper .RESTMapping (schema.GroupKind {Group : "crew.example.com" , Kind : "rider" })
490
+ g .Expect (err ).NotTo (gmg .HaveOccurred ())
491
+ g .Expect (mapping .GroupVersionKind .Kind ).To (gmg .Equal ("rider" ))
492
+ })
410
493
}
0 commit comments