mirror of https://github.com/k3s-io/k3s
Merge pull request #8604 from brendandburns/kubectl
Make exec more consistent with the rest of the kubectl commands.pull/6/head
commit
ffabf17ed4
|
@ -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
|
||||||
|
|
||||||
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/kubectl_exec.md?pixel)]()
|
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/docs/kubectl_exec.md?pixel)]()
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in New Issue