diff --git a/hack/make-rules/test-cmd-util.sh b/hack/make-rules/test-cmd-util.sh index 23a2430a295..2620613fe0a 100755 --- a/hack/make-rules/test-cmd-util.sh +++ b/hack/make-rules/test-cmd-util.sh @@ -1296,9 +1296,9 @@ run_kubectl_run_tests() { kubectl run nginx-extensions "--image=$IMAGE_NGINX" "${kube_flags[@]}" # Post-Condition: Deployment "nginx" is created kube::test::get_object_assert deployment.extensions "{{range.items}}{{$id_field}}:{{end}}" 'nginx-extensions:' - # and old generator was used, iow. old defaults are applied + # new generator was used output_message=$(kubectl get deployment.extensions/nginx-extensions -o jsonpath='{.spec.revisionHistoryLimit}') - kube::test::if_has_not_string "${output_message}" '2' + kube::test::if_has_string "${output_message}" '2' # Clean up kubectl delete deployment nginx-extensions "${kube_flags[@]}" # Command @@ -3924,7 +3924,7 @@ run_cmd_with_img_tests() { # Test that a valid image reference value is provided as the value of --image in `kubectl run --image` output_message=$(kubectl run test1 --image=validname) - kube::test::if_has_string "${output_message}" 'deployment.apps "test1" created' + kube::test::if_has_string "${output_message}" 'deployment.apps/test1 created' kubectl delete deployments test1 # test invalid image name output_message=$(! kubectl run test2 --image=InvalidImageName 2>&1) diff --git a/pkg/kubectl/cmd/run.go b/pkg/kubectl/cmd/run.go index 227a94bd28b..411dbb0fad0 100644 --- a/pkg/kubectl/cmd/run.go +++ b/pkg/kubectl/cmd/run.go @@ -20,6 +20,8 @@ import ( "fmt" "io" + "k8s.io/kubernetes/pkg/printers" + "github.com/docker/distribution/reference" "github.com/spf13/cobra" @@ -85,18 +87,21 @@ var ( ) type RunObject struct { - Object runtime.Object - Kind string - Mapping *meta.RESTMapping + Versioned runtime.Object + Object runtime.Object + Kind string + Mapping *meta.RESTMapping } type RunOpts struct { - DeleteFlags *DeleteFlags - + PrintFlags *printers.PrintFlags + DeleteFlags *DeleteFlags DeleteOptions *DeleteOptions DryRun bool + PrintObj func(runtime.Object) error + ArgsLenAtDash int Attach bool Expose bool @@ -117,6 +122,7 @@ type RunOpts struct { func NewCmdRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command { options := &RunOpts{ + PrintFlags: printers.NewPrintFlags("created"), DeleteFlags: NewDeleteFlags("to use to replace the resource."), In: cmdIn, @@ -137,8 +143,8 @@ func NewCmdRun(f cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *co } options.DeleteFlags.AddFlags(cmd) + options.PrintFlags.AddFlags(cmd) - cmdutil.AddPrinterFlags(cmd) addRunFlags(cmd) cmdutil.AddApplyAnnotationFlags(cmd) cmdutil.AddRecordFlag(cmd) @@ -195,6 +201,17 @@ func (o *RunOpts) Complete(f cmdutil.Factory, cmd *cobra.Command) error { o.Attach = true } + if o.DryRun { + o.PrintFlags.Complete("%s (dry run)") + } + printer, err := o.PrintFlags.ToPrinter() + if err != nil { + return err + } + o.PrintObj = func(obj runtime.Object) error { + return printer.PrintObj(obj, o.Out) + } + deleteOpts := o.DeleteFlags.ToOptions(o.Out, o.ErrOut) deleteOpts.IgnoreNotFound = true deleteOpts.WaitForDeletion = false @@ -269,14 +286,13 @@ func (o *RunOpts) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) erro } generatorName := o.Generator - schedule := o.Schedule - if len(schedule) != 0 && len(generatorName) == 0 { + if len(o.Schedule) != 0 && len(generatorName) == 0 { generatorName = cmdutil.CronJobV1Beta1GeneratorName } if len(generatorName) == 0 { switch restartPolicy { case api.RestartPolicyAlways: - generatorName = cmdutil.DeploymentV1Beta1GeneratorName + generatorName = cmdutil.DeploymentAppsV1Beta1GeneratorName case api.RestartPolicyOnFailure: generatorName = cmdutil.JobV1GeneratorName case api.RestartPolicyNever: @@ -408,11 +424,9 @@ func (o *RunOpts) Run(f cmdutil.Factory, cmd *cobra.Command, args []string) erro } if runObject != nil { - outputFormat := cmdutil.GetFlagString(cmd, "output") - if outputFormat != "" || cmdutil.GetDryRunFlag(cmd) { - return cmdutil.PrintObject(cmd, runObject.Object, o.Out) + if err := o.PrintObj(runObject.Versioned); err != nil { + return err } - cmdutil.PrintSuccess(false, o.Out, runObject.Object, cmdutil.GetDryRunFlag(cmd), "created") } return utilerrors.NewAggregate(allErrs) @@ -592,17 +606,13 @@ func (o *RunOpts) generateService(f cmdutil.Factory, cmd *cobra.Command, service return nil, err } - if cmdutil.GetFlagString(cmd, "output") != "" || cmdutil.GetDryRunFlag(cmd) { - err := cmdutil.PrintObject(cmd, runObject.Object, o.Out) - if err != nil { - return nil, err - } - if cmdutil.GetFlagString(cmd, "output") == "yaml" { - fmt.Fprintln(o.Out, "---") - } - return runObject, nil + if err := o.PrintObj(runObject.Versioned); err != nil { + return nil, err + } + // separate yaml objects + if o.PrintFlags.OutputFormat != nil && *o.PrintFlags.OutputFormat == "yaml" { + fmt.Fprintln(o.Out, "---") } - cmdutil.PrintSuccess(false, o.Out, runObject.Object, cmdutil.GetDryRunFlag(cmd), "created") return runObject, nil } @@ -653,6 +663,7 @@ func (o *RunOpts) createGeneratedObject(f cmdutil.Factory, cmd *cobra.Command, g } } + versioned := obj if !o.DryRun { resourceMapper := &resource.Mapper{ ObjectTyper: typer, @@ -673,10 +684,13 @@ func (o *RunOpts) createGeneratedObject(f cmdutil.Factory, cmd *cobra.Command, g if err != nil { return nil, err } + + versioned = info.AsVersioned() } return &RunObject{ - Object: obj, - Kind: groupVersionKind.Kind, - Mapping: mapping, + Versioned: versioned, + Object: obj, + Kind: groupVersionKind.Kind, + Mapping: mapping, }, nil } diff --git a/pkg/kubectl/cmd/run_test.go b/pkg/kubectl/cmd/run_test.go index c863dc70c38..e7e8f24b062 100644 --- a/pkg/kubectl/cmd/run_test.go +++ b/pkg/kubectl/cmd/run_test.go @@ -41,6 +41,7 @@ import ( cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" "k8s.io/kubernetes/pkg/kubectl/scheme" "k8s.io/kubernetes/pkg/kubectl/util/i18n" + "k8s.io/kubernetes/pkg/printers" ) // This init should be removed after switching this command and its tests to user external types. @@ -196,8 +197,16 @@ func TestRunArgsFollowDashRules(t *testing.T) { cmd.Flags().Set("image", "nginx") cmd.Flags().Set("generator", "run/v1") + printFlags := printers.NewPrintFlags("created") + printer, err := printFlags.ToPrinter() + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + deleteFlags := NewDeleteFlags("to use to replace the resource.") opts := &RunOpts{ + PrintFlags: printFlags, DeleteOptions: deleteFlags.ToOptions(os.Stdout, os.Stderr), In: os.Stdin, @@ -207,10 +216,14 @@ func TestRunArgsFollowDashRules(t *testing.T) { Image: "nginx", Generator: "run/v1", + PrintObj: func(obj runtime.Object) error { + return printer.PrintObj(obj, os.Stdout) + }, + ArgsLenAtDash: test.argsLenAtDash, } - err := opts.Run(tf, cmd, test.args) + err = opts.Run(tf, cmd, test.args) if test.expectError && err == nil { t.Errorf("unexpected non-error (%s)", test.name) } @@ -353,9 +366,17 @@ func TestGenerateService(t *testing.T) { }), } - buff := &bytes.Buffer{} + printFlags := printers.NewPrintFlags("created") + printer, err := printFlags.ToPrinter() + if err != nil { + t.Errorf("unexpected error: %v", err) + return + } + deleteFlags := NewDeleteFlags("to use to replace the resource.") + buff := &bytes.Buffer{} opts := &RunOpts{ + PrintFlags: printFlags, DeleteOptions: deleteFlags.ToOptions(os.Stdout, os.Stderr), Out: buff, @@ -363,12 +384,15 @@ func TestGenerateService(t *testing.T) { Port: test.port, Record: false, + + PrintObj: func(obj runtime.Object) error { + return printer.PrintObj(obj, buff) + }, } cmd := &cobra.Command{} cmd.Flags().Bool(cmdutil.ApplyAnnotationsFlag, false, "") cmd.Flags().Bool("record", false, "Record current kubectl command in the resource annotation. If set to false, do not record the command. If set to true, record the command. If not set, default to updating the existing annotation value only if one already exists.") - cmdutil.AddPrinterFlags(cmd) cmdutil.AddInclude3rdPartyFlags(cmd) addRunFlags(cmd) @@ -381,7 +405,7 @@ func TestGenerateService(t *testing.T) { test.params["port"] = test.port } - _, err := opts.generateService(tf, cmd, test.serviceGenerator, test.params, "namespace") + _, err = opts.generateService(tf, cmd, test.serviceGenerator, test.params, "namespace") if test.expectErr { if err == nil { t.Error("unexpected non-error")