diff --git a/pkg/kubectl/categories/BUILD b/pkg/kubectl/categories/BUILD index 2a7d7588ec3..0e195f3d58e 100644 --- a/pkg/kubectl/categories/BUILD +++ b/pkg/kubectl/categories/BUILD @@ -1,4 +1,4 @@ -load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") +load("@io_bazel_rules_go//go:def.bzl", "go_library") go_library( name = "go_default_library", @@ -7,22 +7,7 @@ go_library( visibility = ["//visibility:public"], deps = [ "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", - "//vendor/k8s.io/client-go/discovery:go_default_library", - ], -) - -go_test( - name = "go_default_test", - srcs = ["categories_test.go"], - embed = [":go_default_library"], - deps = [ - "//vendor/github.com/googleapis/gnostic/OpenAPIv2:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/runtime/schema:go_default_library", - "//vendor/k8s.io/apimachinery/pkg/version:go_default_library", - "//vendor/k8s.io/client-go/discovery:go_default_library", - "//vendor/k8s.io/client-go/rest:go_default_library", - "//vendor/k8s.io/client-go/rest/fake:go_default_library", + "//vendor/k8s.io/client-go/restmapper:go_default_library", ], ) diff --git a/pkg/kubectl/categories/categories.go b/pkg/kubectl/categories/categories.go index 29bcc5d3948..0d00e2cc622 100644 --- a/pkg/kubectl/categories/categories.go +++ b/pkg/kubectl/categories/categories.go @@ -18,155 +18,9 @@ package categories import ( "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/discovery" + "k8s.io/client-go/restmapper" ) -// CategoryExpander maps category strings to GroupResouces. -// Categories are classification or 'tag' of a group of resources. -type CategoryExpander interface { - Expand(category string) ([]schema.GroupResource, bool) -} - -// SimpleCategoryExpander implements CategoryExpander interface -// using a static mapping of categories to GroupResource mapping. -type SimpleCategoryExpander struct { - Expansions map[string][]schema.GroupResource -} - -func (e SimpleCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) { - ret, ok := e.Expansions[category] - return ret, ok -} - -// discoveryCategoryExpander struct lets a REST Client wrapper (discoveryClient) to retrieve list of APIResourceList, -// and then convert to fallbackExpander -type discoveryCategoryExpander struct { - fallbackExpander CategoryExpander - discoveryClient discovery.DiscoveryInterface -} - -// NewDiscoveryCategoryExpander returns a category expander that makes use of the "categories" fields from -// the API, found through the discovery client. In case of any error or no category found (which likely -// means we're at a cluster prior to categories support, fallback to the expander provided. -func NewDiscoveryCategoryExpander(fallbackExpander CategoryExpander, client discovery.DiscoveryInterface) (discoveryCategoryExpander, error) { - if client == nil { - panic("Please provide discovery client to shortcut expander") - } - return discoveryCategoryExpander{fallbackExpander: fallbackExpander, discoveryClient: client}, nil -} - -func (e discoveryCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) { - // Get all supported resources for groups and versions from server, if no resource found, fallback anyway. - apiResourceLists, _ := e.discoveryClient.ServerResources() - if len(apiResourceLists) == 0 { - return e.fallbackExpander.Expand(category) - } - - discoveredExpansions := map[string][]schema.GroupResource{} - - for _, apiResourceList := range apiResourceLists { - gv, err := schema.ParseGroupVersion(apiResourceList.GroupVersion) - if err != nil { - return e.fallbackExpander.Expand(category) - } - // Collect GroupVersions by categories - for _, apiResource := range apiResourceList.APIResources { - if categories := apiResource.Categories; len(categories) > 0 { - for _, category := range categories { - groupResource := schema.GroupResource{ - Group: gv.Group, - Resource: apiResource.Name, - } - discoveredExpansions[category] = append(discoveredExpansions[category], groupResource) - } - } - } - } - - if len(discoveredExpansions) == 0 { - // We don't know if the server really don't have any resource with categories, - // or we're on a cluster version prior to categories support. Anyways, fallback. - return e.fallbackExpander.Expand(category) - } - - ret, ok := discoveredExpansions[category] - return ret, ok -} - -// discoveryFilteredExpander expands the given CategoryExpander (delegate) to filter group and resource returned from server -type discoveryFilteredExpander struct { - delegate CategoryExpander - - discoveryClient discovery.DiscoveryInterface -} - -// NewDiscoveryFilteredExpander returns a category expander that filters the returned groupresources -// by what the server has available -func NewDiscoveryFilteredExpander(delegate CategoryExpander, client discovery.DiscoveryInterface) (discoveryFilteredExpander, error) { - if client == nil { - panic("Please provide discovery client to shortcut expander") - } - return discoveryFilteredExpander{delegate: delegate, discoveryClient: client}, nil -} - -func (e discoveryFilteredExpander) Expand(category string) ([]schema.GroupResource, bool) { - delegateExpansion, ok := e.delegate.Expand(category) - - // Check if we have access to server resources - apiResources, err := e.discoveryClient.ServerResources() - if err != nil { - return delegateExpansion, ok - } - - availableResources, err := discovery.GroupVersionResources(apiResources) - if err != nil { - return delegateExpansion, ok - } - - available := []schema.GroupResource{} - for _, requestedResource := range delegateExpansion { - for availableResource := range availableResources { - if requestedResource.Group == availableResource.Group && - requestedResource.Resource == availableResource.Resource { - available = append(available, requestedResource) - break - } - } - } - - return available, ok -} - -// UnionCategoryExpander implements CategoryExpander interface. -// It maps given category string to union of expansions returned by all the CategoryExpanders in the list. -type UnionCategoryExpander []CategoryExpander - -func (u UnionCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) { - ret := []schema.GroupResource{} - ok := false - - // Expand the category for each CategoryExpander in the list and merge/combine the results. - for _, expansion := range u { - curr, currOk := expansion.Expand(category) - - for _, currGR := range curr { - found := false - for _, existing := range ret { - if existing == currGR { - found = true - break - } - } - if !found { - ret = append(ret, currGR) - } - } - ok = ok || currOk - } - - return ret, ok -} - // legacyUserResources are the resource names that apply to the primary, user facing resources used by // client tools. They are in deletion-first order - dependent resources should be last. // Should remain exported in order to expose a current list of resources to downstream @@ -185,7 +39,7 @@ var legacyUserResources = []schema.GroupResource{ } // LegacyCategoryExpander is the old hardcoded expansion -var LegacyCategoryExpander CategoryExpander = SimpleCategoryExpander{ +var LegacyCategoryExpander restmapper.CategoryExpander = restmapper.SimpleCategoryExpander{ Expansions: map[string][]schema.GroupResource{ "all": legacyUserResources, }, diff --git a/pkg/kubectl/cmd/testing/fake.go b/pkg/kubectl/cmd/testing/fake.go index 9a1bbf86a37..4e69bdf0619 100644 --- a/pkg/kubectl/cmd/testing/fake.go +++ b/pkg/kubectl/cmd/testing/fake.go @@ -287,7 +287,7 @@ func (f *TestFactory) Cleanup() { os.Remove(f.tempConfigFile.Name()) } -func (f *TestFactory) CategoryExpander() categories.CategoryExpander { +func (f *TestFactory) CategoryExpander() restmapper.CategoryExpander { return categories.LegacyCategoryExpander } @@ -335,6 +335,7 @@ func (f *TestFactory) Command(*cobra.Command, bool) string { func (f *TestFactory) NewBuilder() *resource.Builder { mapper, err := f.RESTMapper() + categoryExpander, err2 := f.CategoryExpander() return resource.NewFakeBuilder( func(version schema.GroupVersion) (resource.RESTClient, error) { @@ -347,8 +348,8 @@ func (f *TestFactory) NewBuilder() *resource.Builder { return f.Client, nil }, mapper, - f.CategoryExpander(), - ).AddError(err) + categoryExpander, + ).AddError(err).AddError(err2) } func (f *TestFactory) KubernetesClientSet() (*kubernetes.Clientset, error) { diff --git a/pkg/kubectl/cmd/util/factory.go b/pkg/kubectl/cmd/util/factory.go index d54b4fc72ce..fc1bbaeb408 100644 --- a/pkg/kubectl/cmd/util/factory.go +++ b/pkg/kubectl/cmd/util/factory.go @@ -36,13 +36,13 @@ import ( "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" scaleclient "k8s.io/client-go/scale" api "k8s.io/kubernetes/pkg/apis/core" apiv1 "k8s.io/kubernetes/pkg/apis/core/v1" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" "k8s.io/kubernetes/pkg/kubectl" - "k8s.io/kubernetes/pkg/kubectl/categories" "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi" "k8s.io/kubernetes/pkg/kubectl/plugins" "k8s.io/kubernetes/pkg/kubectl/resource" @@ -169,7 +169,7 @@ type ClientAccessFactory interface { // Generally they provide object typing and functions that build requests based on the negotiated clients. type ObjectMappingFactory interface { // Returns interface for expanding categories like `all`. - CategoryExpander() categories.CategoryExpander + CategoryExpander() restmapper.CategoryExpander // Returns a RESTClient for working with the specified RESTMapping or an error. This is intended // for working with arbitrary resources and is not guaranteed to point to a Kubernetes APIServer. ClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) diff --git a/pkg/kubectl/cmd/util/factory_object_mapping.go b/pkg/kubectl/cmd/util/factory_object_mapping.go index 758c578a5f6..efb80d6507b 100644 --- a/pkg/kubectl/cmd/util/factory_object_mapping.go +++ b/pkg/kubectl/cmd/util/factory_object_mapping.go @@ -40,6 +40,7 @@ import ( "k8s.io/apimachinery/pkg/runtime" "k8s.io/client-go/dynamic" restclient "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" "k8s.io/kubernetes/pkg/apis/apps" "k8s.io/kubernetes/pkg/apis/batch" api "k8s.io/kubernetes/pkg/apis/core" @@ -75,17 +76,17 @@ func NewObjectMappingFactory(clientAccessFactory ClientAccessFactory) ObjectMapp return f } -func (f *ring1Factory) CategoryExpander() categories.CategoryExpander { +func (f *ring1Factory) CategoryExpander() restmapper.CategoryExpander { legacyExpander := categories.LegacyCategoryExpander discoveryClient, err := f.clientAccessFactory.DiscoveryClient() if err == nil { // fallback is the legacy expander wrapped with discovery based filtering - fallbackExpander, err := categories.NewDiscoveryFilteredExpander(legacyExpander, discoveryClient) + fallbackExpander, err := restmapper.NewDiscoveryFilteredExpander(legacyExpander, discoveryClient) CheckErr(err) // by default use the expander that discovers based on "categories" field from the API - discoveryCategoryExpander, err := categories.NewDiscoveryCategoryExpander(fallbackExpander, discoveryClient) + discoveryCategoryExpander, err := restmapper.NewDiscoveryCategoryExpander(fallbackExpander, discoveryClient) CheckErr(err) return discoveryCategoryExpander diff --git a/pkg/kubectl/resource/BUILD b/pkg/kubectl/resource/BUILD index a2df4dc864f..ea2f78bb10a 100644 --- a/pkg/kubectl/resource/BUILD +++ b/pkg/kubectl/resource/BUILD @@ -22,7 +22,6 @@ go_library( "//build/visible_to:pkg_kubectl_resource_CONSUMERS", ], deps = [ - "//pkg/kubectl/categories:go_default_library", "//pkg/kubectl/validation:go_default_library", "//vendor/golang.org/x/text/encoding/unicode:go_default_library", "//vendor/golang.org/x/text/transform:go_default_library", @@ -44,6 +43,7 @@ go_library( "//vendor/k8s.io/apimachinery/pkg/watch:go_default_library", "//vendor/k8s.io/client-go/dynamic:go_default_library", "//vendor/k8s.io/client-go/rest:go_default_library", + "//vendor/k8s.io/client-go/restmapper:go_default_library", ], ) diff --git a/pkg/kubectl/resource/builder.go b/pkg/kubectl/resource/builder.go index f41df2f7b10..47f3df66443 100644 --- a/pkg/kubectl/resource/builder.go +++ b/pkg/kubectl/resource/builder.go @@ -34,7 +34,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/serializer" utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/kubernetes/pkg/kubectl/categories" + "k8s.io/client-go/restmapper" "k8s.io/kubernetes/pkg/kubectl/validation" ) @@ -47,7 +47,7 @@ const defaultHttpGetAttempts int = 3 // from the command line and converting them to a list of resources to iterate // over using the Visitor interface. type Builder struct { - categoryExpander categories.CategoryExpander + categoryExpander restmapper.CategoryExpander // mapper is set explicitly by resource builders mapper *mapper @@ -143,7 +143,7 @@ type resourceTuple struct { type FakeClientFunc func(version schema.GroupVersion) (RESTClient, error) -func NewFakeBuilder(fakeClientFn FakeClientFunc, restMapper meta.RESTMapper, categoryExpander categories.CategoryExpander) *Builder { +func NewFakeBuilder(fakeClientFn FakeClientFunc, restMapper meta.RESTMapper, categoryExpander restmapper.CategoryExpander) *Builder { ret := NewBuilder(nil, restMapper, categoryExpander) ret.fakeClientFn = fakeClientFn return ret @@ -153,7 +153,7 @@ func NewFakeBuilder(fakeClientFn FakeClientFunc, restMapper meta.RESTMapper, cat // internal or unstructured must be specified. // TODO: Add versioned client (although versioned is still lossy) // TODO remove internal and unstructured mapper and instead have them set the negotiated serializer for use in the client -func NewBuilder(clientConfigFn ClientConfigFunc, restMapper meta.RESTMapper, categoryExpander categories.CategoryExpander) *Builder { +func NewBuilder(clientConfigFn ClientConfigFunc, restMapper meta.RESTMapper, categoryExpander restmapper.CategoryExpander) *Builder { return &Builder{ clientConfigFn: clientConfigFn, restMapper: restMapper, diff --git a/staging/src/k8s.io/client-go/restmapper/BUILD b/staging/src/k8s.io/client-go/restmapper/BUILD index 42a1d0392ce..afd6762fd74 100644 --- a/staging/src/k8s.io/client-go/restmapper/BUILD +++ b/staging/src/k8s.io/client-go/restmapper/BUILD @@ -3,6 +3,7 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test") go_library( name = "go_default_library", srcs = [ + "category_expansion.go", "discovery.go", "shortcut.go", ], @@ -20,6 +21,7 @@ go_library( go_test( name = "go_default_test", srcs = [ + "category_expansion_test.go", "discovery_test.go", "shortcut_test.go", ], diff --git a/staging/src/k8s.io/client-go/restmapper/category_expansion.go b/staging/src/k8s.io/client-go/restmapper/category_expansion.go new file mode 100644 index 00000000000..207a5729358 --- /dev/null +++ b/staging/src/k8s.io/client-go/restmapper/category_expansion.go @@ -0,0 +1,168 @@ +/* +Copyright 2017 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package restmapper + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/client-go/discovery" +) + +// CategoryExpander maps category strings to GroupResouces. +// Categories are classification or 'tag' of a group of resources. +type CategoryExpander interface { + Expand(category string) ([]schema.GroupResource, bool) +} + +// SimpleCategoryExpander implements CategoryExpander interface +// using a static mapping of categories to GroupResource mapping. +type SimpleCategoryExpander struct { + Expansions map[string][]schema.GroupResource +} + +func (e SimpleCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) { + ret, ok := e.Expansions[category] + return ret, ok +} + +// discoveryCategoryExpander struct lets a REST Client wrapper (discoveryClient) to retrieve list of APIResourceList, +// and then convert to fallbackExpander +type discoveryCategoryExpander struct { + fallbackExpander CategoryExpander + discoveryClient discovery.DiscoveryInterface +} + +// NewDiscoveryCategoryExpander returns a category expander that makes use of the "categories" fields from +// the API, found through the discovery client. In case of any error or no category found (which likely +// means we're at a cluster prior to categories support, fallback to the expander provided. +func NewDiscoveryCategoryExpander(fallbackExpander CategoryExpander, client discovery.DiscoveryInterface) (discoveryCategoryExpander, error) { + if client == nil { + panic("Please provide discovery client to shortcut expander") + } + return discoveryCategoryExpander{fallbackExpander: fallbackExpander, discoveryClient: client}, nil +} + +func (e discoveryCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) { + // Get all supported resources for groups and versions from server, if no resource found, fallback anyway. + apiResourceLists, _ := e.discoveryClient.ServerResources() + if len(apiResourceLists) == 0 { + return e.fallbackExpander.Expand(category) + } + + discoveredExpansions := map[string][]schema.GroupResource{} + + for _, apiResourceList := range apiResourceLists { + gv, err := schema.ParseGroupVersion(apiResourceList.GroupVersion) + if err != nil { + return e.fallbackExpander.Expand(category) + } + // Collect GroupVersions by categories + for _, apiResource := range apiResourceList.APIResources { + if categories := apiResource.Categories; len(categories) > 0 { + for _, category := range categories { + groupResource := schema.GroupResource{ + Group: gv.Group, + Resource: apiResource.Name, + } + discoveredExpansions[category] = append(discoveredExpansions[category], groupResource) + } + } + } + } + + if len(discoveredExpansions) == 0 { + // We don't know if the server really don't have any resource with categories, + // or we're on a cluster version prior to categories support. Anyways, fallback. + return e.fallbackExpander.Expand(category) + } + + ret, ok := discoveredExpansions[category] + return ret, ok +} + +// discoveryFilteredExpander expands the given CategoryExpander (delegate) to filter group and resource returned from server +type discoveryFilteredExpander struct { + delegate CategoryExpander + + discoveryClient discovery.DiscoveryInterface +} + +// NewDiscoveryFilteredExpander returns a category expander that filters the returned groupresources +// by what the server has available +func NewDiscoveryFilteredExpander(delegate CategoryExpander, client discovery.DiscoveryInterface) (discoveryFilteredExpander, error) { + if client == nil { + panic("Please provide discovery client to shortcut expander") + } + return discoveryFilteredExpander{delegate: delegate, discoveryClient: client}, nil +} + +func (e discoveryFilteredExpander) Expand(category string) ([]schema.GroupResource, bool) { + delegateExpansion, ok := e.delegate.Expand(category) + + // Check if we have access to server resources + apiResources, err := e.discoveryClient.ServerResources() + if err != nil { + return delegateExpansion, ok + } + + availableResources, err := discovery.GroupVersionResources(apiResources) + if err != nil { + return delegateExpansion, ok + } + + available := []schema.GroupResource{} + for _, requestedResource := range delegateExpansion { + for availableResource := range availableResources { + if requestedResource.Group == availableResource.Group && + requestedResource.Resource == availableResource.Resource { + available = append(available, requestedResource) + break + } + } + } + + return available, ok +} + +// UnionCategoryExpander implements CategoryExpander interface. +// It maps given category string to union of expansions returned by all the CategoryExpanders in the list. +type UnionCategoryExpander []CategoryExpander + +func (u UnionCategoryExpander) Expand(category string) ([]schema.GroupResource, bool) { + ret := []schema.GroupResource{} + ok := false + + // Expand the category for each CategoryExpander in the list and merge/combine the results. + for _, expansion := range u { + curr, currOk := expansion.Expand(category) + + for _, currGR := range curr { + found := false + for _, existing := range ret { + if existing == currGR { + found = true + break + } + } + if !found { + ret = append(ret, currGR) + } + } + ok = ok || currOk + } + + return ret, ok +} diff --git a/pkg/kubectl/categories/categories_test.go b/staging/src/k8s.io/client-go/restmapper/category_expansion_test.go similarity index 61% rename from pkg/kubectl/categories/categories_test.go rename to staging/src/k8s.io/client-go/restmapper/category_expansion_test.go index 5344bad2242..ac42307f69f 100644 --- a/pkg/kubectl/categories/categories_test.go +++ b/staging/src/k8s.io/client-go/restmapper/category_expansion_test.go @@ -14,19 +14,14 @@ See the License for the specific language governing permissions and limitations under the License. */ -package categories +package restmapper import ( "reflect" "testing" - "github.com/googleapis/gnostic/OpenAPIv2" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/apimachinery/pkg/version" - "k8s.io/client-go/discovery" - restclient "k8s.io/client-go/rest" - "k8s.io/client-go/rest/fake" ) func TestCategoryExpansion(t *testing.T) { @@ -46,23 +41,28 @@ func TestCategoryExpansion(t *testing.T) { name: "all-replacement", arg: "all", expected: []schema.GroupResource{ - {Resource: "pods"}, - {Resource: "replicationcontrollers"}, - {Resource: "services"}, - {Resource: "statefulsets", Group: "apps"}, - {Resource: "horizontalpodautoscalers", Group: "autoscaling"}, - {Resource: "jobs", Group: "batch"}, - {Resource: "cronjobs", Group: "batch"}, - {Resource: "daemonsets", Group: "extensions"}, - {Resource: "deployments", Group: "extensions"}, - {Resource: "replicasets", Group: "extensions"}, + {Resource: "one"}, + {Resource: "two"}, + {Resource: "three", Group: "alpha"}, + {Resource: "four", Group: "bravo"}, }, expectedOk: true, }, } for _, test := range tests { - actual, actualOk := LegacyCategoryExpander.Expand(test.arg) + simpleCategoryExpander := SimpleCategoryExpander{ + Expansions: map[string][]schema.GroupResource{ + "all": { + {Group: "", Resource: "one"}, + {Group: "", Resource: "two"}, + {Group: "alpha", Resource: "three"}, + {Group: "bravo", Resource: "four"}, + }, + }, + } + + actual, actualOk := simpleCategoryExpander.Expand(test.arg) if e, a := test.expected, actual; !reflect.DeepEqual(e, a) { t.Errorf("%s: expected %s, got %s", test.name, e, a) } @@ -146,41 +146,3 @@ func TestDiscoveryCategoryExpander(t *testing.T) { } } - -type fakeDiscoveryClient struct { - serverResourcesHandler func() ([]*metav1.APIResourceList, error) -} - -var _ discovery.DiscoveryInterface = &fakeDiscoveryClient{} - -func (c *fakeDiscoveryClient) RESTClient() restclient.Interface { - return &fake.RESTClient{} -} - -func (c *fakeDiscoveryClient) ServerGroups() (*metav1.APIGroupList, error) { - return nil, nil -} - -func (c *fakeDiscoveryClient) ServerResourcesForGroupVersion(groupVersion string) (*metav1.APIResourceList, error) { - return &metav1.APIResourceList{}, nil -} - -func (c *fakeDiscoveryClient) ServerResources() ([]*metav1.APIResourceList, error) { - return c.serverResourcesHandler() -} - -func (c *fakeDiscoveryClient) ServerPreferredResources() ([]*metav1.APIResourceList, error) { - return nil, nil -} - -func (c *fakeDiscoveryClient) ServerPreferredNamespacedResources() ([]*metav1.APIResourceList, error) { - return nil, nil -} - -func (c *fakeDiscoveryClient) ServerVersion() (*version.Info, error) { - return &version.Info{}, nil -} - -func (c *fakeDiscoveryClient) OpenAPISchema() (*openapi_v2.Document, error) { - return &openapi_v2.Document{}, nil -}