Merge pull request #15307 from calavera/stop_signal

Signal to stop a container.
This commit is contained in:
David Calavera 2015-09-11 09:25:18 -07:00
commit db54c79d7c
31 changed files with 214 additions and 43 deletions

View File

@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"strconv" "strconv"
"strings" "strings"
"syscall"
"time" "time"
"golang.org/x/net/websocket" "golang.org/x/net/websocket"
@ -220,32 +221,18 @@ func (s *Server) postContainersKill(ctx context.Context, w http.ResponseWriter,
return err return err
} }
var sig uint64 var sig syscall.Signal
name := vars["name"] name := vars["name"]
// If we have a signal, look at it. Otherwise, do nothing // If we have a signal, look at it. Otherwise, do nothing
if sigStr := r.Form.Get("signal"); sigStr != "" { if sigStr := r.Form.Get("signal"); sigStr != "" {
// Check if we passed the signal as a number: var err error
// The largest legal signal is 31, so let's parse on 5 bits if sig, err = signal.ParseSignal(sigStr); err != nil {
sigN, err := strconv.ParseUint(sigStr, 10, 5) return err
if err != nil {
// The signal is not a number, treat it as a string (either like
// "KILL" or like "SIGKILL")
syscallSig, ok := signal.SignalMap[strings.TrimPrefix(sigStr, "SIG")]
if !ok {
return fmt.Errorf("Invalid signal: %s", sigStr)
}
sig = uint64(syscallSig)
} else {
sig = sigN
}
if sig == 0 {
return fmt.Errorf("Invalid signal: %s", sigStr)
} }
} }
if err := s.daemon.ContainerKill(name, sig); err != nil { if err := s.daemon.ContainerKill(name, uint64(sig)); err != nil {
_, isStopped := err.(daemon.ErrContainerNotRunning) _, isStopped := err.(daemon.ErrContainerNotRunning)
// Return error that's not caused because the container is stopped. // Return error that's not caused because the container is stopped.
// Return error if the container is not running and the api is >= 1.20 // Return error if the container is not running and the api is >= 1.20

View File

@ -17,6 +17,7 @@ const (
Expose = "expose" Expose = "expose"
Volume = "volume" Volume = "volume"
User = "user" User = "user"
StopSignal = "stopsignal"
) )
// Commands is list of all Dockerfile commands // Commands is list of all Dockerfile commands
@ -35,4 +36,5 @@ var Commands = map[string]struct{}{
Expose: {}, Expose: {},
Volume: {}, Volume: {},
User: {}, User: {},
StopSignal: {},
} }

View File

@ -20,6 +20,7 @@ import (
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/nat" "github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/stringutils" "github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/pkg/system" "github.com/docker/docker/pkg/system"
"github.com/docker/docker/runconfig" "github.com/docker/docker/runconfig"
@ -534,3 +535,21 @@ func volume(b *builder, args []string, attributes map[string]bool, original stri
} }
return nil return nil
} }
// STOPSIGNAL signal
//
// Set the signal that will be used to kill the container.
func stopSignal(b *builder, args []string, attributes map[string]bool, original string) error {
if len(args) != 1 {
return fmt.Errorf("STOPSIGNAL requires exactly one argument")
}
sig := args[0]
_, err := signal.ParseSignal(sig)
if err != nil {
return err
}
b.Config.StopSignal = sig
return b.commit("", b.Config.Cmd, fmt.Sprintf("STOPSIGNAL %v", args))
}

View File

@ -45,14 +45,15 @@ import (
// Environment variable interpolation will happen on these statements only. // Environment variable interpolation will happen on these statements only.
var replaceEnvAllowed = map[string]struct{}{ var replaceEnvAllowed = map[string]struct{}{
command.Env: {}, command.Env: {},
command.Label: {}, command.Label: {},
command.Add: {}, command.Add: {},
command.Copy: {}, command.Copy: {},
command.Workdir: {}, command.Workdir: {},
command.Expose: {}, command.Expose: {},
command.Volume: {}, command.Volume: {},
command.User: {}, command.User: {},
command.StopSignal: {},
} }
var evaluateTable map[string]func(*builder, []string, map[string]bool, string) error var evaluateTable map[string]func(*builder, []string, map[string]bool, string) error
@ -73,6 +74,7 @@ func init() {
command.Expose: expose, command.Expose: expose,
command.Volume: volume, command.Volume: volume,
command.User: user, command.User: user,
command.StopSignal: stopSignal,
} }
} }

