Skip to content

Commit 9dac169

Browse files
committed
Wire --filename flag to exec
1 parent 39ed64e commit 9dac169

File tree

3 files changed

+34
-23
lines changed

3 files changed

+34
-23
lines changed

staging/src/k8s.io/kubectl/pkg/cmd/exec/exec.go

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ import (
4545
var (
4646
execExample = templates.Examples(i18n.T(`
4747
# Get output from running 'date' command from pod mypod, using the first container by default
48-
kubectl exec mypod date
48+
kubectl exec mypod -- date
4949
5050
# Get output from running 'date' command in ruby-container from pod mypod
51-
kubectl exec mypod -c ruby-container date
51+
kubectl exec mypod -c ruby-container -- date
5252
5353
# Switch to raw terminal mode, sends stdin to 'bash' in ruby-container from pod mypod
5454
# and sends stdout/stderr from 'bash' back to the client
@@ -62,15 +62,14 @@ var (
6262
kubectl exec mypod -i -t -- ls -t /usr
6363
6464
# Get output from running 'date' command from the first pod of the deployment mydeployment, using the first container by default
65-
kubectl exec deploy/mydeployment date
65+
kubectl exec deploy/mydeployment -- date
6666
6767
# Get output from running 'date' command from the first pod of the service myservice, using the first container by default
68-
kubectl exec svc/myservice date
68+
kubectl exec svc/myservice -- date
6969
`))
7070
)
7171

7272
const (
73-
execUsageStr = "expected 'exec (POD | TYPE/NAME) COMMAND [ARG1] [ARG2] ... [ARGN]'.\nPOD or TYPE/NAME and COMMAND are required arguments for the exec command"
7473
defaultPodExecTimeout = 60 * time.Second
7574
)
7675

@@ -96,6 +95,7 @@ func NewCmdExec(f cmdutil.Factory, streams genericclioptions.IOStreams) *cobra.C
9695
},
9796
}
9897
cmdutil.AddPodRunningTimeoutFlag(cmd, defaultPodExecTimeout)
98+
cmdutil.AddJsonFilenameFlag(cmd.Flags(), &options.FilenameOptions.Filenames, "to use to exec into the resource")
9999
// TODO support UID
100100
cmd.Flags().StringVarP(&options.ContainerName, "container", "c", options.ContainerName, "Container name. If omitted, the first container in the pod will be chosen")
101101
cmd.Flags().BoolVarP(&options.Stdin, "stdin", "i", options.Stdin, "Pass stdin to the container")
@@ -146,9 +146,11 @@ type StreamOptions struct {
146146
// ExecOptions declare the arguments accepted by the Exec command
147147
type ExecOptions struct {
148148
StreamOptions
149+
resource.FilenameOptions
149150

150-
ResourceName string
151-
Command []string
151+
ResourceName string
152+
Command []string
153+
EnforceNamespace bool
152154

153155
ParentCommandName string
154156
EnableSuggestedCmdUsage bool
@@ -166,17 +168,22 @@ type ExecOptions struct {
166168

167169
// Complete verifies command line arguments and loads data from the command environment
168170
func (p *ExecOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn []string, argsLenAtDash int) error {
169-
// Let kubectl exec follow rules for `--`, see #13004 issue
170-
if len(argsIn) == 0 || argsLenAtDash == 0 {
171-
return cmdutil.UsageErrorf(cmd, execUsageStr)
171+
if len(argsIn) > 0 && argsLenAtDash != 0 {
172+
p.ResourceName = argsIn[0]
173+
}
174+
if argsLenAtDash > -1 {
175+
p.Command = argsIn[argsLenAtDash:]
176+
} else if len(argsIn) > 1 {
177+
fmt.Fprint(p.ErrOut, "kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.\n")
178+
p.Command = argsIn[1:]
179+
} else if len(argsIn) > 0 && len(p.FilenameOptions.Filenames) != 0 {
180+
fmt.Fprint(p.ErrOut, "kubectl exec [POD] [COMMAND] is DEPRECATED and will be removed in a future version. Use kubectl kubectl exec [POD] -- [COMMAND] instead.\n")
181+
p.Command = argsIn[0:]
182+
p.ResourceName = ""
172183
}
173-
174-
p.ResourceName = argsIn[0]
175-
p.Command = argsIn[1:]
176184

177185
var err error
178-
179-
p.Namespace, _, err = f.ToRawKubeConfigLoader().Namespace()
186+
p.Namespace, p.EnforceNamespace, err = f.ToRawKubeConfigLoader().Namespace()
180187
if err != nil {
181188
return err
182189
}
@@ -215,8 +222,8 @@ func (p *ExecOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, argsIn []s
215222

216223
// Validate checks that the provided exec options are specified.
217224
func (p *ExecOptions) Validate() error {
218-
if len(p.PodName) == 0 && len(p.ResourceName) == 0 {
219-
return fmt.Errorf("pod or type/name must be specified")
225+
if len(p.PodName) == 0 && len(p.ResourceName) == 0 && len(p.FilenameOptions.Filenames) == 0 {
226+
return fmt.Errorf("pod, type/name or --filename must be specified")
220227
}
221228
if len(p.Command) == 0 {
222229
return fmt.Errorf("you must specify at least one command for the container")
@@ -293,7 +300,11 @@ func (p *ExecOptions) Run() error {
293300
} else {
294301
builder := p.Builder().
295302
WithScheme(scheme.Scheme, scheme.Scheme.PrioritizedVersionsAllGroups()...).
296-
NamespaceParam(p.Namespace).DefaultNamespace().ResourceNames("pods", p.ResourceName)
303+
FilenameParam(p.EnforceNamespace, &p.FilenameOptions).
304+
NamespaceParam(p.Namespace).DefaultNamespace()
305+
if len(p.ResourceName) > 0 {
306+
builder = builder.ResourceNames("pods", p.ResourceName)
307+
}
297308

298309
obj, err := builder.Do().Object()
299310
if err != nil {

staging/src/k8s.io/kubectl/pkg/cmd/exec/exec_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ func TestPodAndContainer(t *testing.T) {
103103
{
104104
p: &ExecOptions{},
105105
args: []string{"foo", "cmd"},
106-
argsLenAtDash: -1,
106+
argsLenAtDash: 1,
107107
expectedPod: "foo",
108108
expectedArgs: []string{"cmd"},
109109
name: "cmd, w/o flags",
@@ -112,7 +112,7 @@ func TestPodAndContainer(t *testing.T) {
112112
{
113113
p: &ExecOptions{},
114114
args: []string{"foo", "cmd"},
115-
argsLenAtDash: 1,
115+
argsLenAtDash: -1,
116116
expectedPod: "foo",
117117
expectedArgs: []string{"cmd"},
118118
name: "cmd, cmd is behind dash",

test/cmd/exec.sh

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,14 @@ run_kubectl_exec_resource_name_tests() {
8181
# POD test-pod is exists this is shouldn't have output not found
8282
kube::test::if_has_not_string "${output_message}" 'not found'
8383
# These must be pass the validate
84-
kube::test::if_has_not_string "${output_message}" 'pod or type/name must be specified'
85-
84+
kube::test::if_has_not_string "${output_message}" 'pod, type/name or --filename must be specified'
85+
8686
output_message=$(! kubectl exec replicaset/frontend date 2>&1)
8787
# Replicaset frontend is valid and exists will select the first pod.
8888
# and Shouldn't have output not found
8989
kube::test::if_has_not_string "${output_message}" 'not found'
9090
# These must be pass the validate
91-
kube::test::if_has_not_string "${output_message}" 'pod or type/name must be specified'
91+
kube::test::if_has_not_string "${output_message}" 'pod, type/name or --filename must be specified'
9292

9393
# Clean up
9494
kubectl delete pods/test-pod

0 commit comments

Comments
 (0)