mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	Merge pull request #8604 from brendandburns/kubectl
Make exec more consistent with the rest of the kubectl commands.
This commit is contained in:
		@@ -485,10 +485,6 @@ _kubectl_exec()
 | 
				
			|||||||
    flags+=("-t")
 | 
					    flags+=("-t")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    must_have_one_flag=()
 | 
					    must_have_one_flag=()
 | 
				
			||||||
    must_have_one_flag+=("--container=")
 | 
					 | 
				
			||||||
    must_have_one_flag+=("-c")
 | 
					 | 
				
			||||||
    must_have_one_flag+=("--pod=")
 | 
					 | 
				
			||||||
    must_have_one_flag+=("-p")
 | 
					 | 
				
			||||||
    must_have_one_noun=()
 | 
					    must_have_one_noun=()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -8,17 +8,20 @@ Execute a command in a container.
 | 
				
			|||||||
Execute a command in a container.
 | 
					Execute a command in a container.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
kubectl exec -p POD -c CONTAINER -- COMMAND [args...]
 | 
					kubectl exec POD -c CONTAINER -- COMMAND [args...]
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Examples
 | 
					### Examples
 | 
				
			||||||
 | 
					
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					// get output from running 'date' from pod 123456-7890, using the first container by default
 | 
				
			||||||
 | 
					$ kubectl exec 123456-7890 date
 | 
				
			||||||
 | 
						
 | 
				
			||||||
// get output from running 'date' in ruby-container from pod 123456-7890
 | 
					// get output from running 'date' in ruby-container from pod 123456-7890
 | 
				
			||||||
$ kubectl exec -p 123456-7890 -c ruby-container date
 | 
					$ kubectl exec 123456-7890 -c ruby-container date
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//switch to raw terminal mode, sends stdin to 'bash' in ruby-container from pod 123456-780 and sends stdout/stderr from 'bash' back to the client
 | 
					//switch to raw terminal mode, sends stdin to 'bash' in ruby-container from pod 123456-780 and sends stdout/stderr from 'bash' back to the client
 | 
				
			||||||
$ kubectl exec -p 123456-7890 -c ruby-container -i -t -- bash -il
 | 
					$ kubectl exec 123456-7890 -c ruby-container -i -t -- bash -il
 | 
				
			||||||
