Add --tty
to docker service create/update
This fix tries to add `--tty` to `docker service create/update`. As was specified in 25644, `TTY` flag has been added to SwarmKit and is already vendored. This fix add `--tty` to `docker service create/update`. Related document has been updated. Additional integration tests has been added. This fix fixes 25644. Signed-off-by: Yong Tang <yong.tang.github@outlook.com>
This commit is contained in:
parent
05b249e70f
commit
599be5a551
9 changed files with 96 additions and 2 deletions
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -5102,7 +5102,8 @@ image](#create-an-image) section for more details.
|
|||
}
|
||||
}
|
||||
],
|
||||
"User": "33"
|
||||
"User": "33",
|
||||
"TTY": false
|
||||
},
|
||||
"LogDriver": {
|
||||
"Name": "json-file",
|
||||
|
@ -5179,6 +5180,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.
|
||||
|
@ -5380,7 +5382,8 @@ image](#create-an-image) section for more details.
|
|||
"Image": "busybox",
|
||||
"Args": [
|
||||
"top"
|
||||
]
|
||||
],
|
||||
"TTY": true
|
||||
},
|
||||
"Resources": {
|
||||
"Limits": {},
|
||||
|
@ -5428,6 +5431,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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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")
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue