Merge pull request #15053 from smarterclayton/stdin_once

Auto commit by PR queue bot
This commit is contained in:
k8s-merge-robot 2015-10-17 00:03:32 -07:00
commit d3ca12f61b
25 changed files with 22721 additions and 22482 deletions

View File

@ -12903,7 +12903,11 @@
},
"stdin": {
"type": "boolean",
"description": "Whether this container should allocate a buffer for stdin in the container runtime. Default is false."
"description": "Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false."
},
"stdinOnce": {
"type": "boolean",
"description": "Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false"
},
"tty": {
"type": "boolean",

View File

@ -3537,7 +3537,11 @@
},
"stdin": {
"type": "boolean",
"description": "Whether this container should allocate a buffer for stdin in the container runtime. Default is false."
"description": "Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false."
},
"stdinOnce": {
"type": "boolean",
"description": "Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false"
},
"tty": {
"type": "boolean",

View File

@ -753,6 +753,7 @@ _kubectl_run()
flags+=("--image=")
flags+=("--labels=")
two_word_flags+=("-l")
flags+=("--leave-stdin-open")
flags+=("--limits=")
flags+=("--no-headers")
flags+=("--output=")

View File

@ -50,6 +50,10 @@ Creates a replication controller to manage the created container(s).
\fB\-l\fP, \fB\-\-labels\fP=""
Labels to apply to the pod(s).
.PP
\fB\-\-leave\-stdin\-open\fP=false
If the pod is started in interactive mode or with stdin, leave stdin open after the first attach completes. By default, stdin will be closed after the first attach completes.
.PP
\fB\-\-limits\fP=""
The resource requirement limits for this container. For example, 'cpu=200m,memory=512Mi'

View File

@ -87,6 +87,7 @@ $ kubectl run nginx --image=nginx --command -- <cmd> <arg1> ... <argN>
--hostport=-1: The host port mapping for the container port. To demonstrate a single-machine container.
--image="": The image for the container to run.
-l, --labels="": Labels to apply to the pod(s).
--leave-stdin-open[=false]: If the pod is started in interactive mode or with stdin, leave stdin open after the first attach completes. By default, stdin will be closed after the first attach completes.
--limits="": The resource requirement limits for this container. For example, 'cpu=200m,memory=512Mi'
--no-headers[=false]: When using the default output, don't print headers.
-o, --output="": Output format. One of: json|yaml|wide|name|go-template=...|go-template-file=...|jsonpath=...|jsonpath-file=... See golang template [http://golang.org/pkg/text/template/#pkg-overview] and jsonpath template [http://releases.k8s.io/HEAD/docs/user-guide/jsonpath.md].

View File

@ -149,6 +149,7 @@ kubelet-timeout
kube-master
label-columns
last-release-pr
leave-stdin-open
limit-bytes
load-balancer-ip
log-flush-frequency

View File

@ -238,6 +238,7 @@ func deepCopy_api_Container(in Container, out *Container, c *conversion.Cloner)
out.SecurityContext = nil
}
out.Stdin = in.Stdin
out.StdinOnce = in.StdinOnce
out.TTY = in.TTY
return nil
}

File diff suppressed because it is too large Load Diff

View File

@ -794,8 +794,9 @@ type Container struct {
// Variables for interactive containers, these have very specialized use-cases (e.g. debugging)
// and shouldn't be used for general purpose containers.
Stdin bool `json:"stdin,omitempty"`
TTY bool `json:"tty,omitempty"`
Stdin bool `json:"stdin,omitempty"`
StdinOnce bool `json:"stdinOnce,omitempty"`
TTY bool `json:"tty,omitempty"`
}
// Handler defines a specific action that should be taken

View File

@ -292,6 +292,7 @@ func autoconvert_api_Container_To_v1_Container(in *api.Container, out *Container
out.SecurityContext = nil
}
out.Stdin = in.Stdin
out.StdinOnce = in.StdinOnce
out.TTY = in.TTY
return nil
}
@ -3305,6 +3306,7 @@ func autoconvert_v1_Container_To_api_Container(in *Container, out *api.Container
out.SecurityContext = nil
}
out.Stdin = in.Stdin
out.StdinOnce = in.StdinOnce
out.TTY = in.TTY
return nil
}

View File

