From 3ac73ea2c834b1268732024766f1e55a5d0327d2 Mon Sep 17 00:00:00 2001 From: Sean Sullivan Date: Wed, 9 Nov 2022 12:30:05 -0800 Subject: [PATCH] Adds bool to force non-aggregated discovery Kubernetes-commit: a84d877310ba5cf9237c8e8e3218229c202d3a1e --- discovery/cached/disk/cached_discovery.go | 6 ++++ .../cached/disk/cached_discovery_test.go | 4 +++ discovery/cached/memory/memcache.go | 6 ++++ discovery/discovery_client.go | 30 ++++++++++++++++--- discovery/discovery_client_test.go | 20 +++++++++++++ discovery/fake/discovery.go | 5 ++++ restmapper/discovery_test.go | 8 +++++ restmapper/shortcut_test.go | 4 +++ 8 files changed, 79 insertions(+), 4 deletions(-) diff --git a/discovery/cached/disk/cached_discovery.go b/discovery/cached/disk/cached_discovery.go index c411acf7c8..82137a8ee4 100644 --- a/discovery/cached/disk/cached_discovery.go +++ b/discovery/cached/disk/cached_discovery.go @@ -277,6 +277,12 @@ func (d *CachedDiscoveryClient) Invalidate() { } } +// WithLegacy returns current cached discovery client; +// current client does not support legacy-only discovery. +func (d *CachedDiscoveryClient) WithLegacy() discovery.DiscoveryInterface { + return d +} + // NewCachedDiscoveryClientForConfig creates a new DiscoveryClient for the given config, and wraps // the created client in a CachedDiscoveryClient. The provided configuration is updated with a // custom transport that understands cache responses. diff --git a/discovery/cached/disk/cached_discovery_test.go b/discovery/cached/disk/cached_discovery_test.go index bf38db737d..1b22cd5fe5 100644 --- a/discovery/cached/disk/cached_discovery_test.go +++ b/discovery/cached/disk/cached_discovery_test.go @@ -786,6 +786,10 @@ func (d *fakeDiscoveryClient) OpenAPIV3() openapi.Client { panic("unimplemented") } +func (d *fakeDiscoveryClient) WithLegacy() discovery.DiscoveryInterface { + panic("unimplemented") +} + func groupNamesFromList(groups *metav1.APIGroupList) []string { result := []string{} for _, group := range groups.Groups { diff --git a/discovery/cached/memory/memcache.go b/discovery/cached/memory/memcache.go index 9c3890180c..0a41018474 100644 --- a/discovery/cached/memory/memcache.go +++ b/discovery/cached/memory/memcache.go @@ -279,6 +279,12 @@ func (d *memCacheClient) serverResourcesForGroupVersion(groupVersion string) (*m return r, nil } +// WithLegacy returns current memory-cached discovery client; +// current client does not support legacy-only discovery. +func (d *memCacheClient) WithLegacy() discovery.DiscoveryInterface { + return d +} + // NewMemCacheClient creates a new CachedDiscoveryInterface which caches // discovery information in memory and will stay up-to-date if Invalidate is // called with regularity. diff --git a/discovery/discovery_client.go b/discovery/discovery_client.go index f55cef3eac..9025e888ec 100644 --- a/discovery/discovery_client.go +++ b/discovery/discovery_client.go @@ -74,6 +74,10 @@ type DiscoveryInterface interface { ServerVersionInterface OpenAPISchemaInterface OpenAPIV3SchemaInterface + // Returns copy of current discovery client that will only + // receive the legacy discovery format, or pointer to current + // discovery client if it does not support legacy-only discovery. + WithLegacy() DiscoveryInterface } // AggregatedDiscoveryInterface extends DiscoveryInterface to include a method to possibly @@ -154,6 +158,8 @@ type DiscoveryClient struct { restClient restclient.Interface LegacyPrefix string + // Forces the client to request only "unaggregated" (legacy) discovery. + UseLegacyDiscovery bool } var _ AggregatedDiscoveryInterface = &DiscoveryClient{} @@ -213,10 +219,14 @@ func (d *DiscoveryClient) GroupsAndMaybeResources() (*metav1.APIGroupList, map[s // possible for the resource map to be nil if the server returned // the unaggregated discovery. func (d *DiscoveryClient) downloadLegacy() (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, error) { + accept := acceptDiscoveryFormats + if d.UseLegacyDiscovery { + accept = AcceptV1 + } var responseContentType string body, err := d.restClient.Get(). AbsPath("/api"). - SetHeader("Accept", acceptDiscoveryFormats). + SetHeader("Accept", accept). Do(context.TODO()). ContentType(&responseContentType). Raw() @@ -262,10 +272,14 @@ func (d *DiscoveryClient) downloadLegacy() (*metav1.APIGroupList, map[schema.Gro // discovery resources. The returned groups will always exist, but the // resources map may be nil. func (d *DiscoveryClient) downloadAPIs() (*metav1.APIGroupList, map[schema.GroupVersion]*metav1.APIResourceList, error) { + accept := acceptDiscoveryFormats + if d.UseLegacyDiscovery { + accept = AcceptV1 + } var responseContentType string body, err := d.restClient.Get(). AbsPath("/apis"). - SetHeader("Accept", acceptDiscoveryFormats). + SetHeader("Accept", accept). Do(context.TODO()). ContentType(&responseContentType). Raw() @@ -590,6 +604,14 @@ func (d *DiscoveryClient) OpenAPIV3() openapi.Client { return openapi.NewClient(d.restClient) } +// WithLegacy returns copy of current discovery client that will only +// receive the legacy discovery format. +func (d *DiscoveryClient) WithLegacy() DiscoveryInterface { + client := *d + client.UseLegacyDiscovery = true + return &client +} + // withRetries retries the given recovery function in case the groups supported by the server change after ServerGroup() returns. func withRetries(maxRetries int, f func() ([]*metav1.APIGroup, []*metav1.APIResourceList, error)) ([]*metav1.APIGroup, []*metav1.APIResourceList, error) { var result []*metav1.APIResourceList @@ -654,7 +676,7 @@ func NewDiscoveryClientForConfigAndClient(c *restclient.Config, httpClient *http return nil, err } client, err := restclient.UnversionedRESTClientForConfigAndClient(&config, httpClient) - return &DiscoveryClient{restClient: client, LegacyPrefix: "/api"}, err + return &DiscoveryClient{restClient: client, LegacyPrefix: "/api", UseLegacyDiscovery: false}, err } // NewDiscoveryClientForConfigOrDie creates a new DiscoveryClient for the given config. If @@ -670,7 +692,7 @@ func NewDiscoveryClientForConfigOrDie(c *restclient.Config) *DiscoveryClient { // NewDiscoveryClient returns a new DiscoveryClient for the given RESTClient. func NewDiscoveryClient(c restclient.Interface) *DiscoveryClient { - return &DiscoveryClient{restClient: c, LegacyPrefix: "/api"} + return &DiscoveryClient{restClient: c, LegacyPrefix: "/api", UseLegacyDiscovery: false} } // RESTClient returns a RESTClient that is used to communicate diff --git a/discovery/discovery_client_test.go b/discovery/discovery_client_test.go index 0610586891..4746fac5b0 100644 --- a/discovery/discovery_client_test.go +++ b/discovery/discovery_client_test.go @@ -2297,6 +2297,26 @@ func TestAggregatedServerPreferredResources(t *testing.T) { } } +func TestUseLegacyDiscovery(t *testing.T) { + // Default client sends aggregated discovery accept format (first) as well as legacy format. + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + acceptHeader := req.Header.Get("Accept") + assert.Equal(t, acceptDiscoveryFormats, acceptHeader) + })) + defer server.Close() + client := NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + client.ServerGroups() + // When "UseLegacyDiscovery" field is set, only the legacy discovery format is requested. + server = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + acceptHeader := req.Header.Get("Accept") + assert.Equal(t, AcceptV1, acceptHeader) + })) + defer server.Close() + client = NewDiscoveryClientForConfigOrDie(&restclient.Config{Host: server.URL}) + client.UseLegacyDiscovery = true + client.ServerGroups() +} + func groupNames(groups []*metav1.APIGroup) []string { result := []string{} for _, group := range groups { diff --git a/discovery/fake/discovery.go b/discovery/fake/discovery.go index 2eef5365d5..c78c256ef7 100644 --- a/discovery/fake/discovery.go +++ b/discovery/fake/discovery.go @@ -26,6 +26,7 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/version" + "k8s.io/client-go/discovery" "k8s.io/client-go/openapi" kubeversion "k8s.io/client-go/pkg/version" restclient "k8s.io/client-go/rest" @@ -164,3 +165,7 @@ func (c *FakeDiscovery) OpenAPIV3() openapi.Client { func (c *FakeDiscovery) RESTClient() restclient.Interface { return nil } + +func (c *FakeDiscovery) WithLegacy() discovery.DiscoveryInterface { + panic("unimplemented") +} diff --git a/restmapper/discovery_test.go b/restmapper/discovery_test.go index 771d96f720..045b3d7948 100644 --- a/restmapper/discovery_test.go +++ b/restmapper/discovery_test.go @@ -422,6 +422,10 @@ func (c *fakeFailingDiscovery) OpenAPIV3() openapi.Client { panic("implement me") } +func (c *fakeFailingDiscovery) WithLegacy() DiscoveryInterface { + panic("implement me") +} + type fakeCachedDiscoveryInterface struct { invalidateCalls int fresh bool @@ -499,6 +503,10 @@ func (c *fakeCachedDiscoveryInterface) OpenAPIV3() openapi.Client { panic("implement me") } +func (c *fakeCachedDiscoveryInterface) WithLegacy() DiscoveryInterface { + panic("implement me") +} + var ( aGroup = metav1.APIGroup{ Name: "a", diff --git a/restmapper/shortcut_test.go b/restmapper/shortcut_test.go index 95b865fe08..cd8506a906 100644 --- a/restmapper/shortcut_test.go +++ b/restmapper/shortcut_test.go @@ -362,6 +362,10 @@ func (c *fakeDiscoveryClient) OpenAPIV3() openapi.Client { panic("implement me") } +func (c *fakeDiscoveryClient) WithLegacy() discovery.DiscoveryInterface { + panic("implement me") +} + type fakeCachedDiscoveryClient struct { discovery.DiscoveryInterface freshHandler func() bool