diff --git a/pkg/kubectl/cmd/describe.go b/pkg/kubectl/cmd/describe.go index 73dcd3dace3..848f82100f8 100644 --- a/pkg/kubectl/cmd/describe.go +++ b/pkg/kubectl/cmd/describe.go @@ -137,7 +137,10 @@ func (o *DescribeOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [ o.BuilderArgs = args - o.Describer = f.Describer + o.Describer = func(mapping *meta.RESTMapping) (printers.Describer, error) { + return cmdutil.DescriberFn(f, mapping) + } + o.NewBuilder = f.NewBuilder // include the uninitialized objects by default diff --git a/pkg/kubectl/cmd/testing/fake.go b/pkg/kubectl/cmd/testing/fake.go index ce678c31665..59a4d947b58 100644 --- a/pkg/kubectl/cmd/testing/fake.go +++ b/pkg/kubectl/cmd/testing/fake.go @@ -271,10 +271,17 @@ func NewTestFactory() *TestFactory { WithClientConfig(clientConfig). WithRESTMapper(testRESTMapper()) + restConfig, err := clientConfig.ClientConfig() + if err != nil { + panic(fmt.Sprintf("unable to create a fake restclient config: %v", err)) + } + return &TestFactory{ Factory: cmdutil.NewFactory(configFlags), FakeDynamicClient: fakedynamic.NewSimpleDynamicClient(legacyscheme.Scheme), tempConfigFile: tmpFile, + + ClientConfigVal: restConfig, } } diff --git a/pkg/kubectl/cmd/util/factory.go b/pkg/kubectl/cmd/util/factory.go index 04e64f65ffa..10c50389346 100644 --- a/pkg/kubectl/cmd/util/factory.go +++ b/pkg/kubectl/cmd/util/factory.go @@ -35,7 +35,6 @@ import ( "k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" "k8s.io/kubernetes/pkg/kubectl/validation" - "k8s.io/kubernetes/pkg/printers" ) // Factory provides abstractions that allow the Kubectl command to be extended across multiple types @@ -102,8 +101,6 @@ type ObjectMappingFactory interface { ClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) // Returns a RESTClient for working with Unstructured objects. UnstructuredClientForMapping(mapping *meta.RESTMapping) (resource.RESTClient, error) - // Returns a Describer for displaying the specified RESTMapping type or an error. - Describer(mapping *meta.RESTMapping) (printers.Describer, error) // Returns a schema that can validate objects stored on disk. Validator(validate bool) (validation.Schema, error) diff --git a/pkg/kubectl/cmd/util/factory_object_mapping.go b/pkg/kubectl/cmd/util/factory_object_mapping.go index aa7105a1bd0..a4769978215 100644 --- a/pkg/kubectl/cmd/util/factory_object_mapping.go +++ b/pkg/kubectl/cmd/util/factory_object_mapping.go @@ -19,19 +19,15 @@ limitations under the License. package util import ( - "fmt" "sync" "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/client-go/dynamic" restclient "k8s.io/client-go/rest" api "k8s.io/kubernetes/pkg/apis/core" "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi" openapivalidation "k8s.io/kubernetes/pkg/kubectl/cmd/util/openapi/validation" "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" "k8s.io/kubernetes/pkg/kubectl/validation" - "k8s.io/kubernetes/pkg/printers" - printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" ) type ring1Factory struct { @@ -91,46 +87,6 @@ func (f *ring1Factory) UnstructuredClientForMapping(mapping *meta.RESTMapping) ( return restclient.RESTClientFor(cfg) } -func (f *ring1Factory) Describer(mapping *meta.RESTMapping) (printers.Describer, error) { - clientConfig, err := f.clientAccessFactory.ToRESTConfig() - if err != nil { - return nil, err - } - // try to get a describer - if describer, ok := printersinternal.DescriberFor(mapping.GroupVersionKind.GroupKind(), clientConfig); ok { - return describer, nil - } - // if this is a kind we don't have a describer for yet, go generic if possible - if genericDescriber, genericErr := genericDescriber(f.clientAccessFactory, mapping); genericErr == nil { - return genericDescriber, nil - } - // otherwise return an unregistered error - return nil, fmt.Errorf("no description has been implemented for %s", mapping.GroupVersionKind.String()) -} - -// helper function to make a generic describer, or return an error -func genericDescriber(clientAccessFactory ClientAccessFactory, mapping *meta.RESTMapping) (printers.Describer, error) { - clientConfig, err := clientAccessFactory.ToRESTConfig() - if err != nil { - return nil, err - } - - // used to fetch the resource - dynamicClient, err := dynamic.NewForConfig(clientConfig) - if err != nil { - return nil, err - } - - // used to get events for the resource - clientSet, err := clientAccessFactory.ClientSet() - if err != nil { - return nil, err - } - eventsClient := clientSet.Core() - - return printersinternal.GenericDescriberFor(mapping, dynamicClient, eventsClient), nil -} - func (f *ring1Factory) Validator(validate bool) (validation.Schema, error) { if !validate { return validation.NullSchema{}, nil diff --git a/pkg/kubectl/cmd/util/helpers.go b/pkg/kubectl/cmd/util/helpers.go index 1e5aa7dc6a1..b4640f67b25 100644 --- a/pkg/kubectl/cmd/util/helpers.go +++ b/pkg/kubectl/cmd/util/helpers.go @@ -37,9 +37,14 @@ import ( utilerrors "k8s.io/apimachinery/pkg/util/errors" "k8s.io/apimachinery/pkg/util/sets" "k8s.io/apimachinery/pkg/util/yaml" + "k8s.io/client-go/dynamic" "k8s.io/client-go/tools/clientcmd" + "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" "k8s.io/kubernetes/pkg/kubectl" + "k8s.io/kubernetes/pkg/kubectl/genericclioptions" "k8s.io/kubernetes/pkg/kubectl/genericclioptions/resource" + "k8s.io/kubernetes/pkg/printers" + printersinternal "k8s.io/kubernetes/pkg/printers/internalversion" utilexec "k8s.io/utils/exec" ) @@ -621,3 +626,50 @@ func ShouldIncludeUninitialized(cmd *cobra.Command, includeUninitialized bool) b } return shouldIncludeUninitialized } + +// DescriberFunc gives a way to display the specified RESTMapping type +type DescriberFunc func(restClientGetter genericclioptions.RESTClientGetter, mapping *meta.RESTMapping) (printers.Describer, error) + +// DescriberFn gives a way to easily override the function for unit testing if needed +var DescriberFn DescriberFunc = describer + +// Returns a Describer for displaying the specified RESTMapping type or an error. +func describer(restClientGetter genericclioptions.RESTClientGetter, mapping *meta.RESTMapping) (printers.Describer, error) { + clientConfig, err := restClientGetter.ToRESTConfig() + if err != nil { + return nil, err + } + // try to get a describer + if describer, ok := printersinternal.DescriberFor(mapping.GroupVersionKind.GroupKind(), clientConfig); ok { + return describer, nil + } + // if this is a kind we don't have a describer for yet, go generic if possible + if genericDescriber, genericErr := genericDescriber(restClientGetter, mapping); genericErr == nil { + return genericDescriber, nil + } + // otherwise return an unregistered error + return nil, fmt.Errorf("no description has been implemented for %s", mapping.GroupVersionKind.String()) +} + +// helper function to make a generic describer, or return an error +func genericDescriber(restClientGetter genericclioptions.RESTClientGetter, mapping *meta.RESTMapping) (printers.Describer, error) { + clientConfig, err := restClientGetter.ToRESTConfig() + if err != nil { + return nil, err + } + + // used to fetch the resource + dynamicClient, err := dynamic.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + + // used to get events for the resource + clientSet, err := internalclientset.NewForConfig(clientConfig) + if err != nil { + return nil, err + } + + eventsClient := clientSet.Core() + return printersinternal.GenericDescriberFor(mapping, dynamicClient, eventsClient), nil +}