From 4d2333b7d8447d35fbd0acb85c67e28bc3f64dae Mon Sep 17 00:00:00 2001 From: feihujiang Date: Mon, 14 Sep 2015 20:18:42 +0800 Subject: [PATCH] Let kubectl run follow rules for `--` --- docs/user-guide/kubectl/kubectl_run.md | 4 +- pkg/kubectl/cmd/run.go | 10 ++-- pkg/kubectl/cmd/run_test.go | 63 ++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 6 deletions(-) diff --git a/docs/user-guide/kubectl/kubectl_run.md b/docs/user-guide/kubectl/kubectl_run.md index def91d0d456..2827fd8d7ea 100644 --- a/docs/user-guide/kubectl/kubectl_run.md +++ b/docs/user-guide/kubectl/kubectl_run.md @@ -42,7 +42,7 @@ Create and run a particular image, possibly replicated. Creates a replication controller to manage the created container(s). ``` -kubectl run NAME --image=image [--env="key=value"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] +kubectl run NAME --image=image [--env="key=value"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] [--command] -- [COMMAND] [args...] ``` ### Examples @@ -140,7 +140,7 @@ $ kubectl run nginx --image=nginx --command -- ... * [kubectl](kubectl.md) - kubectl controls the Kubernetes cluster manager -###### Auto generated by spf13/cobra on 6-Nov-2015 +###### Auto generated by spf13/cobra on 10-Nov-2015 [![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/user-guide/kubectl/kubectl_run.md?pixel)]() diff --git a/pkg/kubectl/cmd/run.go b/pkg/kubectl/cmd/run.go index 2dfa9600586..57a195b49d4 100644 --- a/pkg/kubectl/cmd/run.go +++ b/pkg/kubectl/cmd/run.go @@ -65,14 +65,15 @@ $ kubectl run nginx --image=nginx --command -- ... ` func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command { cmd := &cobra.Command{ - Use: "run NAME --image=image [--env=\"key=value\"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json]", + Use: "run NAME --image=image [--env=\"key=value\"] [--port=port] [--replicas=replicas] [--dry-run=bool] [--overrides=inline-json] [--command] -- [COMMAND] [args...]", // run-container is deprecated Aliases: []string{"run-container"}, Short: "Run a particular image on the cluster.", Long: run_long, Example: run_example, Run: func(cmd *cobra.Command, args []string) { - err := Run(f, cmdIn, cmdOut, cmdErr, cmd, args) + argsLenAtDash := cmd.ArgsLenAtDash() + err := Run(f, cmdIn, cmdOut, cmdErr, cmd, args, argsLenAtDash) cmdutil.CheckErr(err) }, } @@ -106,12 +107,13 @@ func addRunFlags(cmd *cobra.Command) { cmd.Flags().String("service-overrides", "", "An inline JSON override for the generated service object. If this is non-empty, it is used to override the generated object. Requires that the object supply a valid apiVersion field. Only used if --expose is true.") } -func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string) error { +func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cobra.Command, args []string, argsLenAtDash int) error { if len(os.Args) > 1 && os.Args[1] == "run-container" { printDeprecationWarning("run", "run-container") } - if len(args) == 0 { + // Let kubectl run follow rules for `--`, see #13004 issue + if len(args) == 0 || argsLenAtDash == 0 { return cmdutil.UsageError(cmd, "NAME is required for run") } diff --git a/pkg/kubectl/cmd/run_test.go b/pkg/kubectl/cmd/run_test.go index cf5ce0e6c02..4fc94558901 100644 --- a/pkg/kubectl/cmd/run_test.go +++ b/pkg/kubectl/cmd/run_test.go @@ -21,6 +21,7 @@ import ( "fmt" "io/ioutil" "net/http" + "os" "reflect" "testing" @@ -106,6 +107,68 @@ func TestGetEnv(t *testing.T) { } } +func TestRunArgsFollowDashRules(t *testing.T) { + _, _, rc := testData() + + tests := []struct { + args []string + argsLenAtDash int + expectError bool + name string + }{ + { + args: []string{}, + argsLenAtDash: -1, + expectError: true, + name: "empty", + }, + { + args: []string{"foo"}, + argsLenAtDash: -1, + expectError: false, + name: "no cmd", + }, + { + args: []string{"foo", "sleep"}, + argsLenAtDash: -1, + expectError: false, + name: "cmd no dash", + }, + { + args: []string{"foo", "sleep"}, + argsLenAtDash: 1, + expectError: false, + name: "cmd has dash", + }, + { + args: []string{"foo", "sleep"}, + argsLenAtDash: 0, + expectError: true, + name: "no name", + }, + } + for _, test := range tests { + f, tf, codec := NewAPIFactory() + tf.Client = &fake.RESTClient{ + Codec: codec, + Client: fake.CreateHTTPClient(func(req *http.Request) (*http.Response, error) { + return &http.Response{StatusCode: 201, Body: objBody(codec, &rc.Items[0])}, nil + }), + } + tf.Namespace = "test" + tf.ClientConfig = &client.Config{} + cmd := NewCmdRun(f, os.Stdin, os.Stdout, os.Stderr) + cmd.Flags().Set("image", "nginx") + err := Run(f, os.Stdin, os.Stdout, os.Stderr, cmd, test.args, test.argsLenAtDash) + if test.expectError && err == nil { + t.Errorf("unexpected non-error (%s)", test.name) + } + if !test.expectError && err != nil { + t.Errorf("unexpected error: %v (%s)", err, test.name) + } + } +} + func TestGenerateService(t *testing.T) { tests := []struct {