@ -274,6 +274,7 @@ func deepCopy_v1_Container(in Container, out *Container, c *conversion.Cloner) e
out.SecurityContext = nil
}
out.Stdin = in.Stdin
out.StdinOnce = in.StdinOnce
out.TTY = in.TTY
return nil
}

File diff suppressed because it is too large Load Diff

View File

@ -976,9 +976,18 @@ type Container struct {
// Variables for interactive containers, these have very specialized use-cases (e.g. debugging)
// and shouldn't be used for general purpose containers.
// Whether this container should allocate a buffer for stdin in the container runtime.
// Whether this container should allocate a buffer for stdin in the container runtime. If this
// is not set, reads from stdin in the container will always result in EOF.
// Default is false.
Stdin bool `json:"stdin,omitempty"`
// Whether the container runtime should close the stdin channel after it has been opened by
// a single attach. When stdin is true the stdin stream will remain open across multiple attach
// sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the
// first client attaches to stdin, and then remains open and accepts data until the client disconnects,
// at which time stdin is closed and remains closed until the container is restarted. If this
// flag is false, a container processes that reads from stdin will never receive an EOF.
// Default is false
StdinOnce bool `json:"stdinOnce,omitempty"`
// Whether this container should allocate a TTY for itself, also requires 'stdin' to be true.
// Default is false.
TTY bool `json:"tty,omitempty"`

View File

@ -132,7 +132,8 @@ var map_Container = map[string]string{
"terminationMessagePath": "Optional: Path at which the file to which the container's termination message will be written is mounted into the container's filesystem. Message written is intended to be brief final status, such as an assertion failure message. Defaults to /dev/termination-log. Cannot be updated.",
"imagePullPolicy": "Image pull policy. One of Always, Never, IfNotPresent. Defaults to Always if :latest tag is specified, or IfNotPresent otherwise. Cannot be updated. More info: http://releases.k8s.io/HEAD/docs/user-guide/images.md#updating-images",
"securityContext": "Security options the pod should run with. More info: http://releases.k8s.io/HEAD/docs/design/security_context.md",
"stdin": "Whether this container should allocate a buffer for stdin in the container runtime. Default is false.",
"stdin": "Whether this container should allocate a buffer for stdin in the container runtime. If this is not set, reads from stdin in the container will always result in EOF. Default is false.",
"stdinOnce": "Whether the container runtime should close the stdin channel after it has been opened by a single attach. When stdin is true the stdin stream will remain open across multiple attach sessions. If stdinOnce is set to true, stdin is opened on container start, is empty until the first client attaches to stdin, and then remains open and accepts data until the client disconnects, at which time stdin is closed and remains closed until the container is restarted. If this flag is false, a container processes that reads from stdin will never receive an EOF. Default is false",
"tty": "Whether this container should allocate a TTY for itself, also requires 'stdin' to be true. Default is false.",
}

View File

@ -175,6 +175,7 @@ func deepCopy_api_Container(in api.Container, out *api.Container, c *conversion.
out.SecurityContext = nil
}
out.Stdin = in.Stdin
out.StdinOnce = in.StdinOnce
out.TTY = in.TTY
return nil
}

View File

@ -205,6 +205,7 @@ func autoconvert_api_Container_To_v1_Container(in *api.Container, out *v1.Contai
out.SecurityContext = nil
}
out.Stdin = in.Stdin
out.StdinOnce = in.StdinOnce
out.TTY = in.TTY
return nil
}
@ -1255,6 +1256,7 @@ func autoconvert_v1_Container_To_api_Container(in *v1.Container, out *api.Contai
out.SecurityContext = nil
}
out.Stdin = in.Stdin
out.StdinOnce = in.StdinOnce
out.TTY = in.TTY
return nil
}

View File

@ -213,6 +213,7 @@ func deepCopy_v1_Container(in v1.Container, out *v1.Container, c *conversion.Clo
out.SecurityContext = nil
}
out.Stdin = in.Stdin
out.StdinOnce = in.StdinOnce
out.TTY = in.TTY
return nil
}

View File

@ -202,8 +202,14 @@ func (p *AttachOptions) Run() error {
Resource("pods").
Name(pod.Name).
Namespace(pod.Namespace).
SubResource("attach").
Param("container", p.GetContainerName(pod))
SubResource("attach")
req.VersionedParams(&api.PodAttachOptions{
Container: p.GetContainerName(pod),
Stdin: stdin != nil,
Stdout: p.Out != nil,
Stderr: p.Err != nil,
TTY: tty,
}, api.Scheme)
return p.Attach.Attach("POST", req.URL(), p.Config, stdin, p.Out, p.Err, tty)
}