View File

@ -61,6 +61,7 @@ func init() {
command.Entrypoint: parseMaybeJSON, command.Entrypoint: parseMaybeJSON,
command.Expose: parseStringsWhitespaceDelimited, command.Expose: parseStringsWhitespaceDelimited,
command.Volume: parseMaybeJSONToList, command.Volume: parseMaybeJSONToList,
command.StopSignal: parseString,
} }
} }

View File

@ -1149,6 +1149,7 @@ _docker_run() {
--publish -p --publish -p
--restart --restart
--security-opt --security-opt
--stop-signal
--ulimit --ulimit
--user -u --user -u
--uts --uts

View File

@ -335,6 +335,7 @@ complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l restart -d 'Res
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l rm -d 'Automatically remove the container when it exits (incompatible with -d)' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l rm -d 'Automatically remove the container when it exits (incompatible with -d)'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l security-opt -d 'Security Options' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l security-opt -d 'Security Options'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l sig-proxy -d 'Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l sig-proxy -d 'Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied.'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -l stop-signal 'Signal to kill a container'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s t -l tty -d 'Allocate a pseudo-TTY' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s t -l tty -d 'Allocate a pseudo-TTY'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s u -l user -d 'Username or UID' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s u -l user -d 'Username or UID'
complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s v -l volume -d 'Bind mount a volume (e.g., from the host: -v /host:/container, from Docker: -v /container)' complete -c docker -A -f -n '__fish_seen_subcommand_from run' -s v -l volume -d 'Bind mount a volume (e.g., from the host: -v /host:/container, from Docker: -v /container)'

View File

@ -502,6 +502,7 @@ __docker_subcommand() {
"($help -d --detach)"{-d,--detach}"[Detached mode: leave the container running in the background]" \ "($help -d --detach)"{-d,--detach}"[Detached mode: leave the container running in the background]" \
"($help)--rm[Remove intermediate containers when it exits]" \ "($help)--rm[Remove intermediate containers when it exits]" \
"($help)--sig-proxy[Proxy all received signals to the process (non-TTY mode only)]" \ "($help)--sig-proxy[Proxy all received signals to the process (non-TTY mode only)]" \
"($help)--stop-signal[Signal to kill a container]" \
"($help -): :__docker_images" \ "($help -): :__docker_images" \
"($help -):command: _command_names -e" \ "($help -):command: _command_names -e" \
"($help -)*::arguments: _normal" && ret=0 "($help -)*::arguments: _normal" && ret=0

View File

@ -23,6 +23,7 @@
<item> WORKDIR </item> <item> WORKDIR </item>
<item> USER </item> <item> USER </item>
<item> LABEL </item> <item> LABEL </item>
<item> STOPSIGNAL </item>
</list> </list>
<contexts> <contexts>

View File

@ -25,7 +25,7 @@
</dict> </dict>
</dict> </dict>
<key>match</key> <key>match</key>
<string>^\s*(?:(ONBUILD)\s+)?(FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|VOLUME|USER|WORKDIR|COPY|LABEL)\s</string> <string>^\s*(?:(ONBUILD)\s+)?(FROM|MAINTAINER|RUN|EXPOSE|ENV|ADD|VOLUME|USER|WORKDIR|COPY|LABEL|STOPSIGNAL)\s</string>
</dict> </dict>
<dict> <dict>
<key>captures</key> <key>captures</key>

View File

@ -11,7 +11,7 @@ let b:current_syntax = "dockerfile"
syntax case ignore syntax case ignore
syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|CMD|ENTRYPOINT|ENV|EXPOSE|FROM|MAINTAINER|RUN|USER|LABEL|VOLUME|WORKDIR|COPY)\s/ syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|CMD|ENTRYPOINT|ENV|EXPOSE|FROM|MAINTAINER|RUN|USER|LABEL|VOLUME|WORKDIR|COPY|STOPSIGNAL)\s/
highlight link dockerfileKeyword Keyword highlight link dockerfileKeyword Keyword
syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/ syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/