```
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
### Options
 | 
					### Options
 | 
				
			||||||
@@ -63,6 +66,6 @@ $ kubectl exec -p 123456-7890 -c ruby-container -i -t -- bash -il
 | 
				
			|||||||
### SEE ALSO
 | 
					### SEE ALSO
 | 
				
			||||||
* [kubectl](kubectl.md)	 - kubectl controls the Kubernetes cluster manager
 | 
					* [kubectl](kubectl.md)	 - kubectl controls the Kubernetes cluster manager
 | 
				
			||||||
 | 
					
 | 
				
			||||||
###### Auto generated by spf13/cobra at 2015-05-21 10:33:11.186469192 +0000 UTC
 | 
					###### Auto generated by spf13/cobra at 2015-05-27 22:47:02.898315735 +0000 UTC
 | 
				
			||||||
 | 
					
 | 
				
			||||||
[]()
 | 
					[]()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -141,11 +141,14 @@ Execute a command in a container.
 | 
				
			|||||||
.RS
 | 
					.RS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.nf
 | 
					.nf
 | 
				
			||||||
 | 
					// get output from running 'date' from pod 123456\-7890, using the first container by default
 | 
				
			||||||
 | 
					$ kubectl exec 123456\-7890 date
 | 
				
			||||||
 | 
						
 | 
				
			||||||
// get output from running 'date' in ruby\-container from pod 123456\-7890
 | 
					// get output from running 'date' in ruby\-container from pod 123456\-7890
 | 
				
			||||||
$ kubectl exec \-p 123456\-7890 \-c ruby\-container date
 | 
					$ kubectl exec 123456\-7890 \-c ruby\-container date
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//switch to raw terminal mode, sends stdin to 'bash' in ruby\-container from pod 123456\-780 and sends stdout/stderr from 'bash' back to the client
 | 
					//switch to raw terminal mode, sends stdin to 'bash' in ruby\-container from pod 123456\-780 and sends stdout/stderr from 'bash' back to the client
 | 
				
			||||||
$ kubectl exec \-p 123456\-7890 \-c ruby\-container \-i \-t \-\- bash \-il
 | 
					$ kubectl exec 123456\-7890 \-c ruby\-container \-i \-t \-\- bash \-il
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.fi
 | 
					.fi
 | 
				
			||||||
.RE
 | 
					.RE
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -32,17 +32,20 @@ import (
 | 
				
			|||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const (
 | 
					const (
 | 
				
			||||||
	exec_example = `// get output from running 'date' in ruby-container from pod 123456-7890
 | 
						exec_example = `// get output from running 'date' from pod 123456-7890, using the first container by default
 | 
				
			||||||
$ kubectl exec -p 123456-7890 -c ruby-container date
 | 
					$ kubectl exec 123456-7890 date
 | 
				
			||||||
 | 
						
 | 
				
			||||||
 | 
					// get output from running 'date' in ruby-container from pod 123456-7890
 | 
				
			||||||
 | 
					$ kubectl exec 123456-7890 -c ruby-container date
 | 
				
			||||||
 | 
					
 | 
				
			||||||
//switch to raw terminal mode, sends stdin to 'bash' in ruby-container from pod 123456-780 and sends stdout/stderr from 'bash' back to the client
 | 
					//switch to raw terminal mode, sends stdin to 'bash' in ruby-container from pod 123456-780 and sends stdout/stderr from 'bash' back to the client
 | 
				
			||||||
$ kubectl exec -p 123456-7890 -c ruby-container -i -t -- bash -il`
 | 
					$ kubectl exec 123456-7890 -c ruby-container -i -t -- bash -il`
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func NewCmdExec(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command {
 | 
					func NewCmdExec(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *cobra.Command {
 | 
				
			||||||
	params := &execParams{}
 | 
						params := &execParams{}
 | 
				
			||||||
	cmd := &cobra.Command{
 | 
						cmd := &cobra.Command{
 | 
				
			||||||
		Use:     "exec -p POD -c CONTAINER -- COMMAND [args...]",
 | 
							Use:     "exec POD -c CONTAINER -- COMMAND [args...]",
 | 
				
			||||||
		Short:   "Execute a command in a container.",
 | 
							Short:   "Execute a command in a container.",
 | 
				
			||||||
		Long:    "Execute a command in a container.",
 | 
							Long:    "Execute a command in a container.",
 | 
				
			||||||
		Example: exec_example,
 | 
							Example: exec_example,
 | 
				
			||||||
@@ -52,10 +55,8 @@ func NewCmdExec(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *
 | 
				
			|||||||
		},
 | 
							},
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	cmd.Flags().StringVarP(¶ms.podName, "pod", "p", "", "Pod name")
 | 
						cmd.Flags().StringVarP(¶ms.podName, "pod", "p", "", "Pod name")
 | 
				
			||||||
	cmd.MarkFlagRequired("pod")
 | 
					 | 
				
			||||||
	// TODO support UID
 | 
						// TODO support UID
 | 
				
			||||||
	cmd.Flags().StringVarP(¶ms.containerName, "container", "c", "", "Container name")
 | 
						cmd.Flags().StringVarP(¶ms.containerName, "container", "c", "", "Container name")
 | 
				
			||||||
	cmd.MarkFlagRequired("container")
 | 
					 | 
				
			||||||
	cmd.Flags().BoolVarP(¶ms.stdin, "stdin", "i", false, "Pass stdin to the container")
 | 
						cmd.Flags().BoolVarP(¶ms.stdin, "stdin", "i", false, "Pass stdin to the container")
 | 
				
			||||||
	cmd.Flags().BoolVarP(¶ms.tty, "tty", "t", false, "Stdin is a TTY")
 | 
						cmd.Flags().BoolVarP(¶ms.tty, "tty", "t", false, "Stdin is a TTY")
 | 
				
			||||||
	return cmd
 | 
						return cmd
 | 
				
			||||||
@@ -79,14 +80,27 @@ type execParams struct {
 | 
				
			|||||||
	tty           bool
 | 
						tty           bool
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func RunExec(f *cmdutil.Factory, cmd *cobra.Command, cmdIn io.Reader, cmdOut, cmdErr io.Writer, p *execParams, args []string, re remoteExecutor) error {
 | 
					func extractPodAndContainer(cmd *cobra.Command, args []string, p *execParams) (podName string, containerName string, err error) {
 | 
				
			||||||
	if len(p.podName) == 0 {
 | 
						if len(p.podName) == 0 && len(args) == 0 {
 | 
				
			||||||
		return cmdutil.UsageError(cmd, "POD is required for exec")
 | 
							return "", "", cmdutil.UsageError(cmd, "POD is required for exec")
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
						if len(p.podName) != 0 {
 | 
				
			||||||
 | 
							printDeprecationWarning("exec POD", "-p POD")
 | 
				
			||||||
 | 
							podName = p.podName
 | 
				
			||||||
 | 
							if len(args) < 1 {
 | 
				
			||||||
 | 
								return "", "", cmdutil.UsageError(cmd, "COMMAND is required for exec")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						} else {
 | 
				
			||||||
 | 
							podName = args[0]
 | 
				
			||||||
 | 
							if len(args) < 2 {
 | 
				
			||||||
 | 
								return "", "", cmdutil.UsageError(cmd, "COMMAND is required for exec")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						return podName, p.containerName, nil
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if len(args) < 1 {
 | 
					func RunExec(f *cmdutil.Factory, cmd *cobra.Command, cmdIn io.Reader, cmdOut, cmdErr io.Writer, p *execParams, args []string, re remoteExecutor) error {
 | 
				
			||||||
		return cmdutil.UsageError(cmd, "COMMAND is required for exec")
 | 
						podName, containerName, err := extractPodAndContainer(cmd, args, p)
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	namespace, err := f.DefaultNamespace()
 | 
						namespace, err := f.DefaultNamespace()
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
@@ -97,17 +111,17 @@ func RunExec(f *cmdutil.Factory, cmd *cobra.Command, cmdIn io.Reader, cmdOut, cm
 | 
				
			|||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	pod, err := client.Pods(namespace).Get(p.podName)
 | 
						pod, err := client.Pods(namespace).Get(podName)
 | 
				
			||||||
	if err != nil {
 | 
						if err != nil {
 | 
				
			||||||
		return err
 | 
							return err
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if pod.Status.Phase != api.PodRunning {
 | 
						if pod.Status.Phase != api.PodRunning {
 | 
				
			||||||
		glog.Fatalf("Unable to execute command because pod is not running. Current status=%v", pod.Status.Phase)
 | 
							glog.Fatalf("Unable to execute command because pod %s is not running. Current status=%v", podName, pod.Status.Phase)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	containerName := p.containerName
 | 
					 | 
				
			||||||
	if len(containerName) == 0 {
 | 
						if len(containerName) == 0 {
 | 
				
			||||||
 | 
							glog.V(4).Infof("defaulting container name to %s", pod.Spec.Containers[0].Name)
 | 
				
			||||||
		containerName = pod.Spec.Containers[0].Name
 | 
							containerName = pod.Spec.Containers[0].Name
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -39,8 +39,67 @@ func (f *fakeRemoteExecutor) Execute(req *client.Request, config *client.Config,
 | 
				
			|||||||
	return f.execErr
 | 
						return f.execErr
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
func TestExec(t *testing.T) {
 | 
					func TestPodAndContainer(t *testing.T) {
 | 
				
			||||||
 | 
						tests := []struct {
 | 
				
			||||||
 | 
							args              []string
 | 
				
			||||||
 | 
							p                 *execParams
 | 
				
			||||||
 | 
							expectError       bool
 | 
				
			||||||
 | 
							expectedPod       string
 | 
				
			||||||
 | 
							expectedContainer string
 | 
				
			||||||
 | 
						}{
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								p:           &execParams{},
 | 
				
			||||||
 | 
								expectError: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								p:           &execParams{podName: "foo"},
 | 
				
			||||||
 | 
								expectError: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								p:           &execParams{podName: "foo", containerName: "bar"},
 | 
				
			||||||
 | 
								expectError: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								p:           &execParams{podName: "foo"},
 | 
				
			||||||
 | 
								args:        []string{"cmd"},
 | 
				
			||||||
 | 
								expectedPod: "foo",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								p:           &execParams{},
 | 
				
			||||||
 | 
								args:        []string{"foo"},
 | 
				
			||||||
 | 
								expectError: true,
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								p:           &execParams{},
 | 
				
			||||||
 | 
								args:        []string{"foo", "cmd"},
 | 
				
			||||||
 | 
								expectedPod: "foo",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								p:                 &execParams{containerName: "bar"},
 | 
				
			||||||
 | 
								args:              []string{"foo", "cmd"},
 | 
				
			||||||
 | 
								expectedPod:       "foo",
 | 
				
			||||||
 | 
								expectedContainer: "bar",
 | 
				
			||||||
 | 
							},
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						for _, test := range tests {
 | 
				
			||||||
 | 
							cmd := &cobra.Command{}
 | 
				
			||||||
 | 
							podName, containerName, err := extractPodAndContainer(cmd, test.args, test.p)
 | 
				
			||||||
 | 
							if podName != test.expectedPod {
 | 
				
			||||||
 | 
								t.Errorf("expected: %s, got: %s", test.expectedPod, podName)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if containerName != test.expectedContainer {
 | 
				
			||||||
 | 
								t.Errorf("expected: %s, got: %s", test.expectedContainer, containerName)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if test.expectError && err == nil {
 | 
				
			||||||
 | 
								t.Error("unexpected non-error")
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if !test.expectError && err != nil {
 | 
				
			||||||
 | 
								t.Errorf("unexpected error: %v", err)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					func TestExec(t *testing.T) {
 | 
				
			||||||
	tests := []struct {
 | 
						tests := []struct {
 | 
				
			||||||
		name, version, podPath, execPath, container string
 | 
							name, version, podPath, execPath, container string
 | 
				
			||||||
		nsInQuery                                   bool
 | 
							nsInQuery                                   bool
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1021,7 +1021,7 @@ func (dm *DockerManager) ExecInContainer(containerId string, cmd []string, stdin
 | 
				
			|||||||
	} else {
 | 
						} else {
 | 
				
			||||||
		if stdin != nil {
 | 
							if stdin != nil {
 | 
				
			||||||
			// Use an os.Pipe here as it returns true *os.File objects.
 | 
								// Use an os.Pipe here as it returns true *os.File objects.
 | 
				
			||||||
			// This way, if you run 'kubectl exec -p <pod> -i bash' (no tty) and type 'exit',
 | 
								// This way, if you run 'kubectl exec <pod> -i bash' (no tty) and type 'exit',
 | 
				
			||||||
			// the call below to command.Run() can unblock because its Stdin is the read half
 | 
								// the call below to command.Run() can unblock because its Stdin is the read half
 | 
				
			||||||
			// of the pipe.
 | 
								// of the pipe.
 | 
				
			||||||
			r, w, err := os.Pipe()
 | 
								r, w, err := os.Pipe()
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -980,7 +980,7 @@ func (r *runtime) ExecInContainer(containerID string, cmd []string, stdin io.Rea
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
	if stdin != nil {
 | 
						if stdin != nil {
 | 
				
			||||||
		// Use an os.Pipe here as it returns true *os.File objects.
 | 
							// Use an os.Pipe here as it returns true *os.File objects.
 | 
				
			||||||
		// This way, if you run 'kubectl exec -p <pod> -i bash' (no tty) and type 'exit',
 | 
							// This way, if you run 'kubectl exec <pod> -i bash' (no tty) and type 'exit',
 | 
				
			||||||
		// the call below to command.Run() can unblock because its Stdin is the read half
 | 
							// the call below to command.Run() can unblock because its Stdin is the read half
 | 
				
			||||||
		// of the pipe.
 | 
							// of the pipe.
 | 
				
			||||||
		r, w, err := os.Pipe()
 | 
							r, w, err := os.Pipe()
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user