View File

@ -186,6 +186,9 @@ func TestAttach(t *testing.T) {
if ex.method != "POST" {
t.Errorf("%s: Did not get method for attach request: %s", test.name, ex.method)
}
if ex.url.Query().Get("container") != "bar" {
t.Errorf("%s: Did not have query parameters: %s", test.name, ex.url.Query())
}
}
}

View File

@ -90,6 +90,7 @@ func NewCmdRun(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer) *c
cmd.Flags().BoolP("stdin", "i", false, "Keep stdin open on the container(s) in the pod, even if nothing is attached.")
cmd.Flags().Bool("tty", false, "Allocated a TTY for each container in the pod. Because -t is currently shorthand for --template, -t is not supported for --tty. This shorthand is deprecated and we expect to adopt -t for --tty soon.")
cmd.Flags().Bool("attach", false, "If true, wait for the Pod to start running, and then attach to the Pod as if 'kubectl attach ...' were called. Default false, unless '-i/--interactive' is set, in which case the default is true.")
cmd.Flags().Bool("leave-stdin-open", false, "If the pod is started in interactive mode or with stdin, leave stdin open after the first attach completes. By default, stdin will be closed after the first attach completes.")
cmd.Flags().String("restart", "Always", "The restart policy for this Pod. Legal values [Always, OnFailure, Never]. If set to 'Always' a replication controller is created for this pod, if set to OnFailure or Never, only the Pod is created and --replicas must be 1. Default 'Always'")
cmd.Flags().Bool("command", false, "If true and extra arguments are present, use them as the 'command' field in the container, rather than the 'args' field which is the default.")
cmd.Flags().String("requests", "", "The resource requirement requests for this container. For example, 'cpu=100m,memory=256Mi'")
@ -126,7 +127,7 @@ func Run(f *cmdutil.Factory, cmdIn io.Reader, cmdOut, cmdErr io.Writer, cmd *cob
return err
}
if restartPolicy != api.RestartPolicyAlways && replicas != 1 {
return cmdutil.UsageError(cmd, fmt.Sprintf("--restart=%s requires that --repliacs=1, found %d", restartPolicy, replicas))
return cmdutil.UsageError(cmd, fmt.Sprintf("--restart=%s requires that --replicas=1, found %d", restartPolicy, replicas))
}
generatorName := cmdutil.GetFlagString(cmd, "generator")
if len(generatorName) == 0 {

View File

@ -267,6 +267,7 @@ func (BasicPod) ParamNames() []GeneratorParam {
{"port", false},
{"hostport", false},
{"stdin", false},
{"leave-stdin-open", false},
{"tty", false},
{"restart", false},
{"command", false},
@ -333,6 +334,10 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
if err != nil {
return nil, err
}
leaveStdinOpen, err := GetBool(params, "leave-stdin-open", false)
if err != nil {
return nil, err
}
tty, err := GetBool(params, "tty", false)
if err != nil {
@ -360,6 +365,7 @@ func (BasicPod) Generate(genericParams map[string]interface{}) (runtime.Object,
Image: params["image"],
ImagePullPolicy: api.PullIfNotPresent,
Stdin: stdin,
StdinOnce: !leaveStdinOpen && stdin,
TTY: tty,
Resources: resourceRequirements,
},

View File

@ -553,6 +553,63 @@ func TestGeneratePod(t *testing.T) {
},
},
},
{
params: map[string]interface{}{
"name": "foo",
"image": "someimage",
"replicas": "1",
"labels": "foo=bar,baz=blah",
"stdin": "true",
},
expected: &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"},
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "foo",
Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent,
Stdin: true,
StdinOnce: true,
},
},
DNSPolicy: api.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways,
},
},
},
{
params: map[string]interface{}{
"name": "foo",
"image": "someimage",
"replicas": "1",
"labels": "foo=bar,baz=blah",
"stdin": "true",
"leave-stdin-open": "true",
},
expected: &api.Pod{
ObjectMeta: api.ObjectMeta{
Name: "foo",
Labels: map[string]string{"foo": "bar", "baz": "blah"},
},
Spec: api.PodSpec{
Containers: []api.Container{
{
Name: "foo",
Image: "someimage",
ImagePullPolicy: api.PullIfNotPresent,
Stdin: true,
StdinOnce: false,
},
},
DNSPolicy: api.DNSClusterFirst,
RestartPolicy: api.RestartPolicyAlways,
},
},
},
}
generator := BasicPod{}
for _, test := range tests {

View File

@ -760,6 +760,7 @@ func (dm *DockerManager) runContainer(
Labels: labels,
// Interactive containers:
OpenStdin: container.Stdin,
StdinOnce: container.StdinOnce,
Tty: container.TTY,
},
}

