diff --git a/discovery/cached/disk/cached_discovery.go b/discovery/cached/disk/cached_discovery.go index c411acf7..82137a8e 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 bf38db73..1b22cd5f 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 9c389018..0a410184 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 f55cef3e..9025e888 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 06105868..4746fac5 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 2eef5365..c78c256e 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 771d96f7..045b3d79 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 95b865fe..cd8506a9 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