1
16
17 package disk
18
19 import (
20 "encoding/json"
21 "net/http"
22 "net/http/httptest"
23 "os"
24 "path/filepath"
25 "strings"
26 "testing"
27 "time"
28
29 openapi_v2 "github.com/google/gnostic-models/openapiv2"
30 "github.com/stretchr/testify/assert"
31 "github.com/stretchr/testify/require"
32
33 apidiscovery "k8s.io/api/apidiscovery/v2"
34 "k8s.io/apimachinery/pkg/api/errors"
35 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
36 "k8s.io/apimachinery/pkg/runtime"
37 "k8s.io/apimachinery/pkg/runtime/schema"
38 "k8s.io/apimachinery/pkg/util/sets"
39 "k8s.io/apimachinery/pkg/version"
40 "k8s.io/client-go/discovery"
41 "k8s.io/client-go/openapi"
42 restclient "k8s.io/client-go/rest"
43 "k8s.io/client-go/rest/fake"
44 testutil "k8s.io/client-go/util/testing"
45 )
46
47 func TestCachedDiscoveryClient_Fresh(t *testing.T) {
48 assert := assert.New(t)
49
50 d, err := os.MkdirTemp("", "")
51 assert.NoError(err)
52 defer os.RemoveAll(d)
53
54 c := fakeDiscoveryClient{}
55 cdc := newCachedDiscoveryClient(&c, d, 60*time.Second)
56 assert.True(cdc.Fresh(), "should be fresh after creation")
57
58 cdc.ServerGroups()
59 assert.True(cdc.Fresh(), "should be fresh after groups call without cache")
60 assert.Equal(c.groupCalls, 1)
61
62 cdc.ServerGroups()
63 assert.True(cdc.Fresh(), "should be fresh after another groups call")
64 assert.Equal(c.groupCalls, 1)
65
66 cdc.ServerGroupsAndResources()
67 assert.True(cdc.Fresh(), "should be fresh after resources call")
68 assert.Equal(c.resourceCalls, 1)
69
70 cdc.ServerGroupsAndResources()
71 assert.True(cdc.Fresh(), "should be fresh after another resources call")
72 assert.Equal(c.resourceCalls, 1)
73
74 cdc = newCachedDiscoveryClient(&c, d, 60*time.Second)
75 cdc.ServerGroups()
76 assert.False(cdc.Fresh(), "should NOT be fresh after recreation with existing groups cache")
77 assert.Equal(c.groupCalls, 1)
78
79 cdc.ServerGroupsAndResources()
80 assert.False(cdc.Fresh(), "should NOT be fresh after recreation with existing resources cache")
81 assert.Equal(c.resourceCalls, 1)
82
83 cdc.Invalidate()
84 assert.True(cdc.Fresh(), "should be fresh after cache invalidation")
85
86 cdc.ServerGroupsAndResources()
87 assert.True(cdc.Fresh(), "should ignore existing resources cache after invalidation")
88 assert.Equal(c.resourceCalls, 2)
89 }
90
91 func TestNewCachedDiscoveryClient_TTL(t *testing.T) {
92 assert := assert.New(t)
93
94 d, err := os.MkdirTemp("", "")
95 assert.NoError(err)
96 defer os.RemoveAll(d)
97
98 c := fakeDiscoveryClient{}
99 cdc := newCachedDiscoveryClient(&c, d, 1*time.Nanosecond)
100 cdc.ServerGroups()
101 assert.Equal(c.groupCalls, 1)
102
103 time.Sleep(1 * time.Second)
104
105 cdc.ServerGroups()
106 assert.Equal(c.groupCalls, 2)
107 }
108
109 func TestNewCachedDiscoveryClient_PathPerm(t *testing.T) {
110 assert := assert.New(t)
111
112 d, err := os.MkdirTemp("", "")
113 assert.NoError(err)
114 os.RemoveAll(d)
115 defer os.RemoveAll(d)
116
117 c := fakeDiscoveryClient{}
118 cdc := newCachedDiscoveryClient(&c, d, 1*time.Nanosecond)
119 cdc.ServerGroups()
120
121 err = filepath.Walk(d, func(path string, info os.FileInfo, err error) error {
122 if err != nil {
123 return err
124 }
125 if info.IsDir() {
126 assert.Equal(os.FileMode(0750), info.Mode().Perm())
127 } else {
128 assert.Equal(os.FileMode(0660), info.Mode().Perm())
129 }
130 return nil
131 })
132 assert.NoError(err)
133 }
134
135
136
137 func TestOpenAPIDiskCache(t *testing.T) {
138
139 discoCache, err := os.MkdirTemp("", "test-cached-discovery-client-disco-*")
140 require.NoError(t, err)
141 os.RemoveAll(discoCache)
142 defer os.RemoveAll(discoCache)
143
144
145 httpCache, err := os.MkdirTemp("", "test-cached-discovery-client-http-*")
146 require.NoError(t, err)
147 os.RemoveAll(httpCache)
148 defer os.RemoveAll(httpCache)
149
150
151 fakeServer, err := testutil.NewFakeOpenAPIV3Server("../../testdata")
152 require.NoError(t, err)
153 defer fakeServer.HttpServer.Close()
154
155 require.Greater(t, len(fakeServer.ServedDocuments), 0)
156
157 client, err := NewCachedDiscoveryClientForConfig(
158 &restclient.Config{Host: fakeServer.HttpServer.URL},
159 discoCache,
160 httpCache,
161 1*time.Nanosecond,
162 )
163 require.NoError(t, err)
164
165 openapiClient := client.OpenAPIV3()
166
167
168 _, err = openapiClient.Paths()
169 require.NoError(t, err)
170 assert.Equal(t, 1, fakeServer.RequestCounters["/openapi/v3"])
171
172
173
174
175 paths, err := openapiClient.Paths()
176 require.NoError(t, err)
177 assert.Equal(t, 1, fakeServer.RequestCounters["/openapi/v3"])
178 require.Greater(t, len(paths), 0)
179
180 contentTypes := []string{
181 runtime.ContentTypeJSON, openapi.ContentTypeOpenAPIV3PB,
182 }
183
184 for _, contentType := range contentTypes {
185 t.Run(contentType, func(t *testing.T) {
186
187 for k := range fakeServer.RequestCounters {
188 delete(fakeServer.RequestCounters, k)
189 }
190
191 i := 0
192 for k, v := range paths {
193 i++
194
195 _, err = v.Schema(contentType)
196 assert.NoError(t, err)
197
198 path := "/openapi/v3/" + strings.TrimPrefix(k, "/")
199 assert.Equal(t, 1, fakeServer.RequestCounters[path])
200
201
202 _, err = v.Schema(contentType)
203 assert.NoError(t, err)
204 assert.Equal(t, 1, fakeServer.RequestCounters[path])
205
206 client.Invalidate()
207
208
209
210 newPaths, err := client.OpenAPIV3().Paths()
211 if !assert.NoError(t, err) {
212 continue
213 }
214
215
216 _, err = newPaths[k].Schema(contentType)
217 assert.NoError(t, err)
218 assert.Equal(t, 1, fakeServer.RequestCounters[path])
219 }
220 })
221 }
222
223 }
224
225
226 func TestCachedDiscoveryClientUnaggregatedServerGroups(t *testing.T) {
227 tests := []struct {
228 name string
229 corev1 *metav1.APIVersions
230 apis *metav1.APIGroupList
231 expectedGroupNames []string
232 expectedGroupVersions []string
233 }{
234 {
235 name: "Legacy discovery format: 1 version at /api, 1 group at /apis",
236 corev1: &metav1.APIVersions{
237 Versions: []string{
238 "v1",
239 },
240 },
241 apis: &metav1.APIGroupList{
242 Groups: []metav1.APIGroup{
243 {
244 Name: "extensions",
245 Versions: []metav1.GroupVersionForDiscovery{
246 {GroupVersion: "extensions/v1beta1"},
247 },
248 },
249 },
250 },
251 expectedGroupNames: []string{"", "extensions"},
252 expectedGroupVersions: []string{"v1", "extensions/v1beta1"},
253 },
254 {
255 name: "Legacy discovery format: 1 version at /api, 2 groups/1 version at /apis",
256 corev1: &metav1.APIVersions{
257 Versions: []string{
258 "v1",
259 },
260 },
261 apis: &metav1.APIGroupList{
262 Groups: []metav1.APIGroup{
263 {
264 Name: "apps",
265 Versions: []metav1.GroupVersionForDiscovery{
266 {GroupVersion: "apps/v1"},
267 },
268 },
269 {
270 Name: "extensions",
271 Versions: []metav1.GroupVersionForDiscovery{
272 {GroupVersion: "extensions/v1beta1"},
273 },
274 },
275 },
276 },
277 expectedGroupNames: []string{"", "apps", "extensions"},
278 expectedGroupVersions: []string{"v1", "apps/v1", "extensions/v1beta1"},
279 },
280 {
281 name: "Legacy discovery format: 1 version at /api, 2 groups/2 versions at /apis",
282 corev1: &metav1.APIVersions{
283 Versions: []string{
284 "v1",
285 },
286 },
287 apis: &metav1.APIGroupList{
288 Groups: []metav1.APIGroup{
289 {
290 Name: "batch",
291 Versions: []metav1.GroupVersionForDiscovery{
292 {GroupVersion: "batch/v1"},
293 },
294 },
295 {
296 Name: "batch",
297 Versions: []metav1.GroupVersionForDiscovery{
298 {GroupVersion: "batch/v1beta1"},
299 },
300 },
301 {
302 Name: "extensions",
303 Versions: []metav1.GroupVersionForDiscovery{
304 {GroupVersion: "extensions/v1beta1"},
305 },
306 },
307 {
308 Name: "extensions",
309 Versions: []metav1.GroupVersionForDiscovery{
310 {GroupVersion: "extensions/v1alpha1"},
311 },
312 },
313 },
314 },
315 expectedGroupNames: []string{
316 "",
317 "batch",
318 "extensions",
319 },
320 expectedGroupVersions: []string{
321 "v1",
322 "batch/v1",
323 "batch/v1beta1",
324 "extensions/v1beta1",
325 "extensions/v1alpha1",
326 },
327 },
328 }
329
330 for _, test := range tests {
331
332 discoCache, err := os.MkdirTemp("", "test-cached-discovery-client-disco-*")
333 require.NoError(t, err)
334 os.RemoveAll(discoCache)
335 defer os.RemoveAll(discoCache)
336
337 httpCache, err := os.MkdirTemp("", "test-cached-discovery-client-http-*")
338 require.NoError(t, err)
339 os.RemoveAll(httpCache)
340 defer os.RemoveAll(httpCache)
341 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
342 var body interface{}
343 switch req.URL.Path {
344 case "/api":
345 body = test.corev1
346 case "/apis":
347 body = test.apis
348 default:
349 w.WriteHeader(http.StatusNotFound)
350 return
351 }
352 output, err := json.Marshal(body)
353 require.NoError(t, err)
354
355 w.Header().Set("Content-Type", discovery.AcceptV1)
356 w.WriteHeader(http.StatusOK)
357 w.Write(output)
358 }))
359 defer server.Close()
360 client, err := NewCachedDiscoveryClientForConfig(
361 &restclient.Config{Host: server.URL},
362 discoCache,
363 httpCache,
364 1*time.Nanosecond,
365 )
366 require.NoError(t, err)
367 apiGroupList, err := client.ServerGroups()
368 require.NoError(t, err)
369
370 numFound, err := numFilesFound(discoCache, "servergroups.json")
371 assert.NoError(t, err)
372 assert.Equal(t, 1, numFound,
373 "%s: expected 1 discovery cache file servergroups.json found, got %d", test.name, numFound)
374
375 expectedGroupNames := sets.NewString(test.expectedGroupNames...)
376 actualGroupNames := sets.NewString(groupNamesFromList(apiGroupList)...)
377 assert.True(t, expectedGroupNames.Equal(actualGroupNames),
378 "%s: Expected groups (%s), got (%s)", test.name, expectedGroupNames.List(), actualGroupNames.List())
379
380 expectedGroupVersions := sets.NewString(test.expectedGroupVersions...)
381 actualGroupVersions := sets.NewString(groupVersionsFromGroups(apiGroupList)...)
382 assert.True(t, expectedGroupVersions.Equal(actualGroupVersions),
383 "%s: Expected group/versions (%s), got (%s)", test.name, expectedGroupVersions.List(), actualGroupVersions.List())
384 }
385 }
386
387
388 func TestCachedDiscoveryClientAggregatedServerGroups(t *testing.T) {
389 tests := []struct {
390 name string
391 corev1 *apidiscovery.APIGroupDiscoveryList
392 apis *apidiscovery.APIGroupDiscoveryList
393 expectedGroupNames []string
394 expectedGroupVersions []string
395 expectedPreferredVersions []string
396 }{
397 {
398 name: "Aggregated cached discovery: 1 group/1 version at /api, 1 group/1 version at /apis",
399 corev1: &apidiscovery.APIGroupDiscoveryList{
400 Items: []apidiscovery.APIGroupDiscovery{
401 {
402 Versions: []apidiscovery.APIVersionDiscovery{
403 {
404 Version: "v1",
405 Resources: []apidiscovery.APIResourceDiscovery{
406 {
407 Resource: "pods",
408 ResponseKind: &metav1.GroupVersionKind{
409 Group: "",
410 Version: "v1",
411 Kind: "Pod",
412 },
413 Scope: apidiscovery.ScopeNamespace,
414 },
415 },
416 },
417 },
418 },
419 },
420 },
421 apis: &apidiscovery.APIGroupDiscoveryList{
422 Items: []apidiscovery.APIGroupDiscovery{
423 {
424 ObjectMeta: metav1.ObjectMeta{
425 Name: "apps",
426 },
427 Versions: []apidiscovery.APIVersionDiscovery{
428 {
429 Version: "v1",
430 Resources: []apidiscovery.APIResourceDiscovery{
431 {
432 Resource: "deployments",
433 ResponseKind: &metav1.GroupVersionKind{
434 Group: "apps",
435 Version: "v1",
436 Kind: "Deployment",
437 },
438 Scope: apidiscovery.ScopeNamespace,
439 },
440 },
441 },
442 },
443 },
444 },
445 },
446 expectedGroupNames: []string{"", "apps"},
447 expectedGroupVersions: []string{"v1", "apps/v1"},
448 expectedPreferredVersions: []string{"v1", "apps/v1"},
449 },
450 {
451 name: "Aggregated discovery: 1 group/1 version at /api, 1 group/2 versions at /apis",
452 corev1: &apidiscovery.APIGroupDiscoveryList{
453 Items: []apidiscovery.APIGroupDiscovery{
454 {
455 ObjectMeta: metav1.ObjectMeta{
456 Name: "",
457 },
458 Versions: []apidiscovery.APIVersionDiscovery{
459 {
460 Version: "v1",
461 Resources: []apidiscovery.APIResourceDiscovery{
462 {
463 Resource: "pods",
464 ResponseKind: &metav1.GroupVersionKind{
465 Group: "",
466 Version: "v1",
467 Kind: "Pod",
468 },
469 Scope: apidiscovery.ScopeNamespace,
470 },
471 },
472 },
473 },
474 },
475 },
476 },
477 apis: &apidiscovery.APIGroupDiscoveryList{
478 Items: []apidiscovery.APIGroupDiscovery{
479 {
480 ObjectMeta: metav1.ObjectMeta{
481 Name: "apps",
482 },
483 Versions: []apidiscovery.APIVersionDiscovery{
484
485 {
486 Version: "v2",
487 Resources: []apidiscovery.APIResourceDiscovery{
488 {
489 Resource: "deployments",
490 ResponseKind: &metav1.GroupVersionKind{
491 Group: "apps",
492 Version: "v2",
493 Kind: "Deployment",
494 },
495 Scope: apidiscovery.ScopeNamespace,
496 },
497 },
498 },
499 {
500 Version: "v1",
501 Resources: []apidiscovery.APIResourceDiscovery{
502 {
503 Resource: "deployments",
504 ResponseKind: &metav1.GroupVersionKind{
505 Group: "apps",
506 Version: "v1",
507 Kind: "Deployment",
508 },
509 Scope: apidiscovery.ScopeNamespace,
510 },
511 },
512 },
513 },
514 },
515 },
516 },
517 expectedGroupNames: []string{"", "apps"},
518 expectedGroupVersions: []string{"v1", "apps/v1", "apps/v2"},
519 expectedPreferredVersions: []string{"v1", "apps/v2"},
520 },
521 {
522 name: "Aggregated discovery: /api returns nothing, 2 groups at /apis",
523 corev1: &apidiscovery.APIGroupDiscoveryList{},
524 apis: &apidiscovery.APIGroupDiscoveryList{
525 Items: []apidiscovery.APIGroupDiscovery{
526 {
527 ObjectMeta: metav1.ObjectMeta{
528 Name: "apps",
529 },
530 Versions: []apidiscovery.APIVersionDiscovery{
531 {
532 Version: "v1",
533 Resources: []apidiscovery.APIResourceDiscovery{
534 {
535 Resource: "deployments",
536 ResponseKind: &metav1.GroupVersionKind{
537 Group: "apps",
538 Version: "v1",
539 Kind: "Deployment",
540 },
541 Scope: apidiscovery.ScopeNamespace,
542 },
543 {
544 Resource: "statefulsets",
545 ResponseKind: &metav1.GroupVersionKind{
546 Group: "apps",
547 Version: "v1",
548 Kind: "StatefulSet",
549 },
550 Scope: apidiscovery.ScopeNamespace,
551 },
552 },
553 },
554 },
555 },
556 {
557 ObjectMeta: metav1.ObjectMeta{
558 Name: "batch",
559 },
560 Versions: []apidiscovery.APIVersionDiscovery{
561
562 {
563 Version: "v1",
564 Resources: []apidiscovery.APIResourceDiscovery{
565 {
566 Resource: "jobs",
567 ResponseKind: &metav1.GroupVersionKind{
568 Group: "batch",
569 Version: "v1",
570 Kind: "Job",
571 },
572 Scope: apidiscovery.ScopeNamespace,
573 },
574 {
575 Resource: "cronjobs",
576 ResponseKind: &metav1.GroupVersionKind{
577 Group: "batch",
578 Version: "v1",
579 Kind: "CronJob",
580 },
581 Scope: apidiscovery.ScopeNamespace,
582 },
583 },
584 },
585 {
586 Version: "v1beta1",
587 Resources: []apidiscovery.APIResourceDiscovery{
588 {
589 Resource: "jobs",
590 ResponseKind: &metav1.GroupVersionKind{
591 Group: "batch",
592 Version: "v1beta1",
593 Kind: "Job",
594 },
595 Scope: apidiscovery.ScopeNamespace,
596 },
597 {
598 Resource: "cronjobs",
599 ResponseKind: &metav1.GroupVersionKind{
600 Group: "batch",
601 Version: "v1beta1",
602 Kind: "CronJob",
603 },
604 Scope: apidiscovery.ScopeNamespace,
605 },
606 },
607 },
608 },
609 },
610 },
611 },
612 expectedGroupNames: []string{"apps", "batch"},
613 expectedGroupVersions: []string{"apps/v1", "batch/v1", "batch/v1beta1"},
614 expectedPreferredVersions: []string{"apps/v1", "batch/v1"},
615 },
616 }
617
618 for _, test := range tests {
619
620 discoCache, err := os.MkdirTemp("", "test-cached-discovery-client-disco-*")
621 require.NoError(t, err)
622 os.RemoveAll(discoCache)
623 defer os.RemoveAll(discoCache)
624
625 httpCache, err := os.MkdirTemp("", "test-cached-discovery-client-http-*")
626 require.NoError(t, err)
627 os.RemoveAll(httpCache)
628 defer os.RemoveAll(httpCache)
629 server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
630 var agg *apidiscovery.APIGroupDiscoveryList
631 switch req.URL.Path {
632 case "/api":
633 agg = test.corev1
634 case "/apis":
635 agg = test.apis
636 default:
637 w.WriteHeader(http.StatusNotFound)
638 return
639 }
640 output, err := json.Marshal(agg)
641 if err != nil {
642 t.Fatalf("unexpected encoding error: %v", err)
643 return
644 }
645
646 w.Header().Set("Content-Type", discovery.AcceptV2)
647 w.WriteHeader(http.StatusOK)
648 w.Write(output)
649 }))
650 defer server.Close()
651 client, err := NewCachedDiscoveryClientForConfig(
652 &restclient.Config{Host: server.URL},
653 discoCache,
654 httpCache,
655 1*time.Nanosecond,
656 )
657 require.NoError(t, err)
658 apiGroupList, err := client.ServerGroups()
659 require.NoError(t, err)
660
661 numFound, err := numFilesFound(discoCache, "servergroups.json")
662 assert.NoError(t, err)
663 assert.Equal(t, 1, numFound,
664 "%s: expected 1 discovery cache file servergroups.json found, got %d", test.name, numFound)
665
666 expectedGroupNames := sets.NewString(test.expectedGroupNames...)
667 actualGroupNames := sets.NewString(groupNamesFromList(apiGroupList)...)
668 assert.True(t, expectedGroupNames.Equal(actualGroupNames),
669 "%s: Expected groups (%s), got (%s)", test.name, expectedGroupNames.List(), actualGroupNames.List())
670
671 expectedGroupVersions := sets.NewString(test.expectedGroupVersions...)
672 actualGroupVersions := sets.NewString(groupVersionsFromGroups(apiGroupList)...)
673 assert.True(t, expectedGroupVersions.Equal(actualGroupVersions),
674 "%s: Expected group/versions (%s), got (%s)", test.name, expectedGroupVersions.List(), actualGroupVersions.List())
675
676 expectedPreferredVersions := sets.NewString(test.expectedPreferredVersions...)
677 actualPreferredVersions := sets.NewString(preferredVersionsFromList(apiGroupList)...)
678 assert.True(t, expectedPreferredVersions.Equal(actualPreferredVersions),
679 "%s: Expected preferred group/version (%s), got (%s)", test.name, expectedPreferredVersions.List(), actualPreferredVersions.List())
680 }
681 }
682
683 func numFilesFound(dir string, filename string) (int, error) {
684 numFound := 0
685 err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
686 if err != nil {
687 return err
688 }
689 if info.Name() == filename {
690 numFound++
691 }
692 return nil
693 })
694 if err != nil {
695 return 0, err
696 }
697 return numFound, nil
698 }
699
700 type fakeDiscoveryClient struct {
701 groupCalls int
702 resourceCalls int
703 versionCalls int
704 openAPICalls int
705
706 serverResourcesHandler func() ([]*metav1.APIResourceList, error)
707 }
708
709 var _ discovery.DiscoveryInterface = &fakeDiscoveryClient{}
710
711 func (c *fakeDiscoveryClient) RESTClient() restclient.Interface {
712 return &fake.RESTClient{}
713 }
714
715 func (c *fakeDiscoveryClient) ServerGroups() (*metav1.APIGroupList, error) {
716 c.groupCalls = c.groupCalls + 1
717 return c.serverGroups()
718 }
719
720 func (c *fakeDiscoveryClient) serverGroups() (*metav1.APIGroupList, error) {
721 return &metav1.APIGroupList{
722 Groups: []metav1.APIGroup{
723 {
724 Name: "a",
725 Versions: []metav1.GroupVersionForDiscovery{
726 {
727 GroupVersion: "a/v1",
728 Version: "v1",
729 },
730 },
731 PreferredVersion: metav1.GroupVersionForDiscovery{
732 GroupVersion: "a/v1",
733 Version: "v1",
734 },
735 },
736 },
737 }, nil
738 }
739
740 func (c *fakeDiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) {
741 c.resourceCalls = c.resourceCalls + 1
742 if groupVersion == "a/v1" {
743 return &metav1.APIResourceList{APIResources: []metav1.APIResource{{Name: "widgets", Kind: "Widget"}}}, nil
744 }
745
746 return nil, errors.NewNotFound(schema.GroupResource{}, "")
747 }
748
749 func (c *fakeDiscoveryClient) ServerGroupsAndResources() ([]*metav1.APIGroup, []*metav1.APIResourceList, error) {
750 c.resourceCalls = c.resourceCalls + 1
751
752 gs, _ := c.serverGroups()
753 resultGroups := []*metav1.APIGroup{}
754 for i := range gs.Groups {
755 resultGroups = append(resultGroups, &gs.Groups[i])
756 }
757
758 if c.serverResourcesHandler != nil {
759 rs, err := c.serverResourcesHandler()
760 return resultGroups, rs, err
761 }
762 return resultGroups, []*metav1.APIResourceList{}, nil
763 }
764
765 func (c *fakeDiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) {
766 c.resourceCalls = c.resourceCalls + 1
767 return nil, nil
768 }
769
770 func (c *fakeDiscoveryClient) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) {
771 c.resourceCalls = c.resourceCalls + 1
772 return nil, nil
773 }
774
775 func (c *fakeDiscoveryClient) ServerVersion() (*version.Info, error) {
776 c.versionCalls = c.versionCalls + 1
777 return &version.Info{}, nil
778 }
779
780 func (c *fakeDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) {
781 c.openAPICalls = c.openAPICalls + 1
782 return &openapi_v2.Document{}, nil
783 }
784
785 func (d *fakeDiscoveryClient) OpenAPIV3() openapi.Client {
786 panic("unimplemented")
787 }
788
789 func (d *fakeDiscoveryClient) WithLegacy() discovery.DiscoveryInterface {
790 panic("unimplemented")
791 }
792
793 func groupNamesFromList(groups *metav1.APIGroupList) []string {
794 result := []string{}
795 for _, group := range groups.Groups {
796 result = append(result, group.Name)
797 }
798 return result
799 }
800
801 func preferredVersionsFromList(groups *metav1.APIGroupList) []string {
802 result := []string{}
803 for _, group := range groups.Groups {
804 preferredGV := group.PreferredVersion.GroupVersion
805 result = append(result, preferredGV)
806 }
807 return result
808 }
809
810 func groupVersionsFromGroups(groups *metav1.APIGroupList) []string {
811 result := []string{}
812 for _, group := range groups.Groups {
813 for _, version := range group.Versions {
814 result = append(result, version.GroupVersion)
815 }
816 }
817 return result
818 }
819
View as plain text