View File

@ -27,6 +27,7 @@ import (
"github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/nat" "github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/promise" "github.com/docker/docker/pkg/promise"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/symlink" "github.com/docker/docker/pkg/symlink"
"github.com/docker/docker/runconfig" "github.com/docker/docker/runconfig"
"github.com/docker/docker/volume" "github.com/docker/docker/volume"
@ -495,10 +496,10 @@ func (container *Container) Kill() error {
return nil return nil
} }
// Stop halts a container by sending SIGTERM, waiting for the given // Stop halts a container by sending a stop signal, waiting for the given
// duration in seconds, and then calling SIGKILL and waiting for the // duration in seconds, and then calling SIGKILL and waiting for the
// process to exit. If a negative duration is given, Stop will wait // process to exit. If a negative duration is given, Stop will wait
// for SIGTERM forever. If the container is not running Stop returns // for the initial signal forever. If the container is not running Stop returns
// immediately. // immediately.
func (container *Container) Stop(seconds int) error { func (container *Container) Stop(seconds int) error {
if !container.IsRunning() { if !container.IsRunning() {
@ -506,9 +507,9 @@ func (container *Container) Stop(seconds int) error {
} }
// 1. Send a SIGTERM // 1. Send a SIGTERM
if err := container.killPossiblyDeadProcess(int(syscall.SIGTERM)); err != nil { if err := container.killPossiblyDeadProcess(container.stopSignal()); err != nil {
logrus.Infof("Failed to send SIGTERM to the process, force killing") logrus.Infof("Failed to send SIGTERM to the process, force killing")
if err := container.killPossiblyDeadProcess(int(syscall.SIGKILL)); err != nil { if err := container.killPossiblyDeadProcess(9); err != nil {
return err return err
} }
} }
@ -1140,3 +1141,15 @@ func (container *Container) copyImagePathContent(v volume.Volume, destination st
return v.Unmount() return v.Unmount()
} }
func (container *Container) stopSignal() int {
var stopSignal syscall.Signal
if container.Config.StopSignal != "" {
stopSignal, _ = signal.ParseSignal(container.Config.StopSignal)
}
if int(stopSignal) == 0 {
stopSignal, _ = signal.ParseSignal(signal.DefaultStopSignal)
}
return int(stopSignal)
}

View File

@ -1,6 +1,11 @@
package daemon package daemon
import "testing" import (
"testing"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/runconfig"
)
func TestGetFullName(t *testing.T) { func TestGetFullName(t *testing.T) {
name, err := GetFullContainerName("testing") name, err := GetFullContainerName("testing")
@ -31,3 +36,31 @@ func TestValidContainerNames(t *testing.T) {
} }
} }
} }
func TestContainerStopSignal(t *testing.T) {
c := &Container{
CommonContainer: CommonContainer{
Config: &runconfig.Config{},
},
}
def, err := signal.ParseSignal(signal.DefaultStopSignal)
if err != nil {
t.Fatal(err)
}
s := c.stopSignal()
if s != int(def) {
t.Fatalf("Expected %v, got %v", def, s)
}
c = &Container{
CommonContainer: CommonContainer{
Config: &runconfig.Config{StopSignal: "SIGKILL"},
},
}
s = c.stopSignal()
if s != 9 {
t.Fatalf("Expected 9, got %v", s)
}
}

View File

