Merge pull request #30754 from yongtang/25696-stop-signal

Add `--stop-signal` for `service create` and `service update`
This commit is contained in:
Sebastiaan van Stijn 2017-03-01 18:10:57 +01:00 committed by GitHub
commit bb9f19503c
10 changed files with 106 additions and 39 deletions

View File

@ -1921,6 +1921,9 @@ definitions:
type: "array" type: "array"
items: items:
$ref: "#/definitions/Mount" $ref: "#/definitions/Mount"
StopSignal:
description: "Signal to stop the container."
type: "string"
StopGracePeriod: StopGracePeriod:
description: "Amount of time to wait for the container to terminate before forcefully killing it." description: "Amount of time to wait for the container to terminate before forcefully killing it."
type: "integer" type: "integer"

View File

@ -32,6 +32,7 @@ type ContainerSpec struct {
Dir string `json:",omitempty"` Dir string `json:",omitempty"`
User string `json:",omitempty"` User string `json:",omitempty"`
Groups []string `json:",omitempty"` Groups []string `json:",omitempty"`
StopSignal string `json:",omitempty"`
TTY bool `json:",omitempty"` TTY bool `json:",omitempty"`
OpenStdin bool `json:",omitempty"` OpenStdin bool `json:",omitempty"`
ReadOnly bool `json:",omitempty"` ReadOnly bool `json:",omitempty"`

View File

@ -269,6 +269,7 @@ type serviceOptions struct {
workdir string workdir string
user string user string
groups opts.ListOpts groups opts.ListOpts
stopSignal string
tty bool tty bool
readOnly bool readOnly bool
mounts opts.MountOpt mounts opts.MountOpt
@ -372,17 +373,18 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
}, },
TaskTemplate: swarm.TaskSpec{ TaskTemplate: swarm.TaskSpec{
ContainerSpec: swarm.ContainerSpec{ ContainerSpec: swarm.ContainerSpec{
Image: opts.image, Image: opts.image,
Args: opts.args, Args: opts.args,
Env: currentEnv, Env: currentEnv,
Hostname: opts.hostname, Hostname: opts.hostname,
Labels: runconfigopts.ConvertKVStringsToMap(opts.containerLabels.GetAll()), Labels: runconfigopts.ConvertKVStringsToMap(opts.containerLabels.GetAll()),
Dir: opts.workdir, Dir: opts.workdir,
User: opts.user, User: opts.user,
Groups: opts.groups.GetAll(), Groups: opts.groups.GetAll(),
TTY: opts.tty, StopSignal: opts.stopSignal,
ReadOnly: opts.readOnly, TTY: opts.tty,
Mounts: opts.mounts.Value(), ReadOnly: opts.readOnly,
Mounts: opts.mounts.Value(),
DNSConfig: &swarm.DNSConfig{ DNSConfig: &swarm.DNSConfig{
Nameservers: opts.dns.GetAll(), Nameservers: opts.dns.GetAll(),
Search: opts.dnsSearch.GetAll(), Search: opts.dnsSearch.GetAll(),
@ -470,6 +472,9 @@ func addServiceFlags(cmd *cobra.Command, opts *serviceOptions) {
flags.BoolVar(&opts.readOnly, flagReadOnly, false, "Mount the container's root filesystem as read only") flags.BoolVar(&opts.readOnly, flagReadOnly, false, "Mount the container's root filesystem as read only")
flags.SetAnnotation(flagReadOnly, "version", []string{"1.27"}) flags.SetAnnotation(flagReadOnly, "version", []string{"1.27"})
flags.StringVar(&opts.stopSignal, flagStopSignal, "", "Signal to stop the container")
flags.SetAnnotation(flagStopSignal, "version", []string{"1.27"})
} }
const ( const (
@ -523,6 +528,7 @@ const (
flagRestartMaxAttempts = "restart-max-attempts" flagRestartMaxAttempts = "restart-max-attempts"
flagRestartWindow = "restart-window" flagRestartWindow = "restart-window"
flagStopGracePeriod = "stop-grace-period" flagStopGracePeriod = "stop-grace-period"
flagStopSignal = "stop-signal"
flagTTY = "tty" flagTTY = "tty"
flagUpdateDelay = "update-delay" flagUpdateDelay = "update-delay"
flagUpdateFailureAction = "update-failure-action" flagUpdateFailureAction = "update-failure-action"

View File

@ -349,6 +349,8 @@ func updateService(flags *pflag.FlagSet, spec *swarm.ServiceSpec) error {
cspec.ReadOnly = readOnly cspec.ReadOnly = readOnly
} }
updateString(flagStopSignal, &cspec.StopSignal)
return nil return nil
} }

View File

@ -441,3 +441,25 @@ func TestUpdateReadOnly(t *testing.T) {
updateService(flags, spec) updateService(flags, spec)
assert.Equal(t, cspec.ReadOnly, false) assert.Equal(t, cspec.ReadOnly, false)
} }
func TestUpdateStopSignal(t *testing.T) {
spec := &swarm.ServiceSpec{}
cspec := &spec.TaskTemplate.ContainerSpec
// Update with --stop-signal=SIGUSR1
flags := newUpdateCommand(nil).Flags()
flags.Set("stop-signal", "SIGUSR1")
updateService(flags, spec)
assert.Equal(t, cspec.StopSignal, "SIGUSR1")
// Update without --stop-signal, no change
flags = newUpdateCommand(nil).Flags()
updateService(flags, spec)
assert.Equal(t, cspec.StopSignal, "SIGUSR1")
// Update with --stop-signal=SIGWINCH
flags = newUpdateCommand(nil).Flags()
flags.Set("stop-signal", "SIGWINCH")
updateService(flags, spec)
assert.Equal(t, cspec.StopSignal, "SIGWINCH")
}

View File

@ -14,20 +14,21 @@ import (
func containerSpecFromGRPC(c *swarmapi.ContainerSpec) types.ContainerSpec { func containerSpecFromGRPC(c *swarmapi.ContainerSpec) types.ContainerSpec {
containerSpec := types.ContainerSpec{ containerSpec := types.ContainerSpec{
Image: c.Image, Image: c.Image,
Labels: c.Labels, Labels: c.Labels,
Command: c.Command, Command: c.Command,
Args: c.Args, Args: c.Args,
Hostname: c.Hostname, Hostname: c.Hostname,
Env: c.Env, Env: c.Env,
Dir: c.Dir, Dir: c.Dir,
User: c.User, User: c.User,
Groups: c.Groups, Groups: c.Groups,
TTY: c.TTY, StopSignal: c.StopSignal,
OpenStdin: c.OpenStdin, TTY: c.TTY,
ReadOnly: c.ReadOnly, OpenStdin: c.OpenStdin,
Hosts: c.Hosts, ReadOnly: c.ReadOnly,
Secrets: secretReferencesFromGRPC(c.Secrets), Hosts: c.Hosts,
Secrets: secretReferencesFromGRPC(c.Secrets),
} }
if c.DNSConfig != nil { if c.DNSConfig != nil {
@ -136,20 +137,21 @@ func secretReferencesFromGRPC(sr []*swarmapi.SecretReference) []*types.SecretRef
func containerToGRPC(c types.ContainerSpec) (*swarmapi.ContainerSpec, error) { func containerToGRPC(c types.ContainerSpec) (*swarmapi.ContainerSpec, error) {
containerSpec := &swarmapi.ContainerSpec{ containerSpec := &swarmapi.ContainerSpec{
Image: c.Image, Image: c.Image,
Labels: c.Labels, Labels: c.Labels,
Command: c.Command, Command: c.Command,
Args: c.Args, Args: c.Args,
Hostname: c.Hostname, Hostname: c.Hostname,
Env: c.Env, Env: c.Env,
Dir: c.Dir, Dir: c.Dir,
User: c.User, User: c.User,
Groups: c.Groups, Groups: c.Groups,
TTY: c.TTY, StopSignal: c.StopSignal,
OpenStdin: c.OpenStdin, TTY: c.TTY,
ReadOnly: c.ReadOnly, OpenStdin: c.OpenStdin,
Hosts: c.Hosts, ReadOnly: c.ReadOnly,
Secrets: secretReferencesToGRPC(c.Secrets), Hosts: c.Hosts,
Secrets: secretReferencesToGRPC(c.Secrets),
} }
if c.DNSConfig != nil { if c.DNSConfig != nil {

View File

@ -185,6 +185,7 @@ func (c *containerConfig) exposedPorts() map[nat.Port]struct{} {
func (c *containerConfig) config() *enginecontainer.Config { func (c *containerConfig) config() *enginecontainer.Config {
config := &enginecontainer.Config{ config := &enginecontainer.Config{
Labels: c.labels(), Labels: c.labels(),
StopSignal: c.spec().StopSignal,
Tty: c.spec().TTY, Tty: c.spec().TTY,
OpenStdin: c.spec().OpenStdin, OpenStdin: c.spec().OpenStdin,
User: c.spec().User, User: c.spec().User,

View File

@ -58,6 +58,7 @@ Options:
--restart-window duration Window used to evaluate the restart policy (ns|us|ms|s|m|h) --restart-window duration Window used to evaluate the restart policy (ns|us|ms|s|m|h)
--secret secret Specify secrets to expose to the service --secret secret Specify secrets to expose to the service
--stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h) --stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h)
--stop-signal string Signal to stop the container
-t, --tty Allocate a pseudo-TTY -t, --tty Allocate a pseudo-TTY
--update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s) --update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s)
--update-failure-action string Action on update failure ("pause"|"continue") (default "pause") --update-failure-action string Action on update failure ("pause"|"continue") (default "pause")

View File

@ -70,6 +70,7 @@ Options:
--secret-add secret Add or update a secret on a service --secret-add secret Add or update a secret on a service
--secret-rm list Remove a secret (default []) --secret-rm list Remove a secret (default [])
--stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h) --stop-grace-period duration Time to wait before force killing a container (ns|us|ms|s|m|h)
--stop-signal string Signal to stop the container
-t, --tty Allocate a pseudo-TTY -t, --tty Allocate a pseudo-TTY
--update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s) --update-delay duration Delay between updates (ns|us|ms|s|m|h) (default 0s)
--update-failure-action string Action on update failure ("pause"|"continue") (default "pause") --update-failure-action string Action on update failure ("pause"|"continue") (default "pause")

View File

@ -1764,3 +1764,31 @@ func (s *DockerSwarmSuite) TestNetworkInspectWithDuplicateNames(c *check.C) {
c.Assert(err, checker.NotNil, check.Commentf(out)) c.Assert(err, checker.NotNil, check.Commentf(out))
c.Assert(out, checker.Contains, "network foo is ambiguous (2 matches found based on name)") c.Assert(out, checker.Contains, "network foo is ambiguous (2 matches found based on name)")
} }
func (s *DockerSwarmSuite) TestSwarmStopSignal(c *check.C) {
testRequires(c, DaemonIsLinux, UserNamespaceROMount)
d := s.AddDaemon(c, true, true)
out, err := d.Cmd("service", "create", "--name", "top", "--stop-signal=SIGHUP", "busybox", "top")
c.Assert(err, checker.IsNil, check.Commentf(out))
// make sure task has been deployed.
waitAndAssert(c, defaultReconciliationTimeout, d.CheckActiveContainerCount, checker.Equals, 1)
out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.StopSignal }}", "top")
c.Assert(err, checker.IsNil, check.Commentf(out))
c.Assert(strings.TrimSpace(out), checker.Equals, "SIGHUP")
containers := d.ActiveContainers()
out, err = d.Cmd("inspect", "--type", "container", "--format", "{{.Config.StopSignal}}", containers[0])
c.Assert(err, checker.IsNil, check.Commentf(out))
c.Assert(strings.TrimSpace(out), checker.Equals, "SIGHUP")
out, err = d.Cmd("service", "update", "--stop-signal=SIGUSR1", "top")
c.Assert(err, checker.IsNil, check.Commentf(out))
out, err = d.Cmd("service", "inspect", "--format", "{{ .Spec.TaskTemplate.ContainerSpec.StopSignal }}", "top")
c.Assert(err, checker.IsNil, check.Commentf(out))
c.Assert(strings.TrimSpace(out), checker.Equals, "SIGUSR1")
}