Pārlūkot izejas kodu

Merge pull request #15307 from calavera/stop_signal

Signal to stop a container.
David Calavera 9 gadi atpakaļ
vecāks
revīzija
db54c79d7c

+ 6 - 19
api/server/container.go

@@ -6,6 +6,7 @@ import (
 	"net/http"
 	"strconv"
 	"strings"
+	"syscall"
 	"time"
 
 	"golang.org/x/net/websocket"
@@ -220,32 +221,18 @@ func (s *Server) postContainersKill(ctx context.Context, w http.ResponseWriter,
 		return err
 	}
 
-	var sig uint64
+	var sig syscall.Signal
 	name := vars["name"]
 
 	// If we have a signal, look at it. Otherwise, do nothing
 	if sigStr := r.Form.Get("signal"); sigStr != "" {
-		// Check if we passed the signal as a number:
-		// The largest legal signal is 31, so let's parse on 5 bits
-		sigN, err := strconv.ParseUint(sigStr, 10, 5)
-		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)
+		var err error
+		if sig, err = signal.ParseSignal(sigStr); err != nil {
+			return err
 		}
 	}
 
-	if err := s.daemon.ContainerKill(name, sig); err != nil {
+	if err := s.daemon.ContainerKill(name, uint64(sig)); err != nil {
 		_, isStopped := err.(daemon.ErrContainerNotRunning)
 		// 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

+ 2 - 0
builder/command/command.go

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

+ 19 - 0
builder/dispatchers.go

@@ -20,6 +20,7 @@ import (
 	"github.com/Sirupsen/logrus"
 	flag "github.com/docker/docker/pkg/mflag"
 	"github.com/docker/docker/pkg/nat"
+	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/pkg/stringutils"
 	"github.com/docker/docker/pkg/system"
 	"github.com/docker/docker/runconfig"
@@ -534,3 +535,21 @@ func volume(b *builder, args []string, attributes map[string]bool, original stri
 	}
 	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))
+}

+ 10 - 8
builder/evaluator.go

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

+ 1 - 0
builder/parser/parser.go

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

+ 1 - 0
contrib/completion/bash/docker

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

+ 1 - 0
contrib/completion/fish/docker.fish

@@ -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 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 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 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)'

+ 1 - 0
contrib/completion/zsh/_docker

@@ -502,6 +502,7 @@ __docker_subcommand() {
                 "($help -d --detach)"{-d,--detach}"[Detached mode: leave the container running in the background]" \
                 "($help)--rm[Remove intermediate containers when it exits]" \
                 "($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 -):command: _command_names -e" \
                 "($help -)*::arguments: _normal" && ret=0

+ 1 - 0
contrib/syntax/kate/Dockerfile.xml

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

+ 1 - 1
contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage

@@ -25,7 +25,7 @@
 				</dict>
 			</dict>
 			<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>
 			<key>captures</key>

+ 1 - 1
contrib/syntax/vim/syntax/dockerfile.vim

@@ -11,7 +11,7 @@ let b:current_syntax = "dockerfile"
 
 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
 
 syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/

+ 17 - 4
daemon/container.go

@@ -27,6 +27,7 @@ import (
 	"github.com/docker/docker/pkg/mount"
 	"github.com/docker/docker/pkg/nat"
 	"github.com/docker/docker/pkg/promise"
+	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/pkg/symlink"
 	"github.com/docker/docker/runconfig"
 	"github.com/docker/docker/volume"
@@ -495,10 +496,10 @@ func (container *Container) Kill() error {
 	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
 // 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.
 func (container *Container) Stop(seconds int) error {
 	if !container.IsRunning() {
@@ -506,9 +507,9 @@ func (container *Container) Stop(seconds int) error {
 	}
 
 	// 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")
-		if err := container.killPossiblyDeadProcess(int(syscall.SIGKILL)); err != nil {
+		if err := container.killPossiblyDeadProcess(9); err != nil {
 			return err
 		}
 	}
@@ -1140,3 +1141,15 @@ func (container *Container) copyImagePathContent(v volume.Volume, destination st
 
 	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)
+}

+ 34 - 1
daemon/container_unit_test.go

@@ -1,6 +1,11 @@
 package daemon
 
-import "testing"
+import (
+	"testing"
+
+	"github.com/docker/docker/pkg/signal"
+	"github.com/docker/docker/runconfig"
+)
 
 func TestGetFullName(t *testing.T) {
 	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)
+	}
+}

+ 7 - 0
daemon/daemon.go

@@ -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)
 			}
 		}
+
+		if len(config.StopSignal) > 0 {
+			_, err := signal.ParseSignal(config.StopSignal)
+			if err != nil {
+				return nil, err
+			}
+		}
 	}
 
 	if hostConfig == nil {

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

@@ -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.
 * `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.
+* The `config` option now accepts the field `StopSignal`, which specifies the signal to use to kill a container.
 
 
 ### v1.20 API changes

+ 4 - 1
docs/reference/api/docker_remote_api_v1.21.md

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

+ 9 - 0
docs/reference/builder.md

@@ -158,6 +158,7 @@ the `Dockerfile`:
 * `USER`
 * `WORKDIR`
 * `VOLUME`
+* `STOPSIGNAL`
 
 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.
 
+## 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
 
     # Nginx

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

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

+ 7 - 0
docs/reference/commandline/run.md

@@ -62,6 +62,7 @@ weight=1
       --restart="no"                Restart policy (no, on-failure[:max-retry], always, unless-stopped)
       --rm=false                    Automatically remove the container when it exits
       --security-opt=[]             Security Options
+      --stop-signal="SIGTERM"       Signal to stop a container
       --sig-proxy=true              Proxy received signals to the process
       -t, --tty=false               Allocate a pseudo-TTY
       -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. 
 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.
+
+### 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.

+ 15 - 0
integration-cli/docker_cli_build_test.go

@@ -5660,3 +5660,18 @@ func (s *DockerSuite) TestBuildNullStringInAddCopyVolume(c *check.C) {
 	_, err = buildImageFromContext(name, ctx, true)
 	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)
+	}
+}

+ 12 - 0
integration-cli/docker_cli_create_test.go

@@ -458,3 +458,15 @@ func (s *DockerTrustSuite) TestTrustedCreateFromBadTrustServer(c *check.C) {
 		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)
+	}
+}

+ 16 - 0
integration-cli/docker_cli_run_unix_test.go

@@ -315,3 +315,19 @@ func (s *DockerSuite) TestRunWithSwappinessInvalid(c *check.C) {
 		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)
+	}
+}

+ 4 - 0
man/docker-create.1.md

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

+ 2 - 1
man/docker-inspect.1.md

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

+ 5 - 1
man/docker-run.1.md

@@ -53,6 +53,7 @@ docker-run - Run a command in a new container
 [**--restart**[=*RESTART*]]
 [**--rm**[=*false*]]
 [**--security-opt**[=*[]*]]
+[**--stop-signal**[=*SIGNAL*]]
 [**--sig-proxy**[=*true*]]
 [**-t**|**--tty**[=*false*]]
 [**-u**|**--user**[=*USER*]]
@@ -371,7 +372,7 @@ its root filesystem mounted as read only prohibiting any writes.
 
 **--restart**="no"
    Restart policy to apply when a container exits (no, on-failure[:max-retry], always, unless-stopped).
-      
+
 **--rm**=*true*|*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:disable"     : Turn off label confinement for the container
 
+**--stop-signal**=SIGTERM
+  Signal to stop a container. Default is SIGTERM.
+
 **--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*.
 

+ 1 - 1
man/docker-stop.1.md

@@ -19,7 +19,7 @@ Stop a running container (Send SIGTERM, and then SIGKILL after
   Print usage statement
 
 **-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
 **docker-start(1)** to restart a stopped container.

+ 21 - 0
pkg/signal/signal.go

@@ -3,8 +3,12 @@
 package signal
 
 import (
+	"fmt"
 	"os"
 	"os/signal"
+	"strconv"
+	"strings"
+	"syscall"
 )
 
 // CatchAll catches all signals and relays them to the specified channel.
@@ -21,3 +25,20 @@ func StopCatch(sigc chan os.Signal) {
 	signal.Stop(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
+}

+ 8 - 5
pkg/signal/signal_unix.go

@@ -9,8 +9,11 @@ import (
 // Signals used in api/client (no windows equivalent, use
 // 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 SIGCHLD = syscall.SIGCHLD
-
-// SIGWINCH is a signal sent to a process when its controlling terminal changes its size
-const SIGWINCH = syscall.SIGWINCH
+const (
+	// 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 = syscall.SIGWINCH
+	// DefaultStopSignal is the syscall signal used to stop a container in unix systems.
+	DefaultStopSignal = "SIGTERM"
+)

+ 2 - 0
pkg/signal/signal_windows.go

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

+ 1 - 0
runconfig/config.go

@@ -34,6 +34,7 @@ type Config struct {
 	MacAddress      string                // Mac Address of the container
 	OnBuild         []string              // ONBUILD metadata that were defined on the image Dockerfile
 	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

+ 3 - 0
runconfig/parse.go

@@ -9,6 +9,7 @@ import (
 	flag "github.com/docker/docker/pkg/mflag"
 	"github.com/docker/docker/pkg/nat"
 	"github.com/docker/docker/pkg/parsers"
+	"github.com/docker/docker/pkg/signal"
 	"github.com/docker/docker/pkg/stringutils"
 	"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")
 		flCgroupParent    = cmd.String([]string{"-cgroup-parent"}, "", "Optional parent cgroup 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")
@@ -322,6 +324,7 @@ func Parse(cmd *flag.FlagSet, args []string) (*Config, *HostConfig, *flag.FlagSe
 		Entrypoint:      entrypoint,
 		WorkingDir:      *flWorkingDir,
 		Labels:          convertKVStringsToMap(labels),
+		StopSignal:      *flStopSignal,
 	}
 
 	hostConfig := &HostConfig{