@ -1076,6 +1076,13 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *runconfig.HostConfig,
return nil, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path.", config.WorkingDir) return nil, fmt.Errorf("The working directory '%s' is invalid. It needs to be an absolute path.", config.WorkingDir)
} }
} }
if len(config.StopSignal) > 0 {
_, err := signal.ParseSignal(config.StopSignal)
if err != nil {
return nil, err
}
}
} }
if hostConfig == nil { if hostConfig == nil {

View File

@ -82,6 +82,7 @@ This section lists each version from latest to oldest. Each listing includes a
* `DELETE /volumes/(name)`remove a volume with the specified name. * `DELETE /volumes/(name)`remove a volume with the specified name.
* `VolumeDriver` has been moved from config to hostConfig to make the configuration portable. * `VolumeDriver` has been moved from config to hostConfig to make the configuration portable.
* `GET /images/(name)/json` now returns information about tags of the image. * `GET /images/(name)/json` now returns information about tags of the image.
* The `config` option now accepts the field `StopSignal`, which specifies the signal to use to kill a container.
### v1.20 API changes ### v1.20 API changes

View File

@ -166,6 +166,7 @@ Create a container
"ExposedPorts": { "ExposedPorts": {
"22/tcp": {} "22/tcp": {}
}, },
"StopSignal": "SIGTERM",
"HostConfig": { "HostConfig": {
"Binds": ["/tmp:/tmp"], "Binds": ["/tmp:/tmp"],
"Links": ["redis3:redis"], "Links": ["redis3:redis"],
@ -250,6 +251,7 @@ Json Parameters:
container container
- **ExposedPorts** - An object mapping ports to an empty object in the form of: - **ExposedPorts** - An object mapping ports to an empty object in the form of:
`"ExposedPorts": { "<port>/<tcp|udp>: {}" }` `"ExposedPorts": { "<port>/<tcp|udp>: {}" }`
- **StopSignal** - Signal to stop a container as a string or unsigned integer. `SIGTERM` by default.
- **HostConfig** - **HostConfig**
- **Binds** A list of volume bindings for this container. Each volume binding is a string in one of these forms: - **Binds** A list of volume bindings for this container. Each volume binding is a string in one of these forms:
+ `container_path` to create a new volume for the container + `container_path` to create a new volume for the container
@ -367,7 +369,8 @@ Return low-level information on the container `id`
"Tty": false, "Tty": false,
"User": "", "User": "",
"Volumes": null, "Volumes": null,
"WorkingDir": "" "WorkingDir": "",
"StopSignal": "SIGTERM"
}, },
"Created": "2015-01-06T15:47:31.485331387Z", "Created": "2015-01-06T15:47:31.485331387Z",
"Driver": "devicemapper", "Driver": "devicemapper",

View File

@ -158,6 +158,7 @@ the `Dockerfile`:
* `USER` * `USER`
* `WORKDIR` * `WORKDIR`
* `VOLUME` * `VOLUME`
* `STOPSIGNAL`
as well as: as well as:
@ -1012,6 +1013,14 @@ For example you might add something like this:
> **Warning**: The `ONBUILD` instruction may not trigger `FROM` or `MAINTAINER` instructions. > **Warning**: The `ONBUILD` instruction may not trigger `FROM` or `MAINTAINER` instructions.
## STOPSIGNAL
STOPSIGNAL signal
The `STOPSIGNAL` instruction sets the system call signal that will be sent to the container to exit.
This signal can be a valid unsigned number that matches a position in the kernel's syscall table, for instance 9,
or a signal name in the format SIGNAME, for instance SIGKILL.
## Dockerfile examples ## Dockerfile examples
# Nginx # Nginx

View File

@ -61,6 +61,7 @@ Creates a new container.
--read-only=false Mount the container's root filesystem as read only --read-only=false Mount the container's root filesystem as read only
--restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped) --restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped)
--security-opt=[] Security options --security-opt=[] Security options
--stop-signal="SIGTERM" Signal to stop a container
-t, --tty=false Allocate a pseudo-TTY -t, --tty=false Allocate a pseudo-TTY
--disable-content-trust=true Skip image verification --disable-content-trust=true Skip image verification
-u, --user="" Username or UID -u, --user="" Username or UID

View File