View File

@ -360,11 +360,49 @@ var _ = Describe("Kubectl client", func() {
})
It("should support inline execution and attach", func() {
By("executing a command with run and attach")
runOutput := runKubectl(fmt.Sprintf("--namespace=%v", ns), "run", "run-test", "--image=busybox", "--restart=Never", "--attach=true", "echo", "running", "in", "container")
expectedRunOutput := "running in container"
Expect(runOutput).To(ContainSubstring(expectedRunOutput))
// everything in the ns will be deleted at the end of the test
nsFlag := fmt.Sprintf("--namespace=%v", ns)
By("executing a command with run and attach with stdin")
runOutput := newKubectlCommand(nsFlag, "run", "run-test", "--image=busybox", "--restart=Never", "--attach=true", "--stdin", "--", "sh", "-c", "cat && echo 'stdin closed'").
withStdinData("abcd1234").
exec()
Expect(runOutput).To(ContainSubstring("abcd1234"))
Expect(runOutput).To(ContainSubstring("stdin closed"))
Expect(c.Pods(ns).Delete("run-test", api.NewDeleteOptions(0))).To(BeNil())
By("executing a command with run and attach without stdin")
runOutput = newKubectlCommand(fmt.Sprintf("--namespace=%v", ns), "run", "run-test-2", "--image=busybox", "--restart=Never", "--attach=true", "--leave-stdin-open=true", "--", "sh", "-c", "cat && echo 'stdin closed'").
withStdinData("abcd1234").
exec()
Expect(runOutput).ToNot(ContainSubstring("abcd1234"))
Expect(runOutput).To(ContainSubstring("stdin closed"))
Expect(c.Pods(ns).Delete("run-test-2", api.NewDeleteOptions(0))).To(BeNil())
By("executing a command with run and attach with stdin with open stdin should remain running")
runOutput = newKubectlCommand(nsFlag, "run", "run-test-3", "--image=busybox", "--restart=Never", "--attach=true", "--leave-stdin-open=true", "--stdin", "--", "sh", "-c", "cat && echo 'stdin closed'").
withStdinData("abcd1234\n").
exec()
Expect(runOutput).ToNot(ContainSubstring("stdin closed"))
if !checkPodsRunningReady(c, ns, []string{"run-test-3"}, time.Minute) {
Failf("Pod %q should still be running", "run-test-3")
}
// NOTE: we cannot guarantee our output showed up in the container logs before stdin was closed, so we have
// to loop test.
err := wait.PollImmediate(time.Second, time.Minute, func() (bool, error) {
if !checkPodsRunningReady(c, ns, []string{"run-test-3"}, 1*time.Second) {
Failf("Pod %q should still be running", "run-test-3")
}
logOutput := runKubectl(nsFlag, "logs", "run-test-3")
Expect(logOutput).ToNot(ContainSubstring("stdin closed"))
return strings.Contains(logOutput, "abcd1234"), nil
})
if err != nil {
os.Exit(1)
}
Expect(err).To(BeNil())
Expect(c.Pods(ns).Delete("run-test-3", api.NewDeleteOptions(0))).To(BeNil())
})
It("should support port-forward", func() {

View File

@ -1061,6 +1061,11 @@ func runKubectl(args ...string) string {
return newKubectlCommand(args...).exec()
}
// runKubectlInput is a convenience wrapper over kubectlBuilder that takes input to stdin
func runKubectlInput(data string, args ...string) string {
return newKubectlCommand(args...).withStdinData(data).exec()
}
func startCmdAndStreamOutput(cmd *exec.Cmd) (stdout, stderr io.ReadCloser, err error) {
stdout, err = cmd.StdoutPipe()
if err != nil {