diff --git a/staging/src/k8s.io/cli-runtime/pkg/resource/dry_run_verifier.go b/staging/src/k8s.io/cli-runtime/pkg/resource/dry_run_verifier.go index 49ab6f861cf..1fb36503a27 100644 --- a/staging/src/k8s.io/cli-runtime/pkg/resource/dry_run_verifier.go +++ b/staging/src/k8s.io/cli-runtime/pkg/resource/dry_run_verifier.go @@ -27,17 +27,10 @@ import ( "k8s.io/client-go/dynamic" ) -// VerifyDryRun returns nil if a resource group-version-kind supports -// server-side dry-run. Otherwise, an error is returned. -func VerifyDryRun(gvk schema.GroupVersionKind, dynamicClient dynamic.Interface, discoveryClient discovery.DiscoveryInterface) error { - verifier := NewDryRunVerifier(dynamicClient, discoveryClient) - return verifier.HasSupport(gvk) -} - -func NewDryRunVerifier(dynamicClient dynamic.Interface, discoveryClient discovery.DiscoveryInterface) *DryRunVerifier { +func NewDryRunVerifier(dynamicClient dynamic.Interface, openAPIGetter discovery.OpenAPISchemaInterface) *DryRunVerifier { return &DryRunVerifier{ finder: NewCRDFinder(CRDFromDynamic(dynamicClient)), - openAPIGetter: discoveryClient, + openAPIGetter: openAPIGetter, } } diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go b/staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go index d7a15df82bc..1e7a7f8daff 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/annotate/annotate.go @@ -178,11 +178,7 @@ func (o *AnnotateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [ if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.dryRunStrategy) printer, err := o.PrintFlags.ToPrinter() diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/apply/apply.go b/staging/src/k8s.io/kubectl/pkg/cmd/apply/apply.go index e041c5c4114..28883537bc6 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/apply/apply.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/apply/apply.go @@ -218,11 +218,7 @@ func (o *ApplyOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(o.DynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(o.DynamicClient, f.OpenAPIGetter()) o.FieldManager = GetApplyFieldManagerFlag(cmd, o.ServerSideApply) if o.ForceConflicts && !o.ServerSideApply { diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/apply/apply_set_last_applied.go b/staging/src/k8s.io/kubectl/pkg/cmd/apply/apply_set_last_applied.go index f761f80032e..1b9dd672b99 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/apply/apply_set_last_applied.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/apply/apply_set_last_applied.go @@ -128,11 +128,7 @@ func (o *SetLastAppliedOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) o.output = cmdutil.GetFlagString(cmd, "output") o.shortOutput = o.output == "name" diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/apply/apply_test.go b/staging/src/k8s.io/kubectl/pkg/cmd/apply/apply_test.go index 194fbe17696..6d2466c3d42 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/apply/apply_test.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/apply/apply_test.go @@ -29,6 +29,7 @@ import ( "strings" "testing" + openapi_v2 "github.com/googleapis/gnostic/openapiv2" "github.com/spf13/cobra" appsv1 "k8s.io/api/apps/v1" @@ -41,6 +42,7 @@ import ( sptest "k8s.io/apimachinery/pkg/util/strategicpatch/testing" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/resource" + "k8s.io/client-go/discovery" dynamicfakeclient "k8s.io/client-go/dynamic/fake" restclient "k8s.io/client-go/rest" "k8s.io/client-go/rest/fake" @@ -52,21 +54,38 @@ import ( ) var ( - fakeSchema = sptest.Fake{Path: filepath.Join("..", "..", "..", "testdata", "openapi", "swagger.json")} - testingOpenAPISchemaFns = []func() (openapi.Resources, error){nil, AlwaysErrorOpenAPISchemaFn, openAPISchemaFn} - AlwaysErrorOpenAPISchemaFn = func() (openapi.Resources, error) { - return nil, errors.New("cannot get openapi spec") + fakeSchema = sptest.Fake{Path: filepath.Join("..", "..", "..", "testdata", "openapi", "swagger.json")} + testingOpenAPISchemas = []testOpenAPISchema{{OpenAPIGetter: &fakeSchema}, AlwaysErrorsOpenAPISchema, FakeOpenAPISchema} + AlwaysErrorsOpenAPISchema = testOpenAPISchema{ + OpenAPISchemaFn: func() (openapi.Resources, error) { + return nil, errors.New("cannot get openapi spec") + }, + OpenAPIGetter: &alwaysErrorsOpenAPISchema{}, } - openAPISchemaFn = func() (openapi.Resources, error) { - s, err := fakeSchema.OpenAPISchema() - if err != nil { - return nil, err - } - return openapi.NewOpenAPIData(s) + FakeOpenAPISchema = testOpenAPISchema{ + OpenAPISchemaFn: func() (openapi.Resources, error) { + s, err := fakeSchema.OpenAPISchema() + if err != nil { + return nil, err + } + return openapi.NewOpenAPIData(s) + }, + OpenAPIGetter: &fakeSchema, } codec = scheme.Codecs.LegacyCodec(scheme.Scheme.PrioritizedVersionsAllGroups()...) ) +type testOpenAPISchema struct { + OpenAPISchemaFn func() (openapi.Resources, error) + OpenAPIGetter discovery.OpenAPISchemaInterface +} + +type alwaysErrorsOpenAPISchema struct{} + +func (o *alwaysErrorsOpenAPISchema) OpenAPISchema() (*openapi_v2.Document, error) { + return nil, errors.New("cannot get openapi schema") +} + func TestApplyExtraArgsFail(t *testing.T) { f := cmdtesting.NewTestFactory() defer f.Cleanup() @@ -518,7 +537,7 @@ func TestApplyObject(t *testing.T) { nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC) pathRC := "/namespaces/test/replicationcontrollers/" + nameRC - for _, fn := range testingOpenAPISchemaFns { + for _, testingOpenAPISchema := range testingOpenAPISchemas { t.Run("test apply when a local object is specified", func(t *testing.T) { tf := cmdtesting.NewTestFactory().WithNamespace("test") defer tf.Cleanup() @@ -540,7 +559,8 @@ func TestApplyObject(t *testing.T) { } }), } - tf.OpenAPISchemaFunc = fn + tf.OpenAPISchemaFunc = testingOpenAPISchema.OpenAPISchemaFn + tf.FakeOpenAPIGetter = testingOpenAPISchema.OpenAPIGetter tf.ClientConfigVal = cmdtesting.DefaultClientConfig() ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams() @@ -566,7 +586,7 @@ func TestApplyPruneObjects(t *testing.T) { nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC) pathRC := "/namespaces/test/replicationcontrollers/" + nameRC - for _, fn := range testingOpenAPISchemaFns { + for _, testingOpenAPISchema := range testingOpenAPISchemas { t.Run("test apply returns correct output", func(t *testing.T) { tf := cmdtesting.NewTestFactory().WithNamespace("test") defer tf.Cleanup() @@ -588,7 +608,8 @@ func TestApplyPruneObjects(t *testing.T) { } }), } - tf.OpenAPISchemaFunc = fn + tf.OpenAPISchemaFunc = testingOpenAPISchema.OpenAPISchemaFn + tf.FakeOpenAPIGetter = testingOpenAPISchema.OpenAPIGetter tf.ClientConfigVal = cmdtesting.DefaultClientConfig() ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams() @@ -631,7 +652,7 @@ func TestApplyObjectOutput(t *testing.T) { t.Fatal(err) } - for _, fn := range testingOpenAPISchemaFns { + for _, testingOpenAPISchema := range testingOpenAPISchemas { t.Run("test apply returns correct output", func(t *testing.T) { tf := cmdtesting.NewTestFactory().WithNamespace("test") defer tf.Cleanup() @@ -653,7 +674,8 @@ func TestApplyObjectOutput(t *testing.T) { } }), } - tf.OpenAPISchemaFunc = fn + tf.OpenAPISchemaFunc = testingOpenAPISchema.OpenAPISchemaFn + tf.FakeOpenAPIGetter = testingOpenAPISchema.OpenAPIGetter tf.ClientConfigVal = cmdtesting.DefaultClientConfig() ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams() @@ -680,7 +702,7 @@ func TestApplyRetry(t *testing.T) { nameRC, currentRC := readAndAnnotateReplicationController(t, filenameRC) pathRC := "/namespaces/test/replicationcontrollers/" + nameRC - for _, fn := range testingOpenAPISchemaFns { + for _, testingOpenAPISchema := range testingOpenAPISchemas { t.Run("test apply retries on conflict error", func(t *testing.T) { firstPatch := true retry := false @@ -714,7 +736,8 @@ func TestApplyRetry(t *testing.T) { } }), } - tf.OpenAPISchemaFunc = fn + tf.OpenAPISchemaFunc = testingOpenAPISchema.OpenAPISchemaFn + tf.FakeOpenAPIGetter = testingOpenAPISchema.OpenAPIGetter tf.ClientConfigVal = cmdtesting.DefaultClientConfig() ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams() @@ -860,7 +883,7 @@ func testApplyMultipleObjects(t *testing.T, asList bool) { nameSVC, currentSVC := readAndAnnotateService(t, filenameSVC) pathSVC := "/namespaces/test/services/" + nameSVC - for _, fn := range testingOpenAPISchemaFns { + for _, testingOpenAPISchema := range testingOpenAPISchemas { t.Run("test apply on multiple objects", func(t *testing.T) { tf := cmdtesting.NewTestFactory().WithNamespace("test") defer tf.Cleanup() @@ -889,7 +912,8 @@ func testApplyMultipleObjects(t *testing.T, asList bool) { } }), } - tf.OpenAPISchemaFunc = fn + tf.OpenAPISchemaFunc = testingOpenAPISchema.OpenAPISchemaFn + tf.FakeOpenAPIGetter = testingOpenAPISchema.OpenAPIGetter tf.ClientConfigVal = cmdtesting.DefaultClientConfig() ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams() @@ -941,7 +965,7 @@ func TestApplyNULLPreservation(t *testing.T) { verifiedPatch := false deploymentBytes := readDeploymentFromFile(t, filenameDeployObjServerside) - for _, fn := range testingOpenAPISchemaFns { + for _, testingOpenAPISchema := range testingOpenAPISchemas { t.Run("test apply preserves NULL fields", func(t *testing.T) { tf := cmdtesting.NewTestFactory().WithNamespace("test") defer tf.Cleanup() @@ -984,7 +1008,8 @@ func TestApplyNULLPreservation(t *testing.T) { } }), } - tf.OpenAPISchemaFunc = fn + tf.OpenAPISchemaFunc = testingOpenAPISchema.OpenAPISchemaFn + tf.FakeOpenAPIGetter = testingOpenAPISchema.OpenAPIGetter tf.ClientConfigVal = cmdtesting.DefaultClientConfig() ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams() @@ -1016,7 +1041,7 @@ func TestUnstructuredApply(t *testing.T) { verifiedPatch := false - for _, fn := range testingOpenAPISchemaFns { + for _, testingOpenAPISchema := range testingOpenAPISchemas { t.Run("test apply works correctly with unstructured objects", func(t *testing.T) { tf := cmdtesting.NewTestFactory().WithNamespace("test") defer tf.Cleanup() @@ -1050,7 +1075,8 @@ func TestUnstructuredApply(t *testing.T) { } }), } - tf.OpenAPISchemaFunc = fn + tf.OpenAPISchemaFunc = testingOpenAPISchema.OpenAPISchemaFn + tf.FakeOpenAPIGetter = testingOpenAPISchema.OpenAPIGetter tf.ClientConfigVal = cmdtesting.DefaultClientConfig() ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams() @@ -1084,7 +1110,7 @@ func TestUnstructuredIdempotentApply(t *testing.T) { } path := "/namespaces/test/widgets/widget" - for _, fn := range testingOpenAPISchemaFns { + for _, testingOpenAPISchema := range testingOpenAPISchemas { t.Run("test repeated apply operations on an unstructured object", func(t *testing.T) { tf := cmdtesting.NewTestFactory().WithNamespace("test") defer tf.Cleanup() @@ -1115,7 +1141,8 @@ func TestUnstructuredIdempotentApply(t *testing.T) { } }), } - tf.OpenAPISchemaFunc = fn + tf.OpenAPISchemaFunc = testingOpenAPISchema.OpenAPISchemaFn + tf.FakeOpenAPIGetter = testingOpenAPISchema.OpenAPIGetter tf.ClientConfigVal = cmdtesting.DefaultClientConfig() ioStreams, _, buf, errBuf := genericclioptions.NewTestIOStreams() @@ -1275,7 +1302,7 @@ func TestForceApply(t *testing.T) { "post": 1, } - for _, fn := range testingOpenAPISchemaFns { + for _, testingOpenAPISchema := range testingOpenAPISchemas { t.Run("test apply with --force", func(t *testing.T) { deleted := false isScaledDownToZero := false @@ -1357,7 +1384,8 @@ func TestForceApply(t *testing.T) { } fakeDynamicClient := dynamicfakeclient.NewSimpleDynamicClient(scheme) tf.FakeDynamicClient = fakeDynamicClient - tf.OpenAPISchemaFunc = fn + tf.OpenAPISchemaFunc = testingOpenAPISchema.OpenAPISchemaFn + tf.FakeOpenAPIGetter = testingOpenAPISchema.OpenAPIGetter tf.Client = tf.UnstructuredClient tf.ClientConfigVal = &restclient.Config{} diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/autoscale/autoscale.go b/staging/src/k8s.io/kubectl/pkg/cmd/autoscale/autoscale.go index 27475d5ccf1..a5fc8a2a71c 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/autoscale/autoscale.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/autoscale/autoscale.go @@ -147,7 +147,7 @@ func (o *AutoscaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args if err != nil { return err } - o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) o.createAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) o.builder = f.NewBuilder() o.scaleKindResolver = scale.NewDiscoveryScaleKindResolver(discoveryClient) diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/create/create.go b/staging/src/k8s.io/kubectl/pkg/cmd/create/create.go index d5a9b95c2bf..090f736c6f1 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/create/create.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/create/create.go @@ -206,11 +206,7 @@ func (o *CreateOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) printer, err := o.PrintFlags.ToPrinter() if err != nil { @@ -387,11 +383,7 @@ func (o *CreateSubcommandOptions) Complete(f cmdutil.Factory, cmd *cobra.Command if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_clusterrolebinding.go b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_clusterrolebinding.go index 35b99cb791d..e973dc9517c 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_clusterrolebinding.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_clusterrolebinding.go @@ -131,11 +131,7 @@ func (o *ClusterRoleBindingOptions) Complete(f cmdutil.Factory, cmd *cobra.Comma if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) printer, err := o.PrintFlags.ToPrinter() diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_cronjob.go b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_cronjob.go index a9be3563a01..a7953703da2 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_cronjob.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_cronjob.go @@ -151,11 +151,7 @@ func (o *CreateCronJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, a if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) printer, err := o.PrintFlags.ToPrinter() if err != nil { diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_deployment.go b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_deployment.go index b542c976854..283e8a528f3 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_deployment.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_deployment.go @@ -156,11 +156,7 @@ func (o *CreateDeploymentOptions) Complete(f cmdutil.Factory, cmd *cobra.Command if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) printer, err := o.PrintFlags.ToPrinter() diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_ingress.go b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_ingress.go index 83a2541e6f4..64a0d696ac7 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_ingress.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_ingress.go @@ -62,7 +62,7 @@ var ( Create an ingress with the specified name.`)) ingressExample = templates.Examples(i18n.T(` - # Create a single ingress called 'simple' that directs requests to foo.com/bar to svc + # Create a single ingress called 'simple' that directs requests to foo.com/bar to svc # svc1:8080 with a tls secret "my-cert" kubectl create ingress simple --rule="foo.com/bar=svc1:8080,tls=my-cert" @@ -75,7 +75,7 @@ var ( --annotation ingress.annotation2=bla # Create an ingress with the same host and multiple paths - kubectl create ingress multipath --class=default \ + kubectl create ingress multipath --class=default \ --rule="foo.com/=svc:port" \ --rule="foo.com/admin/=svcadmin:portadmin" @@ -88,11 +88,11 @@ var ( kubectl create ingress ingtls --class=default \ --rule="foo.com/=svc:https,tls" \ --rule="foo.com/path/subpath*=othersvc:8080" - + # Create an ingress with TLS enabled using a specific secret and pathType as Prefix kubectl create ingress ingsecret --class=default \ --rule="foo.com/*=svc:8080,tls=secret1" - + # Create an ingress with a default backend kubectl create ingress ingdefault --class=default \ --default-backend=defaultsvc:http \ @@ -198,11 +198,7 @@ func (o *CreateIngressOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, a if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) printer, err := o.PrintFlags.ToPrinter() diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_job.go b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_job.go index b6133434730..207edf7da44 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_job.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_job.go @@ -146,11 +146,7 @@ func (o *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) printer, err := o.PrintFlags.ToPrinter() if err != nil { diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_priorityclass.go b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_priorityclass.go index 65125a4d0e1..39f490409b1 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_priorityclass.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_priorityclass.go @@ -138,11 +138,7 @@ func (o *PriorityClassOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, a if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) printer, err := o.PrintFlags.ToPrinter() diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_quota.go b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_quota.go index ddf5d203eb4..df5444a2e94 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_quota.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_quota.go @@ -136,11 +136,7 @@ func (o *QuotaOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []strin if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resourcecli.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resourcecli.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() if err != nil { diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_role.go b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_role.go index 9e379ae7216..c34cbd7f4d6 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_role.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_role.go @@ -250,11 +250,7 @@ func (o *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) o.OutputFormat = cmdutil.GetFlagString(cmd, "output") o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_rolebinding.go b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_rolebinding.go index d2932d271b3..77012da75bd 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_rolebinding.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_rolebinding.go @@ -140,11 +140,7 @@ func (o *RoleBindingOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicCient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicCient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) printer, err := o.PrintFlags.ToPrinter() if err != nil { diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_service.go b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_service.go index 8661c712df8..09b776aaf48 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_service.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_service.go @@ -118,11 +118,7 @@ func (o *ServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [] if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) printer, err := o.PrintFlags.ToPrinter() diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_serviceaccount.go b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_serviceaccount.go index 0634f41d265..f35649a694e 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/create/create_serviceaccount.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/create/create_serviceaccount.go @@ -128,11 +128,7 @@ func (o *ServiceAccountOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, arg if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() if err != nil { diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/delete/delete.go b/staging/src/k8s.io/kubectl/pkg/cmd/delete/delete.go index 1ba0ceae848..022c9917181 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/delete/delete.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/delete/delete.go @@ -188,11 +188,7 @@ func (o *DeleteOptions) Complete(f cmdutil.Factory, args []string, cmd *cobra.Co if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) if len(o.Raw) == 0 { r := f.NewBuilder(). diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/diff/diff.go b/staging/src/k8s.io/kubectl/pkg/cmd/diff/diff.go index d2045c2cb18..b1310b04f4d 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/diff/diff.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/diff/diff.go @@ -487,7 +487,7 @@ func (o *DiffOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { return err } - o.DryRunVerifier = resource.NewDryRunVerifier(o.DynamicClient, o.DiscoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(o.DynamicClient, f.OpenAPIGetter()) o.CmdNamespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() if err != nil { diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/drain/drain.go b/staging/src/k8s.io/kubectl/pkg/cmd/drain/drain.go index d6657b83a49..1d63eb105da 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/drain/drain.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/drain/drain.go @@ -222,11 +222,7 @@ func (o *DrainCmdOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [ if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.drainer.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.drainer.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) if o.drainer.Client, err = f.KubernetesClientSet(); err != nil { return err diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/expose/expose.go b/staging/src/k8s.io/kubectl/pkg/cmd/expose/expose.go index 48cc4bd3f3f..008dcb32c34 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/expose/expose.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/expose/expose.go @@ -178,11 +178,7 @@ func (o *ExposeServiceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) e if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) printer, err := o.PrintFlags.ToPrinter() diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/label/label.go b/staging/src/k8s.io/kubectl/pkg/cmd/label/label.go index 1b2cbded74c..b3de4f24a23 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/label/label.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/label/label.go @@ -175,11 +175,7 @@ func (o *LabelOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.dryRunStrategy) o.ToPrinter = func(operation string) (printers.ResourcePrinter, error) { diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/patch/patch.go b/staging/src/k8s.io/kubectl/pkg/cmd/patch/patch.go index bd2ed51fa57..fe563ecbc3f 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/patch/patch.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/patch/patch.go @@ -167,11 +167,7 @@ func (o *PatchOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) return nil } diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/replace/replace.go b/staging/src/k8s.io/kubectl/pkg/cmd/replace/replace.go index ff4a9be31ed..3a7d3224bd0 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/replace/replace.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/replace/replace.go @@ -156,11 +156,7 @@ func (o *ReplaceOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [] if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) printer, err := o.PrintFlags.ToPrinter() diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/rollout/rollout_undo.go b/staging/src/k8s.io/kubectl/pkg/cmd/rollout/rollout_undo.go index e2e31955678..783ace37952 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/rollout/rollout_undo.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/rollout/rollout_undo.go @@ -114,11 +114,7 @@ func (o *UndoOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []str if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) if o.Namespace, o.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace(); err != nil { return err diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/run/run.go b/staging/src/k8s.io/kubectl/pkg/cmd/run/run.go index 90d67ef7bf8..4beb60cbc4d 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/run/run.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/run/run.go @@ -226,11 +226,7 @@ func (o *RunOptions) Complete(f cmdutil.Factory, cmd *cobra.Command) error { if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) attachFlag := cmd.Flags().Lookup("attach") if !attachFlag.Changed && o.Interactive { diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/scale/scale.go b/staging/src/k8s.io/kubectl/pkg/cmd/scale/scale.go index 027473ac26b..f46be57e8fd 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/scale/scale.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/scale/scale.go @@ -157,11 +157,7 @@ func (o *ScaleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) o.namespace, o.enforceNamespace, err = f.ToRawKubeConfigLoader().Namespace() if err != nil { diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/set/set_env.go b/staging/src/k8s.io/kubectl/pkg/cmd/set/set_env.go index ebd54e4f71d..9c90f3f3467 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/set/set_env.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/set/set_env.go @@ -229,11 +229,7 @@ func (o *EnvOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []stri if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.dryRunStrategy) printer, err := o.PrintFlags.ToPrinter() diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/set/set_image.go b/staging/src/k8s.io/kubectl/pkg/cmd/set/set_image.go index 63279068203..5adcf9250b9 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/set/set_image.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/set/set_image.go @@ -149,11 +149,7 @@ func (o *SetImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [ if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) o.Output = cmdutil.GetFlagString(cmd, "output") o.ResolveImage = resolveImageFunc diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/set/set_resources.go b/staging/src/k8s.io/kubectl/pkg/cmd/set/set_resources.go index eb8f858df86..45c3c109c3d 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/set/set_resources.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/set/set_resources.go @@ -161,11 +161,7 @@ func (o *SetResourcesOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, ar if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) printer, err := o.PrintFlags.ToPrinter() diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/set/set_selector.go b/staging/src/k8s.io/kubectl/pkg/cmd/set/set_selector.go index 913ab76b11b..a4c40db21fc 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/set/set_selector.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/set/set_selector.go @@ -140,11 +140,7 @@ func (o *SetSelectorOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, arg if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) o.resources, o.selector, err = getResourcesAndSelector(args) if err != nil { diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/set/set_serviceaccount.go b/staging/src/k8s.io/kubectl/pkg/cmd/set/set_serviceaccount.go index 10276f84da7..fe0d5c9c746 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/set/set_serviceaccount.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/set/set_serviceaccount.go @@ -142,11 +142,7 @@ func (o *SetServiceAccountOptions) Complete(f cmdutil.Factory, cmd *cobra.Comman if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.dryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) o.output = cmdutil.GetFlagString(cmd, "output") o.updatePodSpecForObject = polymorphichelpers.UpdatePodSpecForObjectFn diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/set/set_subject.go b/staging/src/k8s.io/kubectl/pkg/cmd/set/set_subject.go index 4b989fa4ff6..ec6974fe703 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/set/set_subject.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/set/set_subject.go @@ -132,11 +132,7 @@ func (o *SubjectOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args [] if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) printer, err := o.PrintFlags.ToPrinter() diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/taint/taint.go b/staging/src/k8s.io/kubectl/pkg/cmd/taint/taint.go index 5e355bd225c..9430028e628 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/taint/taint.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/taint/taint.go @@ -147,11 +147,7 @@ func (o *TaintOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st if err != nil { return err } - discoveryClient, err := f.ToDiscoveryClient() - if err != nil { - return err - } - o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, discoveryClient) + o.DryRunVerifier = resource.NewDryRunVerifier(dynamicClient, f.OpenAPIGetter()) cmdutil.PrintFlagsWithDryRunStrategy(o.PrintFlags, o.DryRunStrategy) // retrieves resource and taint args from args diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/testing/fake.go b/staging/src/k8s.io/kubectl/pkg/cmd/testing/fake.go index 0e77b267483..db0ac18bd4f 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/testing/fake.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/testing/fake.go @@ -50,6 +50,8 @@ import ( "k8s.io/kubectl/pkg/util/openapi" openapitesting "k8s.io/kubectl/pkg/util/openapi/testing" "k8s.io/kubectl/pkg/validation" + + openapi_v2 "github.com/googleapis/gnostic/openapiv2" ) // InternalType is the schema for internal type @@ -398,6 +400,7 @@ type TestFactory struct { UnstructuredClientForMappingFunc resource.FakeClientFunc OpenAPISchemaFunc func() (openapi.Resources, error) + FakeOpenAPIGetter discovery.OpenAPISchemaInterface } // NewTestFactory returns an initialized TestFactory instance @@ -502,6 +505,23 @@ func (f *TestFactory) OpenAPISchema() (openapi.Resources, error) { return openapitesting.EmptyResources{}, nil } +type EmptyOpenAPI struct{} + +func (EmptyOpenAPI) OpenAPISchema() (*openapi_v2.Document, error) { + return &openapi_v2.Document{}, nil +} + +func (f *TestFactory) OpenAPIGetter() discovery.OpenAPISchemaInterface { + if f.FakeOpenAPIGetter != nil { + return f.FakeOpenAPIGetter + } + client, err := f.ToDiscoveryClient() + if err != nil { + return EmptyOpenAPI{} + } + return client +} + // NewBuilder returns an initialized resource.Builder instance func (f *TestFactory) NewBuilder() *resource.Builder { return resource.NewFakeBuilder( diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/util/factory.go b/staging/src/k8s.io/kubectl/pkg/cmd/util/factory.go index d9df0bf3b51..9235b4b0ab3 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/util/factory.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/util/factory.go @@ -20,6 +20,7 @@ import ( "k8s.io/apimachinery/pkg/api/meta" "k8s.io/cli-runtime/pkg/genericclioptions" "k8s.io/cli-runtime/pkg/resource" + "k8s.io/client-go/discovery" "k8s.io/client-go/dynamic" "k8s.io/client-go/kubernetes" restclient "k8s.io/client-go/rest" @@ -61,6 +62,8 @@ type Factory interface { // Returns a schema that can validate objects stored on disk. Validator(validate bool) (validation.Schema, error) - // OpenAPISchema returns the schema openapi schema definition + // OpenAPISchema returns the parsed openapi schema definition OpenAPISchema() (openapi.Resources, error) + // OpenAPIGetter returns a getter for the openapi schema document + OpenAPIGetter() discovery.OpenAPISchemaInterface } diff --git a/staging/src/k8s.io/kubectl/pkg/cmd/util/factory_client_access.go b/staging/src/k8s.io/kubectl/pkg/cmd/util/factory_client_access.go index e4cf2da0734..2b9074cbac8 100644 --- a/staging/src/k8s.io/kubectl/pkg/cmd/util/factory_client_access.go +++ b/staging/src/k8s.io/kubectl/pkg/cmd/util/factory_client_access.go @@ -19,6 +19,7 @@ limitations under the License. package util import ( + "errors" "sync" corev1 "k8s.io/api/core/v1" @@ -38,20 +39,17 @@ import ( type factoryImpl struct { clientGetter genericclioptions.RESTClientGetter - // openAPIGetter loads and caches openapi specs - openAPIGetter openAPIGetter -} - -type openAPIGetter struct { - once sync.Once - getter openapi.Getter + // Caches OpenAPI document and parsed resources + openAPIParser *openapi.CachedOpenAPIParser + openAPIGetter *openapi.CachedOpenAPIGetter + parser sync.Once + getter sync.Once } func NewFactory(clientGetter genericclioptions.RESTClientGetter) Factory { if clientGetter == nil { panic("attempt to instantiate client_access_factory with nil clientGetter") } - f := &factoryImpl{ clientGetter: clientGetter, } @@ -159,19 +157,32 @@ func (f *factoryImpl) Validator(validate bool) (validation.Schema, error) { }, nil } -// OpenAPISchema returns metadata and structural information about Kubernetes object definitions. +// OpenAPISchema returns metadata and structural information about +// Kubernetes object definitions. func (f *factoryImpl) OpenAPISchema() (openapi.Resources, error) { - discovery, err := f.clientGetter.ToDiscoveryClient() - if err != nil { - return nil, err + openAPIGetter := f.OpenAPIGetter() + if openAPIGetter == nil { + return nil, errors.New("no openapi getter") } - // Lazily initialize the OpenAPIGetter once - f.openAPIGetter.once.Do(func() { - // Create the caching OpenAPIGetter - f.openAPIGetter.getter = openapi.NewOpenAPIGetter(discovery) + // Lazily initialize the OpenAPIParser once + f.parser.Do(func() { + // Create the caching OpenAPIParser + f.openAPIParser = openapi.NewOpenAPIParser(f.OpenAPIGetter()) }) - // Delegate to the OpenAPIGetter - return f.openAPIGetter.getter.Get() + // Delegate to the OpenAPIPArser + return f.openAPIParser.Parse() +} + +func (f *factoryImpl) OpenAPIGetter() discovery.OpenAPISchemaInterface { + discovery, err := f.clientGetter.ToDiscoveryClient() + if err != nil { + return nil + } + f.getter.Do(func() { + f.openAPIGetter = openapi.NewOpenAPIGetter(discovery) + }) + + return f.openAPIGetter } diff --git a/staging/src/k8s.io/kubectl/pkg/util/openapi/openapi_getter.go b/staging/src/k8s.io/kubectl/pkg/util/openapi/openapi_getter.go index d5c9476a02b..e0f82eba9c5 100644 --- a/staging/src/k8s.io/kubectl/pkg/util/openapi/openapi_getter.go +++ b/staging/src/k8s.io/kubectl/pkg/util/openapi/openapi_getter.go @@ -19,47 +19,64 @@ package openapi import ( "sync" + openapi_v2 "github.com/googleapis/gnostic/openapiv2" "k8s.io/client-go/discovery" ) -// synchronizedOpenAPIGetter fetches the openapi schema once and then caches it in memory -type synchronizedOpenAPIGetter struct { +// CachedOpenAPIGetter fetches the openapi schema once and then caches it in memory +type CachedOpenAPIGetter struct { + openAPIClient discovery.OpenAPISchemaInterface + // Cached results sync.Once - openAPISchema Resources + openAPISchema *openapi_v2.Document err error - - openAPIClient discovery.OpenAPISchemaInterface } -var _ Getter = &synchronizedOpenAPIGetter{} - -// Getter is an interface for fetching openapi specs and parsing them into an Resources struct -type Getter interface { - // OpenAPIData returns the parsed OpenAPIData - Get() (Resources, error) -} +var _ discovery.OpenAPISchemaInterface = &CachedOpenAPIGetter{} // NewOpenAPIGetter returns an object to return OpenAPIDatas which reads // from a server, and then stores in memory for subsequent invocations -func NewOpenAPIGetter(openAPIClient discovery.OpenAPISchemaInterface) Getter { - return &synchronizedOpenAPIGetter{ +func NewOpenAPIGetter(openAPIClient discovery.OpenAPISchemaInterface) *CachedOpenAPIGetter { + return &CachedOpenAPIGetter{ openAPIClient: openAPIClient, } } -// Resources implements Getter -func (g *synchronizedOpenAPIGetter) Get() (Resources, error) { +// OpenAPISchema implements OpenAPISchemaInterface. +func (g *CachedOpenAPIGetter) OpenAPISchema() (*openapi_v2.Document, error) { g.Do(func() { - s, err := g.openAPIClient.OpenAPISchema() - if err != nil { - g.err = err - return - } - - g.openAPISchema, g.err = NewOpenAPIData(s) + g.openAPISchema, g.err = g.openAPIClient.OpenAPISchema() }) - // Return the save result + // Return the saved result. return g.openAPISchema, g.err } + +type CachedOpenAPIParser struct { + openAPIClient discovery.OpenAPISchemaInterface + + // Cached results + sync.Once + openAPIResources Resources + err error +} + +func NewOpenAPIParser(openAPIClient discovery.OpenAPISchemaInterface) *CachedOpenAPIParser { + return &CachedOpenAPIParser{ + openAPIClient: openAPIClient, + } +} + +func (p *CachedOpenAPIParser) Parse() (Resources, error) { + p.Do(func() { + oapi, err := p.openAPIClient.OpenAPISchema() + if err != nil { + p.err = err + return + } + p.openAPIResources, p.err = NewOpenAPIData(oapi) + }) + + return p.openAPIResources, p.err +} diff --git a/staging/src/k8s.io/kubectl/pkg/util/openapi/openapi_getter_test.go b/staging/src/k8s.io/kubectl/pkg/util/openapi/openapi_getter_test.go index 4414194cd1f..3e48f5d5d35 100644 --- a/staging/src/k8s.io/kubectl/pkg/util/openapi/openapi_getter_test.go +++ b/staging/src/k8s.io/kubectl/pkg/util/openapi/openapi_getter_test.go @@ -40,12 +40,12 @@ func (f *FakeCounter) OpenAPISchema() (*openapi_v2.Document, error) { var _ = Describe("Getting the Resources", func() { var client FakeCounter - var instance openapi.Getter + var instance *openapi.CachedOpenAPIParser var expectedData openapi.Resources BeforeEach(func() { client = FakeCounter{} - instance = openapi.NewOpenAPIGetter(&client) + instance = openapi.NewOpenAPIParser(openapi.NewOpenAPIGetter(&client)) var err error expectedData, err = openapi.NewOpenAPIData(nil) Expect(err).To(BeNil()) @@ -55,12 +55,12 @@ var _ = Describe("Getting the Resources", func() { It("should return the same data for multiple calls", func() { Expect(client.Calls).To(Equal(0)) - result, err := instance.Get() + result, err := instance.Parse() Expect(err).To(BeNil()) Expect(result).To(Equal(expectedData)) Expect(client.Calls).To(Equal(1)) - result, err = instance.Get() + result, err = instance.Parse() Expect(err).To(BeNil()) Expect(result).To(Equal(expectedData)) // No additional client calls expected @@ -73,11 +73,11 @@ var _ = Describe("Getting the Resources", func() { Expect(client.Calls).To(Equal(0)) client.Err = fmt.Errorf("expected error") - _, err := instance.Get() + _, err := instance.Parse() Expect(err).To(Equal(client.Err)) Expect(client.Calls).To(Equal(1)) - _, err = instance.Get() + _, err = instance.Parse() Expect(err).To(Equal(client.Err)) // No additional client calls expected Expect(client.Calls).To(Equal(1))