@ -62,6 +62,7 @@ weight=1
--restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped) --restart="no" Restart policy (no, on-failure[:max-retry], always, unless-stopped)
--rm=false Automatically remove the container when it exits --rm=false Automatically remove the container when it exits
--security-opt=[] Security Options --security-opt=[] Security Options
--stop-signal="SIGTERM" Signal to stop a container
--sig-proxy=true Proxy received signals to the process --sig-proxy=true Proxy received signals to the process
-t, --tty=false Allocate a pseudo-TTY -t, --tty=false Allocate a pseudo-TTY
-u, --user="" Username or UID (format: <name|uid>[:<group|gid>]) -u, --user="" Username or UID (format: <name|uid>[:<group|gid>])
@ -531,3 +532,9 @@ containers with `daemon` user:
The 4th container fails and reports "[8] System error: resource temporarily unavailable" error. The 4th container fails and reports "[8] System error: resource temporarily unavailable" error.
This fails because the caller set `nproc=3` resulting in the first three containers using up This fails because the caller set `nproc=3` resulting in the first three containers using up
the three processes quota set for the `daemon` user. the three processes quota set for the `daemon` user.
### Stopping a container with a specific signal
The `--stop-signal` flag sets the system call signal that will be sent to the container to exit.
This signal can be a valid unsigned number that matches a position in the kernel's syscall table, for instance 9,
or a signal name in the format SIGNAME, for instance SIGKILL.

View File

@ -5660,3 +5660,18 @@ func (s *DockerSuite) TestBuildNullStringInAddCopyVolume(c *check.C) {
_, err = buildImageFromContext(name, ctx, true) _, err = buildImageFromContext(name, ctx, true)
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
} }
func (s *DockerSuite) TestBuildStopSignal(c *check.C) {
name := "test_build_stop_signal"
_, err := buildImage(name,
`FROM busybox
STOPSIGNAL SIGKILL`,
true)
c.Assert(err, check.IsNil)
res, err := inspectFieldJSON(name, "Config.StopSignal")
c.Assert(err, check.IsNil)
if res != `"SIGKILL"` {
c.Fatalf("Signal %s, expected SIGKILL", res)
}
}

View File

@ -458,3 +458,15 @@ func (s *DockerTrustSuite) TestTrustedCreateFromBadTrustServer(c *check.C) {
c.Fatalf("Missing expected output on trusted push:\n%s", out) c.Fatalf("Missing expected output on trusted push:\n%s", out)
} }
} }
func (s *DockerSuite) TestCreateStopSignal(c *check.C) {
name := "test_create_stop_signal"
dockerCmd(c, "create", "--name", name, "--stop-signal", "9", "busybox")
res, err := inspectFieldJSON(name, "Config.StopSignal")
c.Assert(err, check.IsNil)
if res != `"9"` {
c.Fatalf("Expected 9, got %s", res)
}
}

View File

@ -315,3 +315,19 @@ func (s *DockerSuite) TestRunWithSwappinessInvalid(c *check.C) {
c.Fatalf("failed. test was able to set invalid value, output: %q", out) c.Fatalf("failed. test was able to set invalid value, output: %q", out)
} }
} }
func (s *DockerSuite) TestStopContainerSignal(c *check.C) {
out, _ := dockerCmd(c, "run", "--stop-signal", "SIGUSR1", "-d", "busybox", "/bin/sh", "-c", `trap 'echo "exit trapped"; exit 0' USR1; while true; do sleep 1; done`)
containerID := strings.TrimSpace(out)
if err := waitRun(containerID); err != nil {
c.Fatal(err)
}
dockerCmd(c, "stop", containerID)
out, _ = dockerCmd(c, "logs", containerID)
if !strings.Contains(out, "exit trapped") {
c.Fatalf("Expected `exit trapped` in the log, got %v", out)
}
}

View File

