From 8a7b2fdda33b91dbcfff5a3e5a7b5a6daf15eb65 Mon Sep 17 00:00:00 2001 From: juanvallejo Date: Thu, 5 Apr 2018 18:39:17 -0400 Subject: [PATCH] begin wiring printopts through complete commands --- pkg/kubectl/cmd/create/BUILD | 2 + pkg/kubectl/cmd/create/create.go | 97 +++++++++--- pkg/kubectl/cmd/create/create_clusterrole.go | 14 +- .../cmd/create/create_clusterrolebinding.go | 36 +++-- pkg/kubectl/cmd/create/create_configmap.go | 36 +++-- pkg/kubectl/cmd/create/create_deployment.go | 51 ++++--- .../cmd/create/create_deployment_test.go | 24 ++- pkg/kubectl/cmd/create/create_job.go | 31 +++- pkg/kubectl/cmd/create/create_job_test.go | 21 ++- pkg/kubectl/cmd/create/create_namespace.go | 36 +++-- pkg/kubectl/cmd/create/create_pdb.go | 35 +++-- pkg/kubectl/cmd/create/create_pdb_test.go | 26 +++- .../cmd/create/create_priorityclass.go | 34 +++-- .../cmd/create/create_priorityclass_test.go | 26 +++- pkg/kubectl/cmd/create/create_quota.go | 35 +++-- pkg/kubectl/cmd/create/create_role.go | 30 ++-- pkg/kubectl/cmd/create/create_role_test.go | 16 +- pkg/kubectl/cmd/create/create_rolebinding.go | 34 +++-- pkg/kubectl/cmd/create/create_secret.go | 108 +++++++++---- pkg/kubectl/cmd/create/create_service.go | 144 ++++++++++++------ .../cmd/create/create_serviceaccount.go | 36 +++-- pkg/kubectl/cmd/create/flags.go | 81 ++++++++++ pkg/kubectl/cmd/set/set_image.go | 1 - pkg/printers/BUILD | 1 + pkg/printers/flags.go | 24 +-- pkg/printers/json_yaml_flags.go | 13 +- pkg/printers/jsonpath_flags.go | 14 +- pkg/printers/jsonpath_flags_test.go | 10 +- pkg/printers/kube_template_flags.go | 6 +- pkg/printers/name_flags.go | 6 + pkg/printers/printers.go | 5 +- pkg/printers/template_flags.go | 14 +- pkg/printers/template_flags_test.go | 10 +- 33 files changed, 762 insertions(+), 295 deletions(-) create mode 100644 pkg/kubectl/cmd/create/flags.go diff --git a/pkg/kubectl/cmd/create/BUILD b/pkg/kubectl/cmd/create/BUILD index 9f42f29e857..a10104449a5 100644 --- a/pkg/kubectl/cmd/create/BUILD +++ b/pkg/kubectl/cmd/create/BUILD @@ -18,6 +18,7 @@ go_library( "create_secret.go", "create_service.go", "create_serviceaccount.go", + "flags.go", ], importpath = "k8s.io/kubernetes/pkg/kubectl/cmd/create", visibility = ["//build/visible_to:pkg_kubectl_cmd_create_CONSUMERS"], @@ -28,6 +29,7 @@ go_library( "//pkg/kubectl/cmd/util/editor:go_default_library", "//pkg/kubectl/resource:go_default_library", "//pkg/kubectl/util/i18n:go_default_library", + "//pkg/printers:go_default_library", "//vendor/github.com/spf13/cobra:go_default_library", "//vendor/k8s.io/api/batch/v1:go_default_library", "//vendor/k8s.io/api/batch/v1beta1:go_default_library", diff --git a/pkg/kubectl/cmd/create/create.go b/pkg/kubectl/cmd/create/create.go index 1ef0a86c66a..66bf40555db 100644 --- a/pkg/kubectl/cmd/create/create.go +++ b/pkg/kubectl/cmd/create/create.go @@ -28,6 +28,7 @@ import ( "net/url" "k8s.io/apimachinery/pkg/api/meta" + kruntime "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/kubernetes/pkg/kubectl" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" @@ -38,6 +39,11 @@ import ( ) type CreateOptions struct { + PrintFlags *PrintFlags + PrintObj func(obj kruntime.Object) error + + DryRun bool + FilenameOptions resource.FilenameOptions Selector string EditBeforeCreate bool @@ -65,6 +71,8 @@ var ( func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { options := &CreateOptions{ + PrintFlags: NewPrintFlags("created"), + Out: out, ErrOut: errOut, } @@ -81,6 +89,7 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { defaultRunFunc(cmd, args) return } + cmdutil.CheckErr(options.Complete(cmd)) cmdutil.CheckErr(options.ValidateArgs(cmd, args)) cmdutil.CheckErr(options.RunCreate(f, cmd)) }, @@ -90,7 +99,6 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { cmdutil.AddFilenameOptionFlags(cmd, &options.FilenameOptions, usage) cmd.MarkFlagRequired("filename") cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmd.Flags().BoolVar(&options.EditBeforeCreate, "edit", options.EditBeforeCreate, "Edit the API resource before creating") cmd.Flags().Bool("windows-line-endings", runtime.GOOS == "windows", "Only relevant if --edit=true. Defaults to the line ending native to your platform.") @@ -101,6 +109,8 @@ func NewCmdCreate(f cmdutil.Factory, out, errOut io.Writer) *cobra.Command { cmd.Flags().StringVarP(&options.Selector, "selector", "l", options.Selector, "Selector (label query) to filter on, supports '=', '==', and '!='.(e.g. -l key1=value1,key2=value2)") cmd.Flags().StringVar(&options.Raw, "raw", options.Raw, "Raw URI to POST to the server. Uses the transport specified by the kubeconfig file.") + options.PrintFlags.AddFlags(cmd) + // create subcommands cmd.AddCommand(NewCmdCreateNamespace(f, out)) cmd.AddCommand(NewCmdCreateQuota(f, out)) @@ -150,6 +160,24 @@ func (o *CreateOptions) ValidateArgs(cmd *cobra.Command, args []string) error { return nil } +func (o *CreateOptions) Complete(cmd *cobra.Command) error { + o.DryRun = cmdutil.GetDryRunFlag(cmd) + + if o.DryRun { + o.PrintFlags.Complete("%s (dry run)") + } + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.PrintObj = func(obj kruntime.Object) error { + return printer.PrintObj(obj, o.Out) + } + + return nil +} + func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error { // raw only makes sense for a single file resource multiple objects aren't likely to do what you want. // the validator enforces this, so @@ -184,9 +212,6 @@ func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error { return err } - dryRun := cmdutil.GetDryRunFlag(cmd) - output := cmdutil.GetFlagString(cmd, "output") - count := 0 err = r.Visit(func(info *resource.Info, err error) error { if err != nil { @@ -202,7 +227,7 @@ func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error { } } - if !dryRun { + if !o.DryRun { if err := createAndRefresh(info); err != nil { return cmdutil.AddSourceToErr("creating", info.Source, err) } @@ -210,13 +235,7 @@ func (o *CreateOptions) RunCreate(f cmdutil.Factory, cmd *cobra.Command) error { count++ - shortOutput := output == "name" - if len(output) > 0 && !shortOutput { - return cmdutil.PrintObject(cmd, info.Object, o.Out) - } - - cmdutil.PrintSuccess(shortOutput, o.Out, info.Object, dryRun, "created") - return nil + return o.PrintObj(info.Object) }) if err != nil { return err @@ -295,17 +314,52 @@ func NameFromCommandArgs(cmd *cobra.Command, args []string) (string, error) { // CreateSubcommandOptions is an options struct to support create subcommands type CreateSubcommandOptions struct { + // PrintFlags holds options necessary for obtaining a printer + PrintFlags *PrintFlags // Name of resource being created Name string // StructuredGenerator is the resource generator for the object being created StructuredGenerator kubectl.StructuredGenerator // DryRun is true if the command should be simulated but not run against the server - DryRun bool - OutputFormat string + DryRun bool + CreateAnnotation bool + + PrintObj func(obj kruntime.Object) error + + CmdOut io.Writer + CmdErr io.Writer } +func (o *CreateSubcommandOptions) Complete(cmd *cobra.Command, args []string, generator kubectl.StructuredGenerator) error { + name, err := NameFromCommandArgs(cmd, args) + if err != nil { + return err + } + + o.Name = name + o.StructuredGenerator = generator + o.DryRun = cmdutil.GetDryRunFlag(cmd) + o.CreateAnnotation = cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag) + + if o.DryRun { + o.PrintFlags.Complete("%s (dry run)") + } + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + + o.PrintObj = func(obj kruntime.Object) error { + return printer.PrintObj(obj, o.CmdOut) + } + + return nil +} + +// TODO(juanvallejo): remove dependency on factory here. Complete necessary bits +// from it in the Complete() method. // RunCreateSubcommand executes a create subcommand using the specified options -func RunCreateSubcommand(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, options *CreateSubcommandOptions) error { +func RunCreateSubcommand(f cmdutil.Factory, options *CreateSubcommandOptions) error { namespace, nsOverriden, err := f.DefaultNamespace() if err != nil { return err @@ -338,25 +392,22 @@ func RunCreateSubcommand(f cmdutil.Factory, cmd *cobra.Command, out io.Writer, o if err != nil { return err } - if err := kubectl.CreateOrUpdateAnnotation(cmdutil.GetFlagBool(cmd, cmdutil.ApplyAnnotationsFlag), info, cmdutil.InternalVersionJSONEncoder()); err != nil { + if err := kubectl.CreateOrUpdateAnnotation(options.CreateAnnotation, info, cmdutil.InternalVersionJSONEncoder()); err != nil { return err } - obj = info.Object obj, err = resource.NewHelper(client, mapping).Create(namespace, false, info.Object) if err != nil { return err } + + // ensure we pass a versioned object to the printer + obj = info.AsVersioned() } else { if meta, err := meta.Accessor(obj); err == nil && nsOverriden { meta.SetNamespace(namespace) } } - if useShortOutput := options.OutputFormat == "name"; useShortOutput || len(options.OutputFormat) == 0 { - cmdutil.PrintSuccess(useShortOutput, out, obj, options.DryRun, "created") - return nil - } - - return cmdutil.PrintObject(cmd, obj, out) + return options.PrintObj(obj) } diff --git a/pkg/kubectl/cmd/create/create_clusterrole.go b/pkg/kubectl/cmd/create/create_clusterrole.go index e30e84e034c..015902f9576 100644 --- a/pkg/kubectl/cmd/create/create_clusterrole.go +++ b/pkg/kubectl/cmd/create/create_clusterrole.go @@ -62,7 +62,8 @@ type CreateClusterRoleOptions struct { func NewCmdCreateClusterRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { c := &CreateClusterRoleOptions{ CreateRoleOptions: &CreateRoleOptions{ - Out: cmdOut, + PrintFlags: NewPrintFlags("created"), + Out: cmdOut, }, } cmd := &cobra.Command{ @@ -77,9 +78,11 @@ func NewCmdCreateClusterRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command cmdutil.CheckErr(c.RunCreateRole()) }, } + + c.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddDryRunFlag(cmd) cmd.Flags().StringSliceVar(&c.Verbs, "verb", c.Verbs, "Verb that applies to the resources contained in the rule") cmd.Flags().StringSliceVar(&c.NonResourceURLs, "non-resource-url", c.NonResourceURLs, "A partial url that user should have access to.") @@ -172,10 +175,5 @@ func (c *CreateClusterRoleOptions) RunCreateRole() error { } } - if useShortOutput := c.OutputFormat == "name"; useShortOutput || len(c.OutputFormat) == 0 { - cmdutil.PrintSuccess(useShortOutput, c.Out, clusterRole, c.DryRun, "created") - return nil - } - - return c.PrintObject(clusterRole) + return c.PrintObj(clusterRole) } diff --git a/pkg/kubectl/cmd/create/create_clusterrolebinding.go b/pkg/kubectl/cmd/create/create_clusterrolebinding.go index e15c3dddc49..9be08b9a963 100644 --- a/pkg/kubectl/cmd/create/create_clusterrolebinding.go +++ b/pkg/kubectl/cmd/create/create_clusterrolebinding.go @@ -36,8 +36,19 @@ var ( kubectl create clusterrolebinding cluster-admin --clusterrole=cluster-admin --user=user1 --user=user2 --group=group1`)) ) +type ClusterRoleBindingOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // ClusterRoleBinding is a command to ease creating ClusterRoleBindings. func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &ClusterRoleBindingOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "clusterrolebinding NAME --clusterrole=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run]", DisableFlagsInUseLine: true, @@ -45,13 +56,15 @@ func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra. Long: clusterRoleBindingLong, Example: clusterRoleBindingExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateClusterRoleBinding(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.ClusterRoleBindingV1GeneratorName) cmd.Flags().String("clusterrole", "", i18n.T("ClusterRole this ClusterRoleBinding should reference")) cmd.MarkFlagCustom("clusterrole", "__kubectl_get_resource_clusterrole") @@ -61,12 +74,12 @@ func NewCmdCreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra. return cmd } -// CreateClusterRoleBinding is the implementation of the create clusterrolebinding command. -func CreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *ClusterRoleBindingOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.ClusterRoleBindingV1GeneratorName: @@ -80,10 +93,11 @@ func CreateClusterRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Co default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreateClusterRoleBinding is the implementation of the create clusterrolebinding command. +func (o *ClusterRoleBindingOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } diff --git a/pkg/kubectl/cmd/create/create_configmap.go b/pkg/kubectl/cmd/create/create_configmap.go index f8b46eadabb..b3b9fa785ea 100644 --- a/pkg/kubectl/cmd/create/create_configmap.go +++ b/pkg/kubectl/cmd/create/create_configmap.go @@ -57,8 +57,19 @@ var ( kubectl create configmap my-config --from-env-file=path/to/bar.env`)) ) +type ConfigMapOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // ConfigMap is a command to ease creating ConfigMaps. func NewCmdCreateConfigMap(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &ConfigMapOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "configmap NAME [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]", DisableFlagsInUseLine: true, @@ -67,13 +78,15 @@ func NewCmdCreateConfigMap(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { Long: configMapLong, Example: configMapExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateConfigMap(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.ConfigMapV1GeneratorName) cmd.Flags().StringSlice("from-file", []string{}, "Key file can be specified using its file path, in which case file basename will be used as configmap key, or optionally with a key and file path, in which case the given key will be used. Specifying a directory will iterate each named file in the directory whose basename is a valid configmap key.") cmd.Flags().StringArray("from-literal", []string{}, "Specify a key and literal value to insert in configmap (i.e. mykey=somevalue)") @@ -82,12 +95,12 @@ func NewCmdCreateConfigMap(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { return cmd } -// CreateConfigMap is the implementation of the create configmap command. -func CreateConfigMap(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *ConfigMapOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.ConfigMapV1GeneratorName: @@ -101,10 +114,11 @@ func CreateConfigMap(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreateConfigMap is the implementation of the create configmap command. +func (o *ConfigMapOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } diff --git a/pkg/kubectl/cmd/create/create_deployment.go b/pkg/kubectl/cmd/create/create_deployment.go index 96f5c4d27ff..8461ab40584 100644 --- a/pkg/kubectl/cmd/create/create_deployment.go +++ b/pkg/kubectl/cmd/create/create_deployment.go @@ -36,10 +36,22 @@ var ( kubectl create deployment my-dep --image=busybox`)) ) +type DeploymentOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreateDeployment is a macro command to create a new deployment. // This command is better known to users as `kubectl create deployment`. // Note that this command overlaps significantly with the `kubectl run` command. func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra.Command { + options := &DeploymentOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + CmdErr: cmdErr, + }, + } + cmd := &cobra.Command{ Use: "deployment NAME --image=image [--dry-run]", DisableFlagsInUseLine: true, @@ -48,13 +60,15 @@ func NewCmdCreateDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer) *cobra. Long: deploymentLong, Example: deploymentExample, Run: func(cmd *cobra.Command, args []string) { - err := createDeployment(f, cmdOut, cmdErr, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(f, cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, "") cmd.Flags().StringSlice("image", []string{}, "Image name to run.") cmd.MarkFlagRequired("image") @@ -102,14 +116,8 @@ func generatorFromName( return nil, false } -// createDeployment -// 1. Reads user config values from Cobra. -// 2. Sets up the correct Generator object. -// 3. Calls RunCreateSubcommand. -func createDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer, - cmd *cobra.Command, args []string) error { - - deploymentName, err := NameFromCommandArgs(cmd, args) +func (o *DeploymentOpts) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error { + name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } @@ -123,27 +131,30 @@ func createDeployment(f cmdutil.Factory, cmdOut, cmdErr io.Writer, if len(generatorName) == 0 { generatorName = cmdutil.DeploymentBasicAppsV1GeneratorName - generatorNameTemp, err := cmdutil.FallbackGeneratorNameIfNecessary(generatorName, clientset.Discovery(), cmdErr) + generatorNameTemp, err := cmdutil.FallbackGeneratorNameIfNecessary(generatorName, clientset.Discovery(), o.CreateSubcommandOptions.CmdErr) if err != nil { return err } if generatorNameTemp != generatorName { - cmdutil.Warning(cmdErr, generatorName, generatorNameTemp) + cmdutil.Warning(o.CreateSubcommandOptions.CmdErr, generatorName, generatorNameTemp) } else { generatorName = generatorNameTemp } } imageNames := cmdutil.GetFlagStringSlice(cmd, "image") - generator, ok := generatorFromName(generatorName, imageNames, deploymentName) + generator, ok := generatorFromName(generatorName, imageNames, name) if !ok { return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: deploymentName, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// createDeployment +// 1. Reads user config values from Cobra. +// 2. Sets up the correct Generator object. +// 3. Calls RunCreateSubcommand. +func (o *DeploymentOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } diff --git a/pkg/kubectl/cmd/create/create_deployment_test.go b/pkg/kubectl/cmd/create/create_deployment_test.go index edceac8ec1d..679870d59b7 100644 --- a/pkg/kubectl/cmd/create/create_deployment_test.go +++ b/pkg/kubectl/cmd/create/create_deployment_test.go @@ -123,13 +123,13 @@ func TestCreateDeploymentNoImage(t *testing.T) { defer tf.Cleanup() ns := legacyscheme.Codecs - + fakeDiscovery := "{\"kind\":\"APIResourceList\",\"apiVersion\":\"v1\",\"groupVersion\":\"apps/v1\",\"resources\":[{\"name\":\"deployments\",\"singularName\":\"\",\"namespaced\":true,\"kind\":\"Deployment\",\"verbs\":[\"create\",\"delete\",\"deletecollection\",\"get\",\"list\",\"patch\",\"update\",\"watch\"],\"shortNames\":[\"deploy\"],\"categories\":[\"all\"]}]}" tf.Client = &fake.RESTClient{ NegotiatedSerializer: ns, Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { return &http.Response{ StatusCode: http.StatusOK, - Body: ioutil.NopCloser(&bytes.Buffer{}), + Body: ioutil.NopCloser(bytes.NewBuffer([]byte(fakeDiscovery))), }, nil }), } @@ -137,9 +137,23 @@ func TestCreateDeploymentNoImage(t *testing.T) { tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) - cmd := NewCmdCreateDeployment(tf, buf, buf) - cmd.Flags().Set("dry-run", "true") + errBuff := bytes.NewBuffer([]byte{}) + cmd := NewCmdCreateDeployment(tf, buf, errBuff) cmd.Flags().Set("output", "name") - err := createDeployment(tf, buf, buf, cmd, []string{depName}) + options := &DeploymentOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: buf, + CmdErr: errBuff, + DryRun: true, + }, + } + + err := options.Complete(tf, cmd, []string{depName}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + err = options.Run(tf) assert.Error(t, err, "at least one image must be specified") } diff --git a/pkg/kubectl/cmd/create/create_job.go b/pkg/kubectl/cmd/create/create_job.go index 62ccd1f7c79..b77212f5c4e 100644 --- a/pkg/kubectl/cmd/create/create_job.go +++ b/pkg/kubectl/cmd/create/create_job.go @@ -25,6 +25,7 @@ import ( batchv1 "k8s.io/api/batch/v1" batchv1beta1 "k8s.io/api/batch/v1beta1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" clientbatchv1 "k8s.io/client-go/kubernetes/typed/batch/v1" "k8s.io/kubernetes/pkg/kubectl/cmd/templates" cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" @@ -42,6 +43,10 @@ var ( ) type CreateJobOptions struct { + PrintFlags *PrintFlags + + PrintObj func(obj runtime.Object) error + Name string From string @@ -57,7 +62,8 @@ type CreateJobOptions struct { // NewCmdCreateJob is a command to ease creating Jobs from CronJobs. func NewCmdCreateJob(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { c := &CreateJobOptions{ - Out: cmdOut, + PrintFlags: NewPrintFlags("created"), + Out: cmdOut, } cmd := &cobra.Command{ Use: "job NAME [--from=CRONJOB]", @@ -69,9 +75,11 @@ func NewCmdCreateJob(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { cmdutil.CheckErr(c.RunCreateJob()) }, } + + c.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddDryRunFlag(cmd) cmd.Flags().String("from", "", "The name of the resource to create a Job from (only cronjob is supported).") @@ -100,6 +108,18 @@ func (c *CreateJobOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args c.Cmd = cmd c.OutputFormat = cmdutil.GetFlagString(cmd, "output") + if c.DryRun { + c.PrintFlags.Complete("%s (dry run)") + } + printer, err := c.PrintFlags.ToPrinter() + if err != nil { + return err + } + + c.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, c.Out) + } + return nil } @@ -150,10 +170,5 @@ func (c *CreateJobOptions) createJob(cronJob *batchv1beta1.CronJob) error { } } - if useShortOutput := c.OutputFormat == "name"; useShortOutput || len(c.OutputFormat) == 0 { - cmdutil.PrintSuccess(useShortOutput, c.Out, job, c.DryRun, "created") - return nil - } - - return cmdutil.PrintObject(c.Cmd, job, c.Out) + return c.PrintObj(job) } diff --git a/pkg/kubectl/cmd/create/create_job_test.go b/pkg/kubectl/cmd/create/create_job_test.go index 228a046e19b..f1da73dca59 100644 --- a/pkg/kubectl/cmd/create/create_job_test.go +++ b/pkg/kubectl/cmd/create/create_job_test.go @@ -84,13 +84,24 @@ func TestCreateJobFromCronJob(t *testing.T) { f := cmdtesting.NewTestFactory() defer f.Cleanup() + printFlags := NewPrintFlags("created") + buf := bytes.NewBuffer([]byte{}) cmdOptions := &CreateJobOptions{ - Name: testJobName, - Namespace: testNamespaceName, - Client: clientset.BatchV1(), - Out: buf, - Cmd: NewCmdCreateJob(f, buf), + PrintFlags: printFlags, + Name: testJobName, + Namespace: testNamespaceName, + Client: clientset.BatchV1(), + Out: buf, + Cmd: NewCmdCreateJob(f, buf), + PrintObj: func(obj runtime.Object) error { + p, err := printFlags.ToPrinter() + if err != nil { + return err + } + + return p.PrintObj(obj, buf) + }, } err := cmdOptions.createJob(cronJob) diff --git a/pkg/kubectl/cmd/create/create_namespace.go b/pkg/kubectl/cmd/create/create_namespace.go index f9a97a48c04..cfbf8ec7059 100644 --- a/pkg/kubectl/cmd/create/create_namespace.go +++ b/pkg/kubectl/cmd/create/create_namespace.go @@ -36,8 +36,19 @@ var ( kubectl create namespace my-namespace`)) ) +type NamespaceOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreateNamespace is a macro command to create a new namespace func NewCmdCreateNamespace(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &NamespaceOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "namespace NAME [--dry-run]", DisableFlagsInUseLine: true, @@ -46,24 +57,26 @@ func NewCmdCreateNamespace(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { Long: namespaceLong, Example: namespaceExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateNamespace(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.NamespaceV1GeneratorName) return cmd } -// CreateNamespace implements the behavior to run the create namespace command -func CreateNamespace(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *NamespaceOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.NamespaceV1GeneratorName: @@ -71,10 +84,11 @@ func CreateNamespace(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreateNamespace implements the behavior to run the create namespace command +func (o *NamespaceOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } diff --git a/pkg/kubectl/cmd/create/create_pdb.go b/pkg/kubectl/cmd/create/create_pdb.go index cbae47be2a2..0d64695e26c 100644 --- a/pkg/kubectl/cmd/create/create_pdb.go +++ b/pkg/kubectl/cmd/create/create_pdb.go @@ -41,8 +41,19 @@ var ( kubectl create pdb my-pdb --selector=app=nginx --min-available=50%`)) ) +type PodDisruptionBudgetOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreatePodDisruptionBudget is a macro command to create a new pod disruption budget. func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &PodDisruptionBudgetOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "poddisruptionbudget NAME --selector=SELECTOR --min-available=N [--dry-run]", DisableFlagsInUseLine: true, @@ -51,14 +62,15 @@ func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer) *cobra Long: pdbLong, Example: pdbExample, Run: func(cmd *cobra.Command, args []string) { - err := CreatePodDisruptionBudget(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.PodDisruptionBudgetV2GeneratorName) cmd.Flags().String("min-available", "", i18n.T("The minimum number or percentage of available pods this budget requires.")) @@ -67,12 +79,12 @@ func NewCmdCreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer) *cobra return cmd } -// CreatePodDisruptionBudget implements the behavior to run the create pdb command. -func CreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *PodDisruptionBudgetOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.PodDisruptionBudgetV1GeneratorName: @@ -91,10 +103,11 @@ func CreatePodDisruptionBudget(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreatePodDisruptionBudget implements the behavior to run the create pdb command. +func (o *PodDisruptionBudgetOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } diff --git a/pkg/kubectl/cmd/create/create_pdb_test.go b/pkg/kubectl/cmd/create/create_pdb_test.go index 034a8cb42a5..86d9c1db875 100644 --- a/pkg/kubectl/cmd/create/create_pdb_test.go +++ b/pkg/kubectl/cmd/create/create_pdb_test.go @@ -50,12 +50,34 @@ func TestCreatePdb(t *testing.T) { tf.Namespace = "test" buf := bytes.NewBuffer([]byte{}) + outputFormat := "name" + cmd := NewCmdCreatePodDisruptionBudget(tf, buf) cmd.Flags().Set("min-available", "1") cmd.Flags().Set("selector", "app=rails") cmd.Flags().Set("dry-run", "true") - cmd.Flags().Set("output", "name") - CreatePodDisruptionBudget(tf, buf, cmd, []string{pdbName}) + cmd.Flags().Set("output", outputFormat) + + printFlags := NewPrintFlags("created") + printFlags.OutputFormat = &outputFormat + + options := &PodDisruptionBudgetOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: printFlags, + CmdOut: buf, + Name: pdbName, + }, + } + err := options.Complete(cmd, []string{pdbName}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + err = options.Run(tf) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + expectedOutput := "poddisruptionbudget.policy/" + pdbName + "\n" if buf.String() != expectedOutput { t.Errorf("expected output: %s, but got: %s", expectedOutput, buf.String()) diff --git a/pkg/kubectl/cmd/create/create_priorityclass.go b/pkg/kubectl/cmd/create/create_priorityclass.go index 96e80015692..18e41d2a661 100644 --- a/pkg/kubectl/cmd/create/create_priorityclass.go +++ b/pkg/kubectl/cmd/create/create_priorityclass.go @@ -39,8 +39,19 @@ var ( kubectl create priorityclass default-priority --value=1000 --global-default=true --description="default priority"`)) ) +type PriorityClassOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreatePriorityClass is a macro command to create a new priorityClass. func NewCmdCreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &PriorityClassOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "priorityclass NAME --value=VALUE --global-default=BOOL [--dry-run]", DisableFlagsInUseLine: true, @@ -49,13 +60,15 @@ func NewCmdCreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma Long: pcLong, Example: pcExample, Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(CreatePriorityClass(f, cmdOut, cmd, args)) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.PriorityClassV1Alpha1GeneratorName) cmd.Flags().Int32("value", 0, i18n.T("the value of this priority class.")) @@ -64,12 +77,12 @@ func NewCmdCreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma return cmd } -// CreatePriorityClass implements the behavior to run the create priorityClass command. -func CreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *PriorityClassOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.PriorityClassV1Alpha1GeneratorName: @@ -82,10 +95,11 @@ func CreatePriorityClass(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreatePriorityClass implements the behavior to run the create priorityClass command. +func (o *PriorityClassOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } diff --git a/pkg/kubectl/cmd/create/create_priorityclass_test.go b/pkg/kubectl/cmd/create/create_priorityclass_test.go index bf456095f11..8738a968f31 100644 --- a/pkg/kubectl/cmd/create/create_priorityclass_test.go +++ b/pkg/kubectl/cmd/create/create_priorityclass_test.go @@ -49,13 +49,35 @@ func TestCreatePriorityClass(t *testing.T) { tf.ClientConfigVal = &restclient.Config{} buf := bytes.NewBuffer([]byte{}) + outputFormat := "name" + cmd := NewCmdCreatePriorityClass(tf, buf) cmd.Flags().Set("value", "1000") cmd.Flags().Set("global-default", "true") cmd.Flags().Set("description", "my priority") cmd.Flags().Set("dry-run", "true") - cmd.Flags().Set("output", "name") - CreatePriorityClass(tf, buf, cmd, []string{pcName}) + cmd.Flags().Set("output", outputFormat) + + printFlags := NewPrintFlags("created") + printFlags.OutputFormat = &outputFormat + + options := &PriorityClassOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: printFlags, + CmdOut: buf, + Name: pcName, + }, + } + err := options.Complete(cmd, []string{pcName}) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + + err = options.Run(tf) + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + expectedOutput := "priorityclass.scheduling.k8s.io/" + pcName + "\n" if buf.String() != expectedOutput { t.Errorf("expected output: %s, but got: %s", expectedOutput, buf.String()) diff --git a/pkg/kubectl/cmd/create/create_quota.go b/pkg/kubectl/cmd/create/create_quota.go index bc74aede060..d46c41e1bfd 100644 --- a/pkg/kubectl/cmd/create/create_quota.go +++ b/pkg/kubectl/cmd/create/create_quota.go @@ -39,8 +39,19 @@ var ( kubectl create quota best-effort --hard=pods=100 --scopes=BestEffort`)) ) +type QuotaOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreateQuota is a macro command to create a new quota func NewCmdCreateQuota(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &QuotaOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "quota NAME [--hard=key1=value1,key2=value2] [--scopes=Scope1,Scope2] [--dry-run=bool]", DisableFlagsInUseLine: true, @@ -49,26 +60,27 @@ func NewCmdCreateQuota(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { Long: quotaLong, Example: quotaExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateQuota(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.ResourceQuotaV1GeneratorName) cmd.Flags().String("hard", "", i18n.T("A comma-delimited set of resource=quantity pairs that define a hard limit.")) cmd.Flags().String("scopes", "", i18n.T("A comma-delimited set of quota scopes that must all match each object tracked by the quota.")) return cmd } -// CreateQuota implements the behavior to run the create quota command -func CreateQuota(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *QuotaOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.ResourceQuotaV1GeneratorName: @@ -80,10 +92,11 @@ func CreateQuota(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args [ default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreateQuota implements the behavior to run the create quota command +func (o *QuotaOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } diff --git a/pkg/kubectl/cmd/create/create_role.go b/pkg/kubectl/cmd/create/create_role.go index 36b167e267c..b2256b31d96 100644 --- a/pkg/kubectl/cmd/create/create_role.go +++ b/pkg/kubectl/cmd/create/create_role.go @@ -100,6 +100,8 @@ type ResourceOptions struct { } type CreateRoleOptions struct { + PrintFlags *PrintFlags + Name string Verbs []string Resources []ResourceOptions @@ -111,12 +113,14 @@ type CreateRoleOptions struct { Client clientgorbacv1.RbacV1Interface Mapper meta.RESTMapper Out io.Writer - PrintObject func(obj runtime.Object) error + PrintObj func(obj runtime.Object) error } // Role is a command to ease creating Roles. func NewCmdCreateRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { c := &CreateRoleOptions{ + PrintFlags: NewPrintFlags("created"), + Out: cmdOut, } cmd := &cobra.Command{ @@ -131,9 +135,11 @@ func NewCmdCreateRole(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { cmdutil.CheckErr(c.RunCreateRole()) }, } + + c.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddDryRunFlag(cmd) cmd.Flags().StringSliceVar(&c.Verbs, "verb", c.Verbs, "Verb that applies to the resources contained in the rule") cmd.Flags().StringSlice("resource", []string{}, "Resource that the rule applies to") @@ -198,13 +204,20 @@ func (c *CreateRoleOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args c.DryRun = cmdutil.GetDryRunFlag(cmd) c.OutputFormat = cmdutil.GetFlagString(cmd, "output") - c.Namespace, _, err = f.DefaultNamespace() + if c.DryRun { + c.PrintFlags.Complete("%s (dry run)") + } + printer, err := c.PrintFlags.ToPrinter() if err != nil { return err } + c.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, c.Out) + } - c.PrintObject = func(obj runtime.Object) error { - return cmdutil.PrintObject(cmd, obj, c.Out) + c.Namespace, _, err = f.DefaultNamespace() + if err != nil { + return err } clientset, err := f.KubernetesClientSet() @@ -292,12 +305,7 @@ func (c *CreateRoleOptions) RunCreateRole() error { } } - if useShortOutput := c.OutputFormat == "name"; useShortOutput || len(c.OutputFormat) == 0 { - cmdutil.PrintSuccess(useShortOutput, c.Out, role, c.DryRun, "created") - return nil - } - - return c.PrintObject(role) + return c.PrintObj(role) } func arrayContains(s []string, e string) bool { diff --git a/pkg/kubectl/cmd/create/create_role_test.go b/pkg/kubectl/cmd/create/create_role_test.go index 6596f13cd3b..f04063b454c 100644 --- a/pkg/kubectl/cmd/create/create_role_test.go +++ b/pkg/kubectl/cmd/create/create_role_test.go @@ -371,14 +371,17 @@ func TestComplete(t *testing.T) { expectErr bool }{ "test-missing-name": { - params: []string{}, - roleOptions: &CreateRoleOptions{}, - expectErr: true, + params: []string{}, + roleOptions: &CreateRoleOptions{ + PrintFlags: NewPrintFlags("created"), + }, + expectErr: true, }, "test-duplicate-verbs": { params: []string{roleName}, roleOptions: &CreateRoleOptions{ - Name: roleName, + PrintFlags: NewPrintFlags("created"), + Name: roleName, Verbs: []string{ "get", "watch", @@ -410,7 +413,8 @@ func TestComplete(t *testing.T) { "test-verball": { params: []string{roleName}, roleOptions: &CreateRoleOptions{ - Name: roleName, + PrintFlags: NewPrintFlags("created"), + Name: roleName, Verbs: []string{ "get", "watch", @@ -438,6 +442,7 @@ func TestComplete(t *testing.T) { "test-duplicate-resourcenames": { params: []string{roleName}, roleOptions: &CreateRoleOptions{ + PrintFlags: NewPrintFlags("created"), Name: roleName, Verbs: []string{"*"}, ResourceNames: []string{"foo", "foo"}, @@ -462,6 +467,7 @@ func TestComplete(t *testing.T) { "test-valid-complete-case": { params: []string{roleName}, roleOptions: &CreateRoleOptions{ + PrintFlags: NewPrintFlags("created"), Name: roleName, Verbs: []string{"*"}, ResourceNames: []string{"foo"}, diff --git a/pkg/kubectl/cmd/create/create_rolebinding.go b/pkg/kubectl/cmd/create/create_rolebinding.go index 760ae686000..6bed1adad13 100644 --- a/pkg/kubectl/cmd/create/create_rolebinding.go +++ b/pkg/kubectl/cmd/create/create_rolebinding.go @@ -36,8 +36,19 @@ var ( kubectl create rolebinding admin --clusterrole=admin --user=user1 --user=user2 --group=group1`)) ) +type RoleBindingOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // RoleBinding is a command to ease creating RoleBindings. func NewCmdCreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &RoleBindingOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "rolebinding NAME --clusterrole=NAME|--role=NAME [--user=username] [--group=groupname] [--serviceaccount=namespace:serviceaccountname] [--dry-run]", DisableFlagsInUseLine: true, @@ -45,13 +56,15 @@ func NewCmdCreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command Long: roleBindingLong, Example: roleBindingExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateRoleBinding(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.RoleBindingV1GeneratorName) cmd.Flags().String("clusterrole", "", i18n.T("ClusterRole this RoleBinding should reference")) cmd.Flags().String("role", "", i18n.T("Role this RoleBinding should reference")) @@ -61,11 +74,12 @@ func NewCmdCreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command return cmd } -func CreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *RoleBindingOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.RoleBindingV1GeneratorName: @@ -80,10 +94,10 @@ func CreateRoleBinding(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +func (o *RoleBindingOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } diff --git a/pkg/kubectl/cmd/create/create_secret.go b/pkg/kubectl/cmd/create/create_secret.go index 65a5f7f214d..c9b6d6f4982 100644 --- a/pkg/kubectl/cmd/create/create_secret.go +++ b/pkg/kubectl/cmd/create/create_secret.go @@ -73,8 +73,19 @@ var ( kubectl create secret generic my-secret --from-env-file=path/to/bar.env`)) ) +type SecretGenericOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreateSecretGeneric is a command to create generic secrets from files, directories, or literal values func NewCmdCreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &SecretGenericOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "generic NAME [--type=string] [--from-file=[key=]source] [--from-literal=key1=value1] [--dry-run]", DisableFlagsInUseLine: true, @@ -82,13 +93,15 @@ func NewCmdCreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma Long: secretLong, Example: secretExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateSecretGeneric(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretV1GeneratorName) cmd.Flags().StringSlice("from-file", []string{}, "Key files can be specified using their file path, in which case a default name will be given to them, or optionally with a name and file path, in which case the given name will be used. Specifying a directory will iterate each named file in the directory that is a valid secret key.") cmd.Flags().StringArray("from-literal", []string{}, "Specify a key and literal value to insert in secret (i.e. mykey=somevalue)") @@ -98,12 +111,12 @@ func NewCmdCreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comma return cmd } -// CreateSecretGeneric is the implementation of the create secret generic command -func CreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *SecretGenericOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.SecretV1GeneratorName: @@ -118,12 +131,13 @@ func CreateSecretGeneric(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreateSecretGeneric is the implementation of the create secret generic command +func (o *SecretGenericOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } var ( @@ -147,8 +161,19 @@ var ( kubectl create secret docker-registry my-secret --docker-server=DOCKER_REGISTRY_SERVER --docker-username=DOCKER_USER --docker-password=DOCKER_PASSWORD --docker-email=DOCKER_EMAIL`)) ) +type SecretDockerRegistryOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreateSecretDockerRegistry is a macro command for creating secrets to work with Docker registries func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &SecretDockerRegistryOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "docker-registry NAME --docker-username=user --docker-password=password --docker-email=email [--docker-server=string] [--from-literal=key1=value1] [--dry-run]", DisableFlagsInUseLine: true, @@ -156,13 +181,15 @@ func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer) *cobr Long: secretForDockerRegistryLong, Example: secretForDockerRegistryExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateSecretDockerRegistry(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretForDockerRegistryV1GeneratorName) cmd.Flags().String("docker-username", "", i18n.T("Username for Docker registry authentication")) cmd.MarkFlagRequired("docker-username") @@ -177,12 +204,12 @@ func NewCmdCreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer) *cobr return cmd } -// CreateSecretDockerRegistry is the implementation of the create secret docker-registry command -func CreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *SecretDockerRegistryOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + fromFileFlag := cmdutil.GetFlagStringSlice(cmd, "from-file") if len(fromFileFlag) == 0 { requiredFlags := []string{"docker-username", "docker-password", "docker-server"} @@ -208,12 +235,13 @@ func CreateSecretDockerRegistry(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra. default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreateSecretDockerRegistry is the implementation of the create secret docker-registry command +func (o *SecretDockerRegistryOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } var ( @@ -228,8 +256,19 @@ var ( kubectl create secret tls tls-secret --cert=path/to/tls.cert --key=path/to/tls.key`)) ) +type SecretTLSOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreateSecretTLS is a macro command for creating secrets to work with Docker registries func NewCmdCreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &SecretTLSOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "tls NAME --cert=path/to/cert/file --key=path/to/key/file [--dry-run]", DisableFlagsInUseLine: true, @@ -237,13 +276,15 @@ func NewCmdCreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { Long: secretForTLSLong, Example: secretForTLSExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateSecretTLS(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.SecretForTLSV1GeneratorName) cmd.Flags().String("cert", "", i18n.T("Path to PEM encoded public key certificate.")) cmd.Flags().String("key", "", i18n.T("Path to private key associated with given certificate.")) @@ -251,12 +292,12 @@ func NewCmdCreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { return cmd } -// CreateSecretTLS is the implementation of the create secret tls command -func CreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *SecretTLSOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + requiredFlags := []string{"cert", "key"} for _, requiredFlag := range requiredFlags { if value := cmdutil.GetFlagString(cmd, requiredFlag); len(value) == 0 { @@ -275,10 +316,11 @@ func CreateSecretTLS(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, ar default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreateSecretTLS is the implementation of the create secret tls command +func (o *SecretTLSOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } diff --git a/pkg/kubectl/cmd/create/create_service.go b/pkg/kubectl/cmd/create/create_service.go index 7ee4c4597dc..891bd766471 100644 --- a/pkg/kubectl/cmd/create/create_service.go +++ b/pkg/kubectl/cmd/create/create_service.go @@ -61,8 +61,19 @@ func addPortFlags(cmd *cobra.Command) { cmd.Flags().StringSlice("tcp", []string{}, "Port pairs can be specified as ':'.") } +type ServiceClusterIPOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreateServiceClusterIP is a command to create a ClusterIP service func NewCmdCreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &ServiceClusterIPOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "clusterip NAME [--tcp=:] [--dry-run]", DisableFlagsInUseLine: true, @@ -70,13 +81,15 @@ func NewCmdCreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer) *cobra.Co Long: serviceClusterIPLong, Example: serviceClusterIPExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateServiceClusterIP(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceClusterIPGeneratorV1Name) addPortFlags(cmd) cmd.Flags().String("clusterip", "", i18n.T("Assign your own ClusterIP or set to 'None' for a 'headless' service (no loadbalancing).")) @@ -87,12 +100,12 @@ func errUnsupportedGenerator(cmd *cobra.Command, generatorName string) error { return cmdutil.UsageErrorf(cmd, "Generator %s not supported. ", generatorName) } -// CreateServiceClusterIP is the implementation of the create service clusterip command -func CreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *ServiceClusterIPOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.ServiceClusterIPGeneratorV1Name: @@ -105,12 +118,13 @@ func CreateServiceClusterIP(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comm default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreateServiceClusterIP is the implementation of the create service clusterip command +func (o *ServiceClusterIPOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } var ( @@ -122,8 +136,19 @@ var ( kubectl create service nodeport my-ns --tcp=5678:8080`)) ) +type ServiceNodePortOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreateServiceNodePort is a macro command for creating a NodePort service func NewCmdCreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &ServiceNodePortOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "nodeport NAME [--tcp=port:targetPort] [--dry-run]", DisableFlagsInUseLine: true, @@ -131,25 +156,27 @@ func NewCmdCreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer) *cobra.Com Long: serviceNodePortLong, Example: serviceNodePortExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateServiceNodePort(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceNodePortGeneratorV1Name) cmd.Flags().Int("node-port", 0, "Port used to expose the service on each node in a cluster.") addPortFlags(cmd) return cmd } -// CreateServiceNodePort is the implementation of the create service nodeport command -func CreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *ServiceNodePortOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.ServiceNodePortGeneratorV1Name: @@ -163,12 +190,13 @@ func CreateServiceNodePort(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comma default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreateServiceNodePort is the implementation of the create service nodeport command +func (o *ServiceNodePortOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } var ( @@ -180,8 +208,19 @@ var ( kubectl create service loadbalancer my-lbs --tcp=5678:8080`)) ) +type ServiceLoadBalancerOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreateServiceLoadBalancer is a macro command for creating a LoadBalancer service func NewCmdCreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &ServiceLoadBalancerOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "loadbalancer NAME [--tcp=port:targetPort] [--dry-run]", DisableFlagsInUseLine: true, @@ -189,24 +228,26 @@ func NewCmdCreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer) *cobra Long: serviceLoadBalancerLong, Example: serviceLoadBalancerExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateServiceLoadBalancer(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceLoadBalancerGeneratorV1Name) addPortFlags(cmd) return cmd } -// CreateServiceLoadBalancer is the implementation of the create service loadbalancer command -func CreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *ServiceLoadBalancerOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.ServiceLoadBalancerGeneratorV1Name: @@ -219,12 +260,13 @@ func CreateServiceLoadBalancer(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreateServiceLoadBalancer is the implementation of the create service loadbalancer command +func (o *ServiceLoadBalancerOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } var ( @@ -240,8 +282,19 @@ var ( kubectl create service externalname my-ns --external-name bar.com`)) ) +type ServiceExternalNameOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreateServiceExternalName is a macro command for creating an ExternalName service func NewCmdCreateServiceExternalName(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &ServiceExternalNameOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "externalname NAME --external-name external.name [--dry-run]", DisableFlagsInUseLine: true, @@ -249,13 +302,15 @@ func NewCmdCreateServiceExternalName(f cmdutil.Factory, cmdOut io.Writer) *cobra Long: serviceExternalNameLong, Example: serviceExternalNameExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateExternalNameService(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceExternalNameGeneratorV1Name) addPortFlags(cmd) cmd.Flags().String("external-name", "", i18n.T("External name of service")) @@ -263,12 +318,12 @@ func NewCmdCreateServiceExternalName(f cmdutil.Factory, cmdOut io.Writer) *cobra return cmd } -// CreateExternalNameService is the implementation of the create service externalname command -func CreateExternalNameService(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *ServiceExternalNameOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.ServiceExternalNameGeneratorV1Name: @@ -281,10 +336,11 @@ func CreateExternalNameService(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.C default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreateExternalNameService is the implementation of the create service externalname command +func (o *ServiceExternalNameOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } diff --git a/pkg/kubectl/cmd/create/create_serviceaccount.go b/pkg/kubectl/cmd/create/create_serviceaccount.go index fb5379dd0d6..9a445a19c48 100644 --- a/pkg/kubectl/cmd/create/create_serviceaccount.go +++ b/pkg/kubectl/cmd/create/create_serviceaccount.go @@ -36,8 +36,19 @@ var ( kubectl create serviceaccount my-service-account`)) ) +type ServiceAccountOpts struct { + CreateSubcommandOptions *CreateSubcommandOptions +} + // NewCmdCreateServiceAccount is a macro command to create a new service account func NewCmdCreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer) *cobra.Command { + options := &ServiceAccountOpts{ + CreateSubcommandOptions: &CreateSubcommandOptions{ + PrintFlags: NewPrintFlags("created"), + CmdOut: cmdOut, + }, + } + cmd := &cobra.Command{ Use: "serviceaccount NAME [--dry-run]", DisableFlagsInUseLine: true, @@ -46,24 +57,26 @@ func NewCmdCreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer) *cobra.Comm Long: serviceAccountLong, Example: serviceAccountExample, Run: func(cmd *cobra.Command, args []string) { - err := CreateServiceAccount(f, cmdOut, cmd, args) - cmdutil.CheckErr(err) + cmdutil.CheckErr(options.Complete(cmd, args)) + cmdutil.CheckErr(options.Run(f)) }, } + + options.CreateSubcommandOptions.PrintFlags.AddFlags(cmd) + cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddValidateFlags(cmd) - cmdutil.AddPrinterFlags(cmd) cmdutil.AddInclude3rdPartyFlags(cmd) cmdutil.AddGeneratorFlags(cmd, cmdutil.ServiceAccountV1GeneratorName) return cmd } -// CreateServiceAccount implements the behavior to run the create service account command -func CreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Command, args []string) error { +func (o *ServiceAccountOpts) Complete(cmd *cobra.Command, args []string) error { name, err := NameFromCommandArgs(cmd, args) if err != nil { return err } + var generator kubectl.StructuredGenerator switch generatorName := cmdutil.GetFlagString(cmd, "generator"); generatorName { case cmdutil.ServiceAccountV1GeneratorName: @@ -71,10 +84,11 @@ func CreateServiceAccount(f cmdutil.Factory, cmdOut io.Writer, cmd *cobra.Comman default: return errUnsupportedGenerator(cmd, generatorName) } - return RunCreateSubcommand(f, cmd, cmdOut, &CreateSubcommandOptions{ - Name: name, - StructuredGenerator: generator, - DryRun: cmdutil.GetDryRunFlag(cmd), - OutputFormat: cmdutil.GetFlagString(cmd, "output"), - }) + + return o.CreateSubcommandOptions.Complete(cmd, args, generator) +} + +// CreateServiceAccount implements the behavior to run the create service account command +func (o *ServiceAccountOpts) Run(f cmdutil.Factory) error { + return RunCreateSubcommand(f, o.CreateSubcommandOptions) } diff --git a/pkg/kubectl/cmd/create/flags.go b/pkg/kubectl/cmd/create/flags.go new file mode 100644 index 00000000000..529bf67a98b --- /dev/null +++ b/pkg/kubectl/cmd/create/flags.go @@ -0,0 +1,81 @@ +/* +Copyright 2018 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 create + +import ( + "github.com/spf13/cobra" + + "k8s.io/kubernetes/pkg/printers" +) + +// PrintFlags composes common printer flag structs +// used across all create commands, and provides a method +// of retrieving a known printer based on flag values provided. +type PrintFlags struct { + JSONYamlPrintFlags *printers.JSONYamlPrintFlags + NamePrintFlags *printers.NamePrintFlags + TemplateFlags *printers.KubeTemplatePrintFlags + + OutputFormat *string +} + +func (f *PrintFlags) Complete(successTemplate string) error { + return f.NamePrintFlags.Complete(successTemplate) +} + +func (f *PrintFlags) ToPrinter() (printers.ResourcePrinter, error) { + outputFormat := "" + if f.OutputFormat != nil { + outputFormat = *f.OutputFormat + } + + if p, err := f.JSONYamlPrintFlags.ToPrinter(outputFormat); !printers.IsNoCompatiblePrinterError(err) { + return p, err + } + + if p, err := f.NamePrintFlags.ToPrinter(outputFormat); !printers.IsNoCompatiblePrinterError(err) { + return p, err + } + + if p, err := f.TemplateFlags.ToPrinter(outputFormat); !printers.IsNoCompatiblePrinterError(err) { + return p, err + } + + return nil, printers.NoCompatiblePrinterError{Options: f} +} + +func (f *PrintFlags) AddFlags(cmd *cobra.Command) { + f.JSONYamlPrintFlags.AddFlags(cmd) + f.NamePrintFlags.AddFlags(cmd) + f.TemplateFlags.AddFlags(cmd) + + if f.OutputFormat != nil { + cmd.Flags().StringVarP(f.OutputFormat, "output", "o", *f.OutputFormat, "Output format. One of: json|yaml|wide|name|custom-columns=...|custom-columns-file=...|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See custom columns [http://kubernetes.io/docs/user-guide/kubectl-overview/#custom-columns], golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://kubernetes.io/docs/user-guide/jsonpath].") + } +} + +func NewPrintFlags(operation string) *PrintFlags { + outputFormat := "" + + return &PrintFlags{ + OutputFormat: &outputFormat, + + JSONYamlPrintFlags: printers.NewJSONYamlPrintFlags(), + NamePrintFlags: printers.NewNamePrintFlags(operation), + TemplateFlags: printers.NewKubeTemplatePrintFlags(), + } +} diff --git a/pkg/kubectl/cmd/set/set_image.go b/pkg/kubectl/cmd/set/set_image.go index 5c12176e22c..7c226e04a49 100644 --- a/pkg/kubectl/cmd/set/set_image.go +++ b/pkg/kubectl/cmd/set/set_image.go @@ -130,7 +130,6 @@ func (o *ImageOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []st if o.DryRun { o.PrintFlags.Complete("%s (dry run)") } - printer, err := o.PrintFlags.ToPrinter() if err != nil { return err diff --git a/pkg/printers/BUILD b/pkg/printers/BUILD index bda4421e5c1..7adeeb08156 100644 --- a/pkg/printers/BUILD +++ b/pkg/printers/BUILD @@ -30,6 +30,7 @@ go_library( ], importpath = "k8s.io/kubernetes/pkg/printers", deps = [ + "//pkg/api/legacyscheme:go_default_library", "//pkg/kubectl/scheme:go_default_library", "//vendor/github.com/ghodss/yaml:go_default_library", "//vendor/github.com/golang/glog:go_default_library", diff --git a/pkg/printers/flags.go b/pkg/printers/flags.go index 8519b85bfa5..6fcea1cbf0c 100644 --- a/pkg/printers/flags.go +++ b/pkg/printers/flags.go @@ -23,14 +23,18 @@ import ( ) type NoCompatiblePrinterError struct { - options interface{} + Options interface{} } func (e NoCompatiblePrinterError) Error() string { - return fmt.Sprintf("unable to match a printer suitable for the options specified: %#v", e.options) + return fmt.Sprintf("unable to match a printer suitable for the options specified: %#v", e.Options) } func IsNoCompatiblePrinterError(err error) bool { + if err == nil { + return false + } + _, ok := err.(NoCompatiblePrinterError) return ok } @@ -45,9 +49,8 @@ type PrintFlags struct { OutputFormat *string } -func (f *PrintFlags) Complete(messageTemplate string) error { - f.NamePrintFlags.Operation = fmt.Sprintf(messageTemplate, f.NamePrintFlags.Operation) - return nil +func (f *PrintFlags) Complete(successTemplate string) error { + return f.NamePrintFlags.Complete(successTemplate) } func (f *PrintFlags) ToPrinter() (ResourcePrinter, error) { @@ -56,12 +59,15 @@ func (f *PrintFlags) ToPrinter() (ResourcePrinter, error) { outputFormat = *f.OutputFormat } - p, err := f.JSONYamlPrintFlags.ToPrinter(outputFormat) - if err == nil { - return p, nil + if p, err := f.JSONYamlPrintFlags.ToPrinter(outputFormat); !IsNoCompatiblePrinterError(err) { + return p, err } - return f.NamePrintFlags.ToPrinter(outputFormat) + if p, err := f.NamePrintFlags.ToPrinter(outputFormat); !IsNoCompatiblePrinterError(err) { + return p, err + } + + return nil, NoCompatiblePrinterError{f} } func (f *PrintFlags) AddFlags(cmd *cobra.Command) { diff --git a/pkg/printers/json_yaml_flags.go b/pkg/printers/json_yaml_flags.go index 134e646ab1f..e74a11bb315 100644 --- a/pkg/printers/json_yaml_flags.go +++ b/pkg/printers/json_yaml_flags.go @@ -20,6 +20,9 @@ import ( "strings" "github.com/spf13/cobra" + + "k8s.io/kubernetes/pkg/api/legacyscheme" + kubectlscheme "k8s.io/kubernetes/pkg/kubectl/scheme" ) // JSONYamlPrintFlags provides default flags necessary for json/yaml printing. @@ -32,15 +35,21 @@ type JSONYamlPrintFlags struct{} // Returns false if the specified outputFormat does not match a supported format. // Supported Format types can be found in pkg/printers/printers.go func (f *JSONYamlPrintFlags) ToPrinter(outputFormat string) (ResourcePrinter, error) { + var printer ResourcePrinter + outputFormat = strings.ToLower(outputFormat) switch outputFormat { case "json": - return &JSONPrinter{}, nil + printer = &JSONPrinter{} case "yaml": - return &YAMLPrinter{}, nil + printer = &YAMLPrinter{} default: return nil, NoCompatiblePrinterError{f} } + + // wrap the printer in a versioning printer that understands when to convert and when not to convert + return NewVersionedPrinter(printer, legacyscheme.Scheme, legacyscheme.Scheme, kubectlscheme.Versions...), nil + } // AddFlags receives a *cobra.Command reference and binds diff --git a/pkg/printers/jsonpath_flags.go b/pkg/printers/jsonpath_flags.go index ba937785a0b..b9443a5546e 100644 --- a/pkg/printers/jsonpath_flags.go +++ b/pkg/printers/jsonpath_flags.go @@ -37,9 +37,9 @@ type JSONPathPrintFlags struct { // ToPrinter receives an templateFormat and returns a printer capable of // handling --template format printing. // Returns false if the specified templateFormat does not match a template format. -func (f *JSONPathPrintFlags) ToPrinter(templateFormat string) (ResourcePrinter, bool, error) { +func (f *JSONPathPrintFlags) ToPrinter(templateFormat string) (ResourcePrinter, error) { if (f.TemplateArgument == nil || len(*f.TemplateArgument) == 0) && len(templateFormat) == 0 { - return nil, false, fmt.Errorf("missing --template value") + return nil, NoCompatiblePrinterError{f} } templateValue := "" @@ -66,17 +66,17 @@ func (f *JSONPathPrintFlags) ToPrinter(templateFormat string) (ResourcePrinter, } if _, supportedFormat := templateFormats[templateFormat]; !supportedFormat { - return nil, false, nil + return nil, NoCompatiblePrinterError{f} } if len(templateValue) == 0 { - return nil, true, fmt.Errorf("template format specified but no template given") + return nil, fmt.Errorf("template format specified but no template given") } if templateFormat == "jsonpath-file" { data, err := ioutil.ReadFile(templateValue) if err != nil { - return nil, true, fmt.Errorf("error reading --template %s, %v\n", templateValue, err) + return nil, fmt.Errorf("error reading --template %s, %v\n", templateValue, err) } templateValue = string(data) @@ -84,7 +84,7 @@ func (f *JSONPathPrintFlags) ToPrinter(templateFormat string) (ResourcePrinter, p, err := NewJSONPathPrinter(templateValue) if err != nil { - return nil, true, fmt.Errorf("error parsing jsonpath %s, %v\n", templateValue, err) + return nil, fmt.Errorf("error parsing jsonpath %s, %v\n", templateValue, err) } allowMissingKeys := true @@ -93,7 +93,7 @@ func (f *JSONPathPrintFlags) ToPrinter(templateFormat string) (ResourcePrinter, } p.AllowMissingKeys(allowMissingKeys) - return p, true, nil + return p, nil } // AddFlags receives a *cobra.Command reference and binds diff --git a/pkg/printers/jsonpath_flags_test.go b/pkg/printers/jsonpath_flags_test.go index 8a03110d5b3..a84241b14bd 100644 --- a/pkg/printers/jsonpath_flags_test.go +++ b/pkg/printers/jsonpath_flags_test.go @@ -103,14 +103,14 @@ func TestPrinterSupportsExpectedJSONPathFormats(t *testing.T) { TemplateArgument: templateArg, } - p, matched, err := printFlags.ToPrinter(tc.outputFormat) + p, err := printFlags.ToPrinter(tc.outputFormat) if tc.expectNoMatch { - if matched { + if !printers.IsNoCompatiblePrinterError(err) { t.Fatalf("expected no printer matches for output format %q", tc.outputFormat) } return } - if !matched { + if printers.IsNoCompatiblePrinterError(err) { t.Fatalf("expected to match template printer for output format %q", tc.outputFormat) } @@ -183,8 +183,8 @@ func TestJSONPathPrinterDefaultsAllowMissingKeysToTrue(t *testing.T) { } outputFormat := "jsonpath" - p, matched, err := printFlags.ToPrinter(outputFormat) - if !matched { + p, err := printFlags.ToPrinter(outputFormat) + if printers.IsNoCompatiblePrinterError(err) { t.Fatalf("expected to match template printer for output format %q", outputFormat) } if err != nil { diff --git a/pkg/printers/kube_template_flags.go b/pkg/printers/kube_template_flags.go index eaddba7f242..691c467a704 100644 --- a/pkg/printers/kube_template_flags.go +++ b/pkg/printers/kube_template_flags.go @@ -29,9 +29,9 @@ type KubeTemplatePrintFlags struct { TemplateArgument *string } -func (f *KubeTemplatePrintFlags) ToPrinter(outputFormat string) (ResourcePrinter, bool, error) { - if p, match, err := f.JSONPathPrintFlags.ToPrinter(outputFormat); match { - return p, match, err +func (f *KubeTemplatePrintFlags) ToPrinter(outputFormat string) (ResourcePrinter, error) { + if p, err := f.JSONPathPrintFlags.ToPrinter(outputFormat); !IsNoCompatiblePrinterError(err) { + return p, err } return f.GoTemplatePrintFlags.ToPrinter(outputFormat) } diff --git a/pkg/printers/name_flags.go b/pkg/printers/name_flags.go index 63553c3d0d9..17deb358534 100644 --- a/pkg/printers/name_flags.go +++ b/pkg/printers/name_flags.go @@ -17,6 +17,7 @@ limitations under the License. package printers import ( + "fmt" "strings" "github.com/spf13/cobra" @@ -37,6 +38,11 @@ type NamePrintFlags struct { Operation string } +func (f *NamePrintFlags) Complete(successTemplate string) error { + f.Operation = fmt.Sprintf(successTemplate, f.Operation) + return nil +} + // ToPrinter receives an outputFormat and returns a printer capable of // handling --output=name printing. // Returns false if the specified outputFormat does not match a supported format. diff --git a/pkg/printers/printers.go b/pkg/printers/printers.go index 86f52361854..a11f3a1ad17 100644 --- a/pkg/printers/printers.go +++ b/pkg/printers/printers.go @@ -63,10 +63,7 @@ func GetStandardPrinter(typer runtime.ObjectTyper, encoder runtime.Encoder, deco }, } - kubeTemplatePrinter, matched, err := kubeTemplateFlags.ToPrinter(format) - if !matched { - return nil, fmt.Errorf("unable to match a template printer to handle current print options") - } + kubeTemplatePrinter, err := kubeTemplateFlags.ToPrinter(format) if err != nil { return nil, err } diff --git a/pkg/printers/template_flags.go b/pkg/printers/template_flags.go index c016d0520d9..8fce11f827e 100644 --- a/pkg/printers/template_flags.go +++ b/pkg/printers/template_flags.go @@ -37,9 +37,9 @@ type GoTemplatePrintFlags struct { // ToPrinter receives an templateFormat and returns a printer capable of // handling --template format printing. // Returns false if the specified templateFormat does not match a template format. -func (f *GoTemplatePrintFlags) ToPrinter(templateFormat string) (ResourcePrinter, bool, error) { +func (f *GoTemplatePrintFlags) ToPrinter(templateFormat string) (ResourcePrinter, error) { if (f.TemplateArgument == nil || len(*f.TemplateArgument) == 0) && len(templateFormat) == 0 { - return nil, false, fmt.Errorf("missing --template argument") + return nil, NoCompatiblePrinterError{f} } templateValue := "" @@ -68,17 +68,17 @@ func (f *GoTemplatePrintFlags) ToPrinter(templateFormat string) (ResourcePrinter } if _, supportedFormat := supportedFormats[templateFormat]; !supportedFormat { - return nil, false, nil + return nil, NoCompatiblePrinterError{f} } if len(templateValue) == 0 { - return nil, true, fmt.Errorf("template format specified but no template given") + return nil, fmt.Errorf("template format specified but no template given") } if templateFormat == "templatefile" || templateFormat == "go-template-file" { data, err := ioutil.ReadFile(templateValue) if err != nil { - return nil, true, fmt.Errorf("error reading --template %s, %v\n", templateValue, err) + return nil, fmt.Errorf("error reading --template %s, %v\n", templateValue, err) } templateValue = string(data) @@ -86,7 +86,7 @@ func (f *GoTemplatePrintFlags) ToPrinter(templateFormat string) (ResourcePrinter p, err := NewGoTemplatePrinter([]byte(templateValue)) if err != nil { - return nil, true, fmt.Errorf("error parsing template %s, %v\n", templateValue, err) + return nil, fmt.Errorf("error parsing template %s, %v\n", templateValue, err) } allowMissingKeys := true @@ -95,7 +95,7 @@ func (f *GoTemplatePrintFlags) ToPrinter(templateFormat string) (ResourcePrinter } p.AllowMissingKeys(allowMissingKeys) - return p, true, nil + return p, nil } // AddFlags receives a *cobra.Command reference and binds diff --git a/pkg/printers/template_flags_test.go b/pkg/printers/template_flags_test.go index bce5b2380bc..f75e51f033b 100644 --- a/pkg/printers/template_flags_test.go +++ b/pkg/printers/template_flags_test.go @@ -103,14 +103,14 @@ func TestPrinterSupportsExpectedTemplateFormats(t *testing.T) { TemplateArgument: templateArg, } - p, matched, err := printFlags.ToPrinter(tc.outputFormat) + p, err := printFlags.ToPrinter(tc.outputFormat) if tc.expectNoMatch { - if matched { + if !printers.IsNoCompatiblePrinterError(err) { t.Fatalf("expected no printer matches for output format %q", tc.outputFormat) } return } - if !matched { + if printers.IsNoCompatiblePrinterError(err) { t.Fatalf("expected to match template printer for output format %q", tc.outputFormat) } @@ -177,8 +177,8 @@ func TestTemplatePrinterDefaultsAllowMissingKeysToTrue(t *testing.T) { } outputFormat := "template" - p, matched, err := printFlags.ToPrinter(outputFormat) - if !matched { + p, err := printFlags.ToPrinter(outputFormat) + if printers.IsNoCompatiblePrinterError(err) { t.Fatalf("expected to match template printer for output format %q", outputFormat) } if err != nil {