mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-25 20:53:33 +00:00
Merge pull request #15053 from smarterclayton/stdin_once
Auto commit by PR queue bot
This commit is contained in:
commit
d3ca12f61b
@ -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",
|
||||
|
@ -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",
|
||||
|
@ -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=")
|
||||
|
@ -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'
|
||||
|
@ -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].
|
||||
|
@ -149,6 +149,7 @@ kubelet-timeout
|
||||
kube-master
|
||||
label-columns
|
||||
last-release-pr
|
||||
leave-stdin-open
|
||||
limit-bytes
|
||||
load-balancer-ip
|
||||
log-flush-frequency
|
||||
|
@ -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
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
@ -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"`
|
||||
|
@ -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.",
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
},
|
||||
|
@ -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 {
|
||||
|
@ -760,6 +760,7 @@ func (dm *DockerManager) runContainer(
|
||||
Labels: labels,
|
||||
// Interactive containers:
|
||||
OpenStdin: container.Stdin,
|
||||
StdinOnce: container.StdinOnce,
|
||||
Tty: container.TTY,
|
||||
},
|
||||
}
|
||||
|
@ -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() {
|
||||
|
@ -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 {
|
||||
|
Loading…
Reference in New Issue
Block a user