@ -51,6 +51,7 @@ docker-create - Create a new container
[**--read-only**[=*false*]] [**--read-only**[=*false*]]
[**--restart**[=*RESTART*]] [**--restart**[=*RESTART*]]
[**--security-opt**[=*[]*]] [**--security-opt**[=*[]*]]
[**--stop-signal**[=*SIGNAL*]]
[**-t**|**--tty**[=*false*]] [**-t**|**--tty**[=*false*]]
[**-u**|**--user**[=*USER*]] [**-u**|**--user**[=*USER*]]
[**--ulimit**[=*[]*]] [**--ulimit**[=*[]*]]
@ -239,6 +240,9 @@ This value should always larger than **-m**, so you should always use this with
**--security-opt**=[] **--security-opt**=[]
Security Options Security Options
**--stop-signal**=SIGTERM
Signal to stop a container. Default is SIGTERM.
**-t**, **--tty**=*true*|*false* **-t**, **--tty**=*true*|*false*
Allocate a pseudo-TTY. The default is *false*. Allocate a pseudo-TTY. The default is *false*.

View File

@ -180,7 +180,8 @@ To get information on a container use its ID or instance name:
"Memory": 0, "Memory": 0,
"MemorySwap": 0, "MemorySwap": 0,
"CpuShares": 0, "CpuShares": 0,
"Cpuset": "" "Cpuset": "",
"StopSignal": "SIGTERM"
} }
} }
] ]

View File

@ -53,6 +53,7 @@ docker-run - Run a command in a new container
[**--restart**[=*RESTART*]] [**--restart**[=*RESTART*]]
[**--rm**[=*false*]] [**--rm**[=*false*]]
[**--security-opt**[=*[]*]] [**--security-opt**[=*[]*]]
[**--stop-signal**[=*SIGNAL*]]
[**--sig-proxy**[=*true*]] [**--sig-proxy**[=*true*]]
[**-t**|**--tty**[=*false*]] [**-t**|**--tty**[=*false*]]
[**-u**|**--user**[=*USER*]] [**-u**|**--user**[=*USER*]]
@ -371,7 +372,7 @@ its root filesystem mounted as read only prohibiting any writes.
**--restart**="no" **--restart**="no"
Restart policy to apply when a container exits (no, on-failure[:max-retry], always, unless-stopped). Restart policy to apply when a container exits (no, on-failure[:max-retry], always, unless-stopped).
**--rm**=*true*|*false* **--rm**=*true*|*false*
Automatically remove the container when it exits (incompatible with -d). The default is *false*. Automatically remove the container when it exits (incompatible with -d). The default is *false*.
@ -384,6 +385,9 @@ its root filesystem mounted as read only prohibiting any writes.
"label:level:LEVEL" : Set the label level for the container "label:level:LEVEL" : Set the label level for the container
"label:disable" : Turn off label confinement for the container "label:disable" : Turn off label confinement for the container
**--stop-signal**=SIGTERM
Signal to stop a container. Default is SIGTERM.
**--sig-proxy**=*true*|*false* **--sig-proxy**=*true*|*false*
Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied. The default is *true*. Proxy received signals to the process (non-TTY mode only). SIGCHLD, SIGSTOP, and SIGKILL are not proxied. The default is *true*.

View File

@ -19,7 +19,7 @@ Stop a running container (Send SIGTERM, and then SIGKILL after
Print usage statement Print usage statement
**-t**, **--time**=10 **-t**, **--time**=10
Number of seconds to wait for the container to stop before killing it. Default is 10 seconds. Number of seconds to wait for the container to stop before killing it. Default is 10 seconds.
#See also #See also
**docker-start(1)** to restart a stopped container. **docker-start(1)** to restart a stopped container.

View File

@ -3,8 +3,12 @@
package signal package signal
import ( import (
"fmt"
"os" "os"
"os/signal" "os/signal"
"strconv"
"strings"
"syscall"
) )
// CatchAll catches all signals and relays them to the specified channel. // CatchAll catches all signals and relays them to the specified channel.
@ -21,3 +25,20 @@ func StopCatch(sigc chan os.Signal) {
signal.Stop(sigc) signal.Stop(sigc)
close(sigc) close(sigc)
} }
// ParseSignal translates a string to a valid syscall signal.
// It returns an error if the signal map doesn't include the given signal.
func ParseSignal(rawSignal string) (syscall.Signal, error) {
s, err := strconv.Atoi(rawSignal)
if err == nil {
if s == 0 {
return -1, fmt.Errorf("Invalid signal: %s", rawSignal)
}
return syscall.Signal(s), nil
}
signal, ok := SignalMap[strings.TrimPrefix(strings.ToUpper(rawSignal), "SIG")]
if !ok {
return -1, fmt.Errorf("Invalid signal: %s", rawSignal)
}
return signal, nil
}

View File

@ -9,8 +9,11 @@ import (
// Signals used in api/client (no windows equivalent, use // Signals used in api/client (no windows equivalent, use
// invalid signals so they don't get handled) // invalid signals so they don't get handled)
// SIGCHLD is a signal sent to a process when a child process terminates, is interrupted, or resumes after being interrupted. const (
const SIGCHLD = syscall.SIGCHLD // SIGCHLD is a signal sent to a process when a child process terminates, is interrupted, or resumes after being interrupted.
SIGCHLD = syscall.SIGCHLD
// SIGWINCH is a signal sent to a process when its controlling terminal changes its size // SIGWINCH is a signal sent to a process when its controlling terminal changes its size
const SIGWINCH = syscall.SIGWINCH SIGWINCH = syscall.SIGWINCH
// DefaultStopSignal is the syscall signal used to stop a container in unix systems.
DefaultStopSignal = "SIGTERM"
)

View File

@ -11,4 +11,6 @@ import (
const ( const (
SIGCHLD = syscall.Signal(0xff) SIGCHLD = syscall.Signal(0xff)
SIGWINCH = syscall.Signal(0xff) SIGWINCH = syscall.Signal(0xff)
// DefaultStopSignal is the syscall signal used to stop a container in windows systems.
DefaultStopSignal = "15"
) )

View File

@ -34,6 +34,7 @@ type Config struct {
MacAddress string // Mac Address of the container MacAddress string // Mac Address of the container
OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile OnBuild []string // ONBUILD metadata that were defined on the image Dockerfile
Labels map[string]string // List of labels set to this container Labels map[string]string // List of labels set to this container
StopSignal string // Signal to stop a container
} }
// DecodeContainerConfig decodes a json encoded config into a ContainerConfigWrapper // DecodeContainerConfig decodes a json encoded config into a ContainerConfigWrapper

View File

@ -9,6 +9,7 @@ import (
flag "github.com/docker/docker/pkg/mflag" flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/nat" "github.com/docker/docker/pkg/nat"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/signal"
"github.com/docker/docker/pkg/stringutils" "github.com/docker/docker/pkg/stringutils"
"github.com/docker/docker/pkg/units" "github.com/docker/docker/pkg/units"
) )
@ -93,6 +94,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
flLoggingDriver = cmd.String([]string{"-log-driver"}, "", "Logging driver for container") flLoggingDriver = cmd.String([]string{"-log-driver"}, "", "Logging driver for container")
flCgroupParent = cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container") flCgroupParent = cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup for the container")
flVolumeDriver = cmd.String([]string{"-volume-driver"}, "", "Optional volume driver for the container") flVolumeDriver = cmd.String([]string{"-volume-driver"}, "", "Optional volume driver for the container")
flStopSignal = cmd.String([]string{"-stop-signal"}, signal.DefaultStopSignal, fmt.Sprintf("Signal to stop a container, %v by default", signal.DefaultStopSignal))
) )
cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR") cmd.Var(&flAttach, []string{"a", "-attach"}, "Attach to STDIN, STDOUT or STDERR")
@ -322,6 +324,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
Entrypoint: entrypoint, Entrypoint: entrypoint,
WorkingDir: *flWorkingDir, WorkingDir: *flWorkingDir,
Labels: convertKVStringsToMap(labels), Labels: convertKVStringsToMap(labels),
StopSignal: *flStopSignal,
} }
hostConfig := &HostConfig{ hostConfig := &HostConfig{