소스 검색

Merge pull request #28076 from yongtang/25644-docker-service-tty

Add `--tty` to `docker service create/update`
Daniel Nephin 8 년 전
부모
커밋
69efb4652c

+ 5 - 0
cli/command/service/opts.go

@@ -294,6 +294,7 @@ type serviceOptions struct {
 	workdir         string
 	user            string
 	groups          []string
+	tty             bool
 	mounts          opts.MountOpt
 
 	resources resourceOptions
@@ -365,6 +366,7 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
 				Dir:             opts.workdir,
 				User:            opts.user,
 				Groups:          opts.groups,
+				TTY:             opts.tty,
 				Mounts:          opts.mounts.Value(),
 				StopGracePeriod: opts.stopGrace.Value(),
 			},
@@ -450,6 +452,8 @@ func addServiceFlags(cmd *cobra.Command, opts *serviceOptions) {
 	flags.Var(&opts.healthcheck.timeout, flagHealthTimeout, "Maximum time to allow one check to run")
 	flags.IntVar(&opts.healthcheck.retries, flagHealthRetries, 0, "Consecutive failures needed to report unhealthy")
 	flags.BoolVar(&opts.healthcheck.noHealthcheck, flagNoHealthcheck, false, "Disable any container-specified HEALTHCHECK")
+
+	flags.BoolVarP(&opts.tty, flagTTY, "t", false, "Allocate a pseudo-TTY")
 }
 
 const (
@@ -490,6 +494,7 @@ const (
 	flagRestartMaxAttempts    = "restart-max-attempts"
 	flagRestartWindow         = "restart-window"
 	flagStopGracePeriod       = "stop-grace-period"
+	flagTTY                   = "tty"
 	flagUpdateDelay           = "update-delay"
 	flagUpdateFailureAction   = "update-failure-action"
 	flagUpdateMaxFailureRatio = "update-max-failure-ratio"

+ 8 - 0
cli/command/service/update.go

@@ -274,6 +274,14 @@ func updateService(flags *pflag.FlagSet, spec *swarm.ServiceSpec) error {
 		return err
 	}
 
+	if flags.Changed(flagTTY) {
+		tty, err := flags.GetBool(flagTTY)
+		if err != nil {
+			return err
+		}
+		cspec.TTY = tty
+	}
+
 	return nil
 }
 

+ 2 - 0
daemon/cluster/convert/container.go

@@ -22,6 +22,7 @@ func containerSpecFromGRPC(c *swarmapi.ContainerSpec) types.ContainerSpec {
 		Dir:      c.Dir,
 		User:     c.User,
 		Groups:   c.Groups,
+		TTY:      c.TTY,
 	}
 
 	// Mounts
@@ -77,6 +78,7 @@ func containerToGRPC(c types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
 		Dir:      c.Dir,
 		User:     c.User,
 		Groups:   c.Groups,
+		TTY:      c.TTY,
 	}
 
 	if c.StopGracePeriod != nil {

+ 1 - 0
daemon/cluster/executor/container/container.go

@@ -127,6 +127,7 @@ func (c *containerConfig) image() string {
 func (c *containerConfig) config() *enginecontainer.Config {
 	config := &enginecontainer.Config{
 		Labels:      c.labels(),
+		Tty:         c.spec().TTY,
 		User:        c.spec().User,
 		Hostname:    c.spec().Hostname,
 		Env:         c.spec().Env,

+ 1 - 0
docs/reference/api/docker_remote_api.md

@@ -167,6 +167,7 @@ This section lists each version from latest to oldest.  Each listing includes a
 * The `HostConfig` field now includes `NanoCPUs` that represents CPU quota in units of 10<sup>-9</sup> CPUs.
 * `GET /info` now returns more structured information about security options.
 * The `HostConfig` field now includes `CpuCount` that represents the number of CPUs available for execution by the container. Windows daemon only.
+* `POST /services/create` and `POST /services/(id or name)/update` now accept the `TTY` parameter, which allocate a pseudo-TTY in container.
 
 ### v1.24 API changes
 

+ 6 - 2
docs/reference/api/docker_remote_api_v1.25.md

@@ -5112,7 +5112,8 @@ image](#create-an-image) section for more details.
               }
             }
           ],
-          "User": "33"
+          "User": "33",
+          "TTY": false
         },
         "LogDriver": {
           "Name": "json-file",
@@ -5189,6 +5190,7 @@ image](#create-an-image) section for more details.
         - **User** – A string value specifying the user inside the container.
         - **Labels** – A map of labels to associate with the service (e.g.,
           `{"key":"value", "key2":"value2"}`).
+        - **TTY** – A boolean indicating whether a pseudo-TTY should be allocated.
         - **Mounts** – Specification for mounts to be added to containers
           created as part of the service.
             - **Target** – Container path.
@@ -5390,7 +5392,8 @@ image](#create-an-image) section for more details.
           "Image": "busybox",
           "Args": [
             "top"
-          ]
+          ],
+          "TTY": true
         },
         "Resources": {
           "Limits": {},
@@ -5438,6 +5441,7 @@ image](#create-an-image) section for more details.
         - **User** – A string value specifying the user inside the container.
         - **Labels** – A map of labels to associate with the service (e.g.,
           `{"key":"value", "key2":"value2"}`).
+        - **TTY** – A boolean indicating whether a pseudo-TTY should be allocated.
         - **Mounts** – Specification for mounts to be added to containers created as part of the new
           service.
             - **Target** – Container path.

+ 1 - 0
docs/reference/commandline/service_create.md

@@ -52,6 +52,7 @@ Options:
       --restart-max-attempts value       Maximum number of restarts before giving up (default none)
       --restart-window value             Window used to evaluate the restart policy (default none)
       --stop-grace-period value          Time to wait before force killing a container (default none)
+  -t, --tty                              Allocate a pseudo-TTY
       --update-delay duration            Delay between updates
       --update-failure-action string     Action on update failure (pause|continue) (default "pause")
       --update-max-failure-ratio value   Failure rate to tolerate during an update

+ 1 - 0
docs/reference/commandline/service_update.md

@@ -58,6 +58,7 @@ Options:
       --restart-window value             Window used to evaluate the restart policy (default none)
       --rollback                         Rollback to previous specification
       --stop-grace-period value          Time to wait before force killing a container (default none)
+  -t, --tty                              Allocate a pseudo-TTY
       --update-delay duration            Delay between updates
       --update-failure-action string     Action on update failure (pause|continue) (default "pause")
       --update-max-failure-ratio value   Failure rate to tolerate during an update

+ 71 - 0
integration-cli/docker_cli_swarm_test.go

@@ -718,3 +718,74 @@ func (s *DockerSwarmSuite) TestSwarmServiceEnvFile(c *check.C) {
 	c.Assert(err, checker.IsNil)
 	c.Assert(out, checker.Contains, "[VAR1=C VAR2]")
 }
+
+func (s *DockerSwarmSuite) TestSwarmServiceTTY(c *check.C) {
+	d := s.AddDaemon(c, true, true)
+
+	name := "top"
+
+	ttyCheck := "if [ -t 0 ]; then echo TTY > /status && top; else echo none > /status && top; fi"
+
+	// Without --tty
+	expectedOutput := "none"
+	out, err := d.Cmd("service", "create", "--name", name, "busybox", "sh", "-c", ttyCheck)
+	c.Assert(err, checker.IsNil)
+
+	// Make sure task has been deployed.
+	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
+
+	// We need to get the container id.
+	out, err = d.Cmd("ps", "-a", "-q", "--no-trunc")
+	c.Assert(err, checker.IsNil)
+	id := strings.TrimSpace(out)
+
+	out, err = d.Cmd("exec", id, "cat", "/status")
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out))
+
+	// Remove service
+	out, err = d.Cmd("service", "rm", name)
+	c.Assert(err, checker.IsNil)
+	// Make sure container has been destroyed.
+	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 0)
+
+	// With --tty
+	expectedOutput = "TTY"
+	out, err = d.Cmd("service", "create", "--name", name, "--tty", "busybox", "sh", "-c", ttyCheck)
+	c.Assert(err, checker.IsNil)
+
+	// Make sure task has been deployed.
+	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
+
+	// We need to get the container id.
+	out, err = d.Cmd("ps", "-a", "-q", "--no-trunc")
+	c.Assert(err, checker.IsNil)
+	id = strings.TrimSpace(out)
+
+	out, err = d.Cmd("exec", id, "cat", "/status")
+	c.Assert(err, checker.IsNil)
+	c.Assert(out, checker.Contains, expectedOutput, check.Commentf("Expected '%s', but got %q", expectedOutput, out))
+}
+
+func (s *DockerSwarmSuite) TestSwarmServiceTTYUpdate(c *check.C) {
+	d := s.AddDaemon(c, true, true)
+
+	// Create a service
+	name := "top"
+	_, err := d.Cmd("service", "create", "--name", name, "busybox", "top")
+	c.Assert(err, checker.IsNil)
+
+	// Make sure task has been deployed.
+	waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, 1)
+
+	out, err := d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name)
+	c.Assert(err, checker.IsNil)
+	c.Assert(strings.TrimSpace(out), checker.Equals, "false")
+
+	_, err = d.Cmd("service", "update", "--tty", name)
+	c.Assert(err, checker.IsNil)
+
+	out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.TTY }}", name)
+	c.Assert(err, checker.IsNil)
+	c.Assert(strings.TrimSpace(out), checker.Equals, "true")
+}