diff --git a/pkg/kubectl/cmd/exec.go b/pkg/kubectl/cmd/exec.go index a0c0c88924b..eef02355bbc 100644 --- a/pkg/kubectl/cmd/exec.go +++ b/pkg/kubectl/cmd/exec.go @@ -59,7 +59,8 @@ func NewCmdExec(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) * Long: "Execute a command in a container.", Example: exec_example, Run: func(cmd *cobra.Command, args []string) { - cmdutil.CheckErr(options.Complete(f, cmd, args)) + argsLenAtDash := cmd.ArgsLenAtDash() + cmdutil.CheckErr(options.Complete(f, cmd, args, argsLenAtDash)) cmdutil.CheckErr(options.Validate()) cmdutil.CheckErr(options.Run()) }, @@ -107,8 +108,9 @@ type ExecOptions struct { } // Complete verifies command line arguments and loads data from the command environment -func (p *ExecOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, argsIn []string) error { - if len(p.PodName) == 0 && len(argsIn) == 0 { +func (p *ExecOptions) Complete(f *cmdutil.Factory, cmd *cobra.Command, argsIn []string, argsLenAtDash int) error { + // Let kubectl exec follow rules for `--`, see #13004 issue + if len(p.PodName) == 0 && (len(argsIn) == 0 || argsLenAtDash == 0) { return cmdutil.UsageError(cmd, "POD is required for exec") } if len(p.PodName) != 0 { diff --git a/pkg/kubectl/cmd/exec_test.go b/pkg/kubectl/cmd/exec_test.go index dd7b85d2ffe..0090dcd6afc 100644 --- a/pkg/kubectl/cmd/exec_test.go +++ b/pkg/kubectl/cmd/exec_test.go @@ -48,6 +48,7 @@ func (f *fakeRemoteExecutor) Execute(method string, url *url.URL, config *client func TestPodAndContainer(t *testing.T) { tests := []struct { args []string + argsLenAtDash int p *ExecOptions name string expectError bool @@ -56,43 +57,65 @@ func TestPodAndContainer(t *testing.T) { expectedArgs []string }{ { - p: &ExecOptions{}, - expectError: true, - name: "empty", + p: &ExecOptions{}, + argsLenAtDash: -1, + expectError: true, + name: "empty", }, { - p: &ExecOptions{PodName: "foo"}, - expectError: true, - name: "no cmd", + p: &ExecOptions{PodName: "foo"}, + argsLenAtDash: -1, + expectError: true, + name: "no cmd", }, { - p: &ExecOptions{PodName: "foo", ContainerName: "bar"}, - expectError: true, - name: "no cmd, w/ container", + p: &ExecOptions{PodName: "foo", ContainerName: "bar"}, + argsLenAtDash: -1, + expectError: true, + name: "no cmd, w/ container", }, { - p: &ExecOptions{PodName: "foo"}, - args: []string{"cmd"}, - expectedPod: "foo", - expectedArgs: []string{"cmd"}, - name: "pod in flags", + p: &ExecOptions{PodName: "foo"}, + args: []string{"cmd"}, + argsLenAtDash: -1, + expectedPod: "foo", + expectedArgs: []string{"cmd"}, + name: "pod in flags", }, { - p: &ExecOptions{}, - args: []string{"foo"}, - expectError: true, - name: "no cmd, w/o flags", + p: &ExecOptions{}, + args: []string{"foo", "cmd"}, + argsLenAtDash: 0, + expectError: true, + name: "no pod, pod name is behind dash", }, { - p: &ExecOptions{}, - args: []string{"foo", "cmd"}, - expectedPod: "foo", - expectedArgs: []string{"cmd"}, - name: "cmd, w/o flags", + p: &ExecOptions{}, + args: []string{"foo"}, + argsLenAtDash: -1, + expectError: true, + name: "no cmd, w/o flags", + }, + { + p: &ExecOptions{}, + args: []string{"foo", "cmd"}, + argsLenAtDash: -1, + expectedPod: "foo", + expectedArgs: []string{"cmd"}, + name: "cmd, w/o flags", + }, + { + p: &ExecOptions{}, + args: []string{"foo", "cmd"}, + argsLenAtDash: 1, + expectedPod: "foo", + expectedArgs: []string{"cmd"}, + name: "cmd, cmd is behind dash", }, { p: &ExecOptions{ContainerName: "bar"}, args: []string{"foo", "cmd"}, + argsLenAtDash: -1, expectedPod: "foo", expectedContainer: "bar", expectedArgs: []string{"cmd"}, @@ -110,7 +133,7 @@ func TestPodAndContainer(t *testing.T) { cmd := &cobra.Command{} options := test.p - err := options.Complete(f, cmd, test.args) + err := options.Complete(f, cmd, test.args, test.argsLenAtDash) if test.expectError && err == nil { t.Errorf("unexpected non-error (%s)", test.name) } @@ -189,7 +212,8 @@ func TestExec(t *testing.T) { Executor: ex, } cmd := &cobra.Command{} - if err := params.Complete(f, cmd, []string{"test", "command"}); err != nil { + args := []string{"test", "command"} + if err := params.Complete(f, cmd, args, -1); err != nil { t.Fatal(err) } err := params.Run()