Merge pull request #4745 from unclejack/prepare_for_bump_v0.9.1

Prepare for bump v0.9.1
This commit is contained in:
unclejack
2014-03-19 20:00:55 +02:00
38 changed files with 652 additions and 305 deletions
+45 -14
View File
@@ -13,6 +13,7 @@ import (
"github.com/dotcloud/docker/engine"
"github.com/dotcloud/docker/nat"
flag "github.com/dotcloud/docker/pkg/mflag"
"github.com/dotcloud/docker/pkg/signal"
"github.com/dotcloud/docker/pkg/term"
"github.com/dotcloud/docker/registry"
"github.com/dotcloud/docker/runconfig"
@@ -24,11 +25,11 @@ import (
"net/http/httputil"
"net/url"
"os"
"os/signal"
gosignal "os/signal"
"path"
"reflect"
"regexp"
"runtime"
goruntime "runtime"
"strconv"
"strings"
"syscall"
@@ -367,7 +368,7 @@ func (cli *DockerCli) CmdVersion(args ...string) error {
if dockerversion.VERSION != "" {
fmt.Fprintf(cli.out, "Client version: %s\n", dockerversion.VERSION)
}
fmt.Fprintf(cli.out, "Go version (client): %s\n", runtime.Version())
fmt.Fprintf(cli.out, "Go version (client): %s\n", goruntime.Version())
if dockerversion.GITCOMMIT != "" {
fmt.Fprintf(cli.out, "Git commit (client): %s\n", dockerversion.GITCOMMIT)
}
@@ -432,7 +433,7 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
fmt.Fprintf(cli.out, "Containers: %d\n", remoteInfo.GetInt("Containers"))
fmt.Fprintf(cli.out, "Images: %d\n", remoteInfo.GetInt("Images"))
fmt.Fprintf(cli.out, "Driver: %s\n", remoteInfo.Get("Driver"))
fmt.Fprintf(cli.out, "Storage Driver: %s\n", remoteInfo.Get("Driver"))
var driverStatus [][2]string
if err := remoteInfo.GetJson("DriverStatus", &driverStatus); err != nil {
return err
@@ -440,14 +441,15 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
for _, pair := range driverStatus {
fmt.Fprintf(cli.out, " %s: %s\n", pair[0], pair[1])
}
fmt.Fprintf(cli.out, "Execution Driver: %s\n", remoteInfo.Get("ExecutionDriver"))
fmt.Fprintf(cli.out, "Kernel Version: %s\n", remoteInfo.Get("KernelVersion"))
if remoteInfo.GetBool("Debug") || os.Getenv("DEBUG") != "" {
fmt.Fprintf(cli.out, "Debug mode (server): %v\n", remoteInfo.GetBool("Debug"))
fmt.Fprintf(cli.out, "Debug mode (client): %v\n", os.Getenv("DEBUG") != "")
fmt.Fprintf(cli.out, "Fds: %d\n", remoteInfo.GetInt("NFd"))
fmt.Fprintf(cli.out, "Goroutines: %d\n", remoteInfo.GetInt("NGoroutines"))
fmt.Fprintf(cli.out, "Execution Driver: %s\n", remoteInfo.Get("ExecutionDriver"))
fmt.Fprintf(cli.out, "EventsListeners: %d\n", remoteInfo.GetInt("NEventsListener"))
fmt.Fprintf(cli.out, "Kernel Version: %s\n", remoteInfo.Get("KernelVersion"))
if initSha1 := remoteInfo.Get("InitSha1"); initSha1 != "" {
fmt.Fprintf(cli.out, "Init SHA1: %s\n", initSha1)
@@ -533,13 +535,23 @@ func (cli *DockerCli) CmdRestart(args ...string) error {
func (cli *DockerCli) forwardAllSignals(cid string) chan os.Signal {
sigc := make(chan os.Signal, 1)
utils.CatchAll(sigc)
signal.CatchAll(sigc)
go func() {
for s := range sigc {
if s == syscall.SIGCHLD {
continue
}
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%d", cid, s), nil, false)); err != nil {
var sig string
for sigStr, sigN := range signal.SignalMap {
if sigN == s {
sig = sigStr
break
}
}
if sig == "" {
utils.Errorf("Unsupported signal: %d. Discarding.", s)
}
if _, _, err := readBody(cli.call("POST", fmt.Sprintf("/containers/%s/kill?signal=%s", cid, sig), nil, false)); err != nil {
utils.Debugf("Error sending signal: %s", err)
}
}
@@ -581,7 +593,7 @@ func (cli *DockerCli) CmdStart(args ...string) error {
if !container.Config.Tty {
sigc := cli.forwardAllSignals(cmd.Arg(0))
defer utils.StopCatch(sigc)
defer signal.StopCatch(sigc)
}
var in io.ReadCloser
@@ -1614,7 +1626,7 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
if *proxy && !container.Config.Tty {
sigc := cli.forwardAllSignals(cmd.Arg(0))
defer utils.StopCatch(sigc)
defer signal.StopCatch(sigc)
}
if err := cli.hijack("POST", "/containers/"+cmd.Arg(0)+"/attach?"+v.Encode(), container.Config.Tty, in, cli.out, cli.err, nil); err != nil {
@@ -1753,7 +1765,21 @@ func (cli *DockerCli) CmdRun(args ...string) error {
if containerIDFile, err = os.Create(hostConfig.ContainerIDFile); err != nil {
return fmt.Errorf("Failed to create the container ID file: %s", err)
}
defer containerIDFile.Close()
defer func() {
containerIDFile.Close()
var (
cidFileInfo os.FileInfo
err error
)
if cidFileInfo, err = os.Stat(hostConfig.ContainerIDFile); err != nil {
return
}
if cidFileInfo.Size() == 0 {
if err := os.Remove(hostConfig.ContainerIDFile); err != nil {
fmt.Printf("failed to remove CID file '%s': %s \n", hostConfig.ContainerIDFile, err)
}
}
}()
}
containerValues := url.Values{}
@@ -1818,7 +1844,7 @@ func (cli *DockerCli) CmdRun(args ...string) error {
if sigProxy {
sigc := cli.forwardAllSignals(runResult.Get("Id"))
defer utils.StopCatch(sigc)
defer signal.StopCatch(sigc)
}
var (
@@ -2239,7 +2265,12 @@ func (cli *DockerCli) hijack(method, path string, setRawTerminal bool, in io.Rea
if setRawTerminal && cli.isTerminal {
term.RestoreTerminal(cli.terminalFd, oldState)
}
in.Close()
// For some reason this Close call blocks on darwin..
// As the client exists right after, simply discard the close
// until we find a better solution.
if goruntime.GOOS != "darwin" {
in.Close()
}
}
}()
@@ -2320,7 +2351,7 @@ func (cli *DockerCli) monitorTtySize(id string) error {
cli.resizeTty(id)
sigchan := make(chan os.Signal, 1)
signal.Notify(sigchan, syscall.SIGWINCH)
gosignal.Notify(sigchan, syscall.SIGWINCH)
go func() {
for _ = range sigchan {
cli.resizeTty(id)
+3 -4
View File
@@ -26,7 +26,6 @@ import (
"strconv"
"strings"
"syscall"
"time"
)
var (
@@ -883,7 +882,7 @@ func postContainersCopy(eng *engine.Engine, version version.Version, w http.Resp
var copyData engine.Env
if contentType := r.Header.Get("Content-Type"); contentType == "application/json" {
if contentType := r.Header.Get("Content-Type"); MatchesContentType(contentType, "application/json") {
if err := copyData.Decode(r.Body); err != nil {
return err
}
@@ -1130,7 +1129,7 @@ func changeGroup(addr string, nameOrGid string) error {
// ListenAndServe sets up the required http.Server and gets it listening for
// each addr passed in and does protocol specific checking.
func ListenAndServe(proto, addr string, eng *engine.Engine, logging, enableCors bool, dockerVersion string, socketGroup string) error {
func ListenAndServe(proto, addr string, eng *engine.Engine, logging, enableCors bool, dockerVersion, socketGroup string) error {
r, err := createRouter(eng, logging, enableCors, dockerVersion)
if err != nil {
@@ -1147,7 +1146,7 @@ func ListenAndServe(proto, addr string, eng *engine.Engine, logging, enableCors
}
}
l, err := listenbuffer.NewListenBuffer(proto, addr, activationLock, 15*time.Minute)
l, err := listenbuffer.NewListenBuffer(proto, addr, activationLock)
if err != nil {
return err
}
+7 -3
View File
@@ -363,14 +363,18 @@ func populateCommand(c *Container) {
driverConfig []string
)
en = &execdriver.Network{
Mtu: c.runtime.config.Mtu,
Interface: nil,
}
if !c.Config.NetworkDisabled {
network := c.NetworkSettings
en = &execdriver.Network{
en.Interface = &execdriver.NetworkInterface{
Gateway: network.Gateway,
Bridge: network.Bridge,
IPAddress: network.IPAddress,
IPPrefixLen: network.IPPrefixLen,
Mtu: c.runtime.config.Mtu,
}
}
@@ -784,7 +788,7 @@ func (container *Container) monitor(callback execdriver.StartCallback) error {
utils.Errorf("Error running container: %s", err)
}
if container.runtime.srv.IsRunning() {
if container.runtime != nil && container.runtime.srv != nil && container.runtime.srv.IsRunning() {
container.State.SetStopped(exitCode)
// FIXME: there is a race condition here which causes this to fail during the unit tests.
+28 -13
View File
@@ -21,6 +21,7 @@ BASE=$(basename $0)
# modify these in /etc/default/$BASE (/etc/default/docker)
DOCKER=/usr/bin/$BASE
DOCKER_PIDFILE=/var/run/$BASE.pid
DOCKER_LOGFILE=/var/log/$BASE.log
DOCKER_OPTS=
DOCKER_DESC="Docker"
@@ -50,23 +51,37 @@ fail_unless_root() {
fi
}
cgroupfs_mount() {
# see also https://github.com/tianon/cgroupfs-mount/blob/master/cgroupfs-mount
if grep -v '^#' /etc/fstab | grep -q cgroup \
|| [ ! -e /proc/cgroups ] \
|| [ ! -d /sys/fs/cgroup ]; then
return
fi
if ! mountpoint -q /sys/fs/cgroup; then
mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup
fi
(
cd /sys/fs/cgroup
for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do
mkdir -p $sys
if ! mountpoint -q $sys; then
if ! mount -n -t cgroup -o $sys cgroup $sys; then
rmdir $sys || true
fi
fi
done
)
}
case "$1" in
start)
fail_unless_root
if ! grep -q cgroup /proc/mounts; then
# rough approximation of cgroupfs-mount
mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup
for sys in $(cut -d' ' -f1 /proc/cgroups); do
mkdir -p /sys/fs/cgroup/$sys
if ! mount -n -t cgroup -o $sys cgroup /sys/fs/cgroup/$sys 2>/dev/null; then
rmdir /sys/fs/cgroup/$sys 2>/dev/null || true
fi
done
fi
cgroupfs_mount
touch /var/log/docker.log
chgrp docker /var/log/docker.log
touch "$DOCKER_LOGFILE"
chgrp docker "$DOCKER_LOGFILE"
log_begin_msg "Starting $DOCKER_DESC: $BASE"
start-stop-daemon --start --background \
@@ -76,7 +91,7 @@ case "$1" in
-- \
-d -p "$DOCKER_PIDFILE" \
$DOCKER_OPTS \
> /var/log/docker.log 2>&1
>> "$DOCKER_LOGFILE" 2>&1
log_end_msg $?
;;
+23 -10
View File
@@ -5,6 +5,29 @@ stop on runlevel [!2345]
respawn
pre-start script
# see also https://github.com/tianon/cgroupfs-mount/blob/master/cgroupfs-mount
if grep -v '^#' /etc/fstab | grep -q cgroup \
|| [ ! -e /proc/cgroups ] \
|| [ ! -d /sys/fs/cgroup ]; then
exit 0
fi
if ! mountpoint -q /sys/fs/cgroup; then
mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup
fi
(
cd /sys/fs/cgroup
for sys in $(awk '!/^#/ { if ($4 == 1) print $1 }' /proc/cgroups); do
mkdir -p $sys
if ! mountpoint -q $sys; then
if ! mount -n -t cgroup -o $sys cgroup $sys; then
rmdir $sys || true
fi
fi
done
)
end script
script
# modify these in /etc/default/$UPSTART_JOB (/etc/default/docker)
DOCKER=/usr/bin/$UPSTART_JOB
@@ -12,15 +35,5 @@ script
if [ -f /etc/default/$UPSTART_JOB ]; then
. /etc/default/$UPSTART_JOB
fi
if ! grep -q cgroup /proc/mounts; then
# rough approximation of cgroupfs-mount
mount -t tmpfs -o uid=0,gid=0,mode=0755 cgroup /sys/fs/cgroup
for sys in $(cut -d' ' -f1 /proc/cgroups); do
mkdir -p /sys/fs/cgroup/$sys
if ! mount -n -t cgroup -o $sys cgroup /sys/fs/cgroup/$sys 2>/dev/null; then
rmdir /sys/fs/cgroup/$sys 2>/dev/null || true
fi
done
fi
"$DOCKER" -d $DOCKER_OPTS
end script
+2 -2
View File
@@ -7,7 +7,7 @@
Docker Security
===============
*Adapted from* `Containers & Docker: How Secure are They? <blogsecurity>`_
*Adapted from* `Containers & Docker: How Secure are They? <blogsecurity_>`_
There are three major areas to consider when reviewing Docker security:
@@ -261,7 +261,7 @@ with Docker, since everything is provided by the kernel anyway.
For more context and especially for comparisons with VMs and other
container systems, please also see the `original blog post
<blogsecurity>`_.
<blogsecurity_>`_.
.. _blogsecurity: http://blog.docker.io/2013/08/containers-docker-how-secure-are-they/
+45 -16
View File
@@ -88,7 +88,7 @@ Commands
-v, --version=false: Print version information and quit
--mtu=0: Set the containers network MTU; if no value is provided: default to the default route MTU or 1500 if no default route is available
The Docker daemon is the persistent process that manages containers. Docker uses the same binary for both the
The Docker daemon is the persistent process that manages containers. Docker uses the same binary for both the
daemon and client. To run the daemon you provide the ``-d`` flag.
To force Docker to use devicemapper as the storage driver, use ``docker -d -s devicemapper``.
@@ -100,10 +100,10 @@ To run the daemon with debug output, use ``docker -d -D``.
To use lxc as the execution driver, use ``docker -d -e lxc``.
The docker client will also honor the ``DOCKER_HOST`` environment variable to set
the ``-H`` flag for the client.
the ``-H`` flag for the client.
::
docker -H tcp://0.0.0.0:4243 ps
# or
export DOCKER_HOST="tcp://0.0.0.0:4243"
@@ -141,7 +141,7 @@ TMPDIR and the data directory can be set like this:
You can detach from the container again (and leave it running) with
``CTRL-c`` (for a quiet exit) or ``CTRL-\`` to get a stacktrace of
the Docker client when it quits. When you detach from the container's
the Docker client when it quits. When you detach from the container's
process the exit code will be returned to the client.
To stop a container, use ``docker stop``.
@@ -303,7 +303,7 @@ by using the ``git://`` schema.
-m, --message="": Commit message
-a, --author="": Author (eg. "John Hannibal Smith <hannibal@a-team.com>"
--run="": Configuration to be applied when the image is launched with `docker run`.
--run="": Configuration changes to be applied when the image is launched with `docker run`.
(ex: -run='{"Cmd": ["cat", "/world"], "PortSpecs": ["22"]}')
.. _cli_commit_examples:
@@ -315,14 +315,14 @@ Commit an existing container
$ sudo docker ps
ID IMAGE COMMAND CREATED STATUS PORTS
c3f279d17e0a ubuntu:12.04 /bin/bash 7 days ago Up 25 hours
197387f1b436 ubuntu:12.04 /bin/bash 7 days ago Up 25 hours
c3f279d17e0a ubuntu:12.04 /bin/bash 7 days ago Up 25 hours
197387f1b436 ubuntu:12.04 /bin/bash 7 days ago Up 25 hours
$ docker commit c3f279d17e0a SvenDowideit/testimage:version3
f5283438590d
$ docker images | head
REPOSITORY TAG ID CREATED VIRTUAL SIZE
SvenDowideit/testimage version3 f5283438590d 16 seconds ago 335.7 MB
Change the command that a container runs
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -344,11 +344,40 @@ run ``ls /etc``.
apt host.conf lsb-base rc2.d
...
Merged configs example
......................
Say you have a Dockerfile like so:
.. code-block:: bash
ENV MYVAR foobar
RUN apt-get install openssh
EXPOSE 22
CMD ["/usr/sbin/sshd -D"]
...
If you run that, make some changes, and then commit, Docker will merge the environment variable and exposed port configuration settings with any that you specify in the -run= option. This is a change from Docker 0.8.0 and prior where no attempt was made to preserve any existing configuration on commit.
.. code-block:: bash
$ docker build -t me/foo .
$ docker run -t -i me/foo /bin/bash
foo-container$ [make changes in the container]
foo-container$ exit
$ docker commit -run='{"Cmd": ["ls"]}' [container-id] me/bar
...
The me/bar image will now have port 22 exposed, MYVAR env var set to 'foobar', and its default command will be ["ls"].
Note that this is currently a shallow merge. So, for example, if you had specified a new port spec in the -run= config above, that would have clobbered the 'EXPOSE 22' setting from the parent container.
Full -run example
.................
The ``--run`` JSON hash changes the ``Config`` section when running ``docker inspect CONTAINERID``
or ``config`` when running ``docker inspect IMAGEID``.
or ``config`` when running ``docker inspect IMAGEID``. Existing configuration key-values that are
not overridden in the JSON hash will be merged in.
(Multiline is okay within a single quote ``'``)
@@ -664,7 +693,7 @@ Displaying image hierarchy
Usage: docker import URL|- [REPOSITORY[:TAG]]
Create an empty filesystem image and import the contents of the tarball
Create an empty filesystem image and import the contents of the tarball
(.tar, .tar.gz, .tgz, .bzip, .tar.xz, .txz) into it, then optionally tag it.
At this time, the URL must start with ``http`` and point to a single
@@ -942,7 +971,7 @@ Running ``docker ps`` showing 2 linked containers.
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4c01db0b339c ubuntu:12.04 bash 17 seconds ago Up 16 seconds webapp
4c01db0b339c ubuntu:12.04 bash 17 seconds ago Up 16 seconds webapp
d7886598dbe2 crosbymichael/redis:latest /redis-server --dir 33 minutes ago Up 33 minutes 6379/tcp redis,webapp/db
fd2645e2e2b5 busybox:latest top 10 days ago Ghost insane_ptolemy
@@ -1047,7 +1076,7 @@ containers will not be deleted.
Remove one or more images
-f, --force=false: Force
Removing tagged images
~~~~~~~~~~~~~~~~~~~~~~
@@ -1126,8 +1155,8 @@ Once the container is stopped it still exists and can be started back up. See `
The ``docker run`` command can be used in combination with ``docker commit`` to
:ref:`change the command that a container runs <cli_commit_examples>`.
See :ref:`port_redirection` for more detailed information about the ``--expose``,
``-p``, ``-P`` and ``--link`` parameters, and :ref:`working_with_links_names` for
See :ref:`port_redirection` for more detailed information about the ``--expose``,
``-p``, ``-P`` and ``--link`` parameters, and :ref:`working_with_links_names` for
specific examples using ``--link``.
Known Issues (run -volumes-from)
@@ -1207,8 +1236,8 @@ starting your container.
$ sudo docker run -t -i -v /var/run/docker.sock:/var/run/docker.sock -v ./static-docker:/usr/bin/docker busybox sh
By bind-mounting the docker unix socket and statically linked docker binary
(such as that provided by https://get.docker.io), you give the container
By bind-mounting the docker unix socket and statically linked docker binary
(such as that provided by https://get.docker.io), you give the container
the full access to create and manipulate the host's docker daemon.
.. code-block:: bash
+7 -3
View File
@@ -84,11 +84,15 @@ type Driver interface {
// Network settings of the container
type Network struct {
Interface *NetworkInterface `json:"interface"` // if interface is nil then networking is disabled
Mtu int `json:"mtu"`
}
type NetworkInterface struct {
Gateway string `json:"gateway"`
IPAddress string `json:"ip"`
Bridge string `json:"bridge"`
IPPrefixLen int `json:"ip_prefix_len"`
Mtu int `json:"mtu"`
}
type Resources struct {
@@ -111,8 +115,8 @@ type Command struct {
WorkingDir string `json:"working_dir"`
ConfigPath string `json:"config_path"` // this should be able to be removed when the lxc template is moved into the driver
Tty bool `json:"tty"`
Network *Network `json:"network"` // if network is nil then networking is disabled
Config []string `json:"config"` // generic values that specific drivers can consume
Network *Network `json:"network"`
Config []string `json:"config"` // generic values that specific drivers can consume
Resources *Resources `json:"resources"`
Terminal Terminal `json:"-"` // standard or tty terminal
+9 -4
View File
@@ -94,13 +94,15 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
DriverName,
}
if c.Network != nil {
if c.Network.Interface != nil {
params = append(params,
"-g", c.Network.Gateway,
"-i", fmt.Sprintf("%s/%d", c.Network.IPAddress, c.Network.IPPrefixLen),
"-mtu", strconv.Itoa(c.Network.Mtu),
"-g", c.Network.Interface.Gateway,
"-i", fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
)
}
params = append(params,
"-mtu", strconv.Itoa(c.Network.Mtu),
)
if c.User != "" {
params = append(params, "-u", c.User)
@@ -168,6 +170,9 @@ func (d *driver) Run(c *execdriver.Command, pipes *execdriver.Pipes, startCallba
// Poll lxc for RUNNING status
pid, err := d.waitForStart(c, waitLock)
if err != nil {
if c.Process != nil {
c.Process.Kill()
}
return -1, err
}
c.ContainerPid = pid
+1 -1
View File
@@ -36,7 +36,7 @@ func parseLxcInfo(raw string) (*lxcInfo, error) {
if len(parts) < 2 {
continue
}
switch strings.TrimSpace(parts[0]) {
switch strings.ToLower(strings.TrimSpace(parts[0])) {
case "state":
info.Running = strings.TrimSpace(parts[1]) == "RUNNING"
case "pid":
+3 -3
View File
@@ -7,17 +7,17 @@ import (
)
const LxcTemplate = `
{{if .Network}}
{{if .Network.Interface}}
# network configuration
lxc.network.type = veth
lxc.network.link = {{.Network.Bridge}}
lxc.network.link = {{.Network.Interface.Bridge}}
lxc.network.name = eth0
lxc.network.mtu = {{.Network.Mtu}}
{{else}}
# network is disabled (-n=false)
lxc.network.type = empty
lxc.network.flags = up
{{end}}
lxc.network.mtu = {{.Network.Mtu}}
# root filesystem
{{$ROOTFS := .Rootfs}}
+8
View File
@@ -43,6 +43,10 @@ func TestLXCConfig(t *testing.T) {
Memory: int64(mem),
CpuShares: int64(cpu),
},
Network: &execdriver.Network{
Mtu: 1500,
Interface: nil,
},
}
p, err := driver.generateLXCConfig(command)
if err != nil {
@@ -75,6 +79,10 @@ func TestCustomLxcConfig(t *testing.T) {
"lxc.utsname = docker",
"lxc.cgroup.cpuset.cpus = 0,1",
},
Network: &execdriver.Network{
Mtu: 1500,
Interface: nil,
},
}
p, err := driver.generateLXCConfig(command)
+22 -11
View File
@@ -19,19 +19,30 @@ func createContainer(c *execdriver.Command) *libcontainer.Container {
container.WorkingDir = c.WorkingDir
container.Env = c.Env
if c.Network != nil {
container.Networks = []*libcontainer.Network{
{
Mtu: c.Network.Mtu,
Address: fmt.Sprintf("%s/%d", c.Network.IPAddress, c.Network.IPPrefixLen),
Gateway: c.Network.Gateway,
Type: "veth",
Context: libcontainer.Context{
"prefix": "veth",
"bridge": c.Network.Bridge,
},
loopbackNetwork := libcontainer.Network{
Mtu: c.Network.Mtu,
Address: fmt.Sprintf("%s/%d", "127.0.0.1", 0),
Gateway: "localhost",
Type: "loopback",
Context: libcontainer.Context{},
}
container.Networks = []*libcontainer.Network{
&loopbackNetwork,
}
if c.Network.Interface != nil {
vethNetwork := libcontainer.Network{
Mtu: c.Network.Mtu,
Address: fmt.Sprintf("%s/%d", c.Network.Interface.IPAddress, c.Network.Interface.IPPrefixLen),
Gateway: c.Network.Interface.Gateway,
Type: "veth",
Context: libcontainer.Context{
"prefix": "veth",
"bridge": c.Network.Interface.Bridge,
},
}
container.Networks = append(container.Networks, &vethNetwork)
}
container.Cgroups.Name = c.ID
+50 -7
View File
@@ -39,6 +39,13 @@ type DevInfo struct {
// first get (since we need to mount to set up the device
// a bit first).
floating bool `json:"-"`
// The global DeviceSet lock guarantees that we serialize all
// the calls to libdevmapper (which is not threadsafe), but we
// sometimes release that lock while sleeping. In that case
// this per-device lock is still held, protecting against
// other accesses to the device that we're doing the wait on.
lock sync.Mutex `json:"-"`
}
type MetaData struct {
@@ -47,7 +54,7 @@ type MetaData struct {
type DeviceSet struct {
MetaData
sync.Mutex
sync.Mutex // Protects Devices map and serializes calls into libdevmapper
root string
devicePrefix string
TransactionId uint64
@@ -569,6 +576,9 @@ func (devices *DeviceSet) AddDevice(hash, baseHash string) error {
return fmt.Errorf("Error adding device for '%s': can't find device for parent '%s'", hash, baseHash)
}
baseInfo.lock.Lock()
defer baseInfo.lock.Unlock()
deviceId := devices.allocateDeviceId()
if err := devices.createSnapDevice(devices.getPoolDevName(), deviceId, baseInfo.Name(), baseInfo.DeviceId); err != nil {
@@ -636,6 +646,14 @@ func (devices *DeviceSet) DeleteDevice(hash string) error {
devices.Lock()
defer devices.Unlock()
info := devices.Devices[hash]
if info == nil {
return fmt.Errorf("Unknown device %s", hash)
}
info.lock.Lock()
defer info.lock.Unlock()
return devices.deleteDevice(hash)
}
@@ -683,7 +701,7 @@ func (devices *DeviceSet) deactivateDevice(hash string) error {
func (devices *DeviceSet) removeDeviceAndWait(devname string) error {
var err error
for i := 0; i < 10; i++ {
for i := 0; i < 1000; i++ {
devices.sawBusy = false
err = removeDevice(devname)
if err == nil {
@@ -695,7 +713,9 @@ func (devices *DeviceSet) removeDeviceAndWait(devname string) error {
// If we see EBUSY it may be a transient error,
// sleep a bit a retry a few times.
time.Sleep(5 * time.Millisecond)
devices.Unlock()
time.Sleep(10 * time.Millisecond)
devices.Lock()
}
if err != nil {
return err
@@ -709,7 +729,7 @@ func (devices *DeviceSet) removeDeviceAndWait(devname string) error {
// waitRemove blocks until either:
// a) the device registered at <device_set_prefix>-<hash> is removed,
// or b) the 1 second timeout expires.
// or b) the 10 second timeout expires.
func (devices *DeviceSet) waitRemove(devname string) error {
utils.Debugf("[deviceset %s] waitRemove(%s)", devices.devicePrefix, devname)
defer utils.Debugf("[deviceset %s] waitRemove(%s) END", devices.devicePrefix, devname)
@@ -728,7 +748,9 @@ func (devices *DeviceSet) waitRemove(devname string) error {
break
}
time.Sleep(1 * time.Millisecond)
devices.Unlock()
time.Sleep(10 * time.Millisecond)
devices.Lock()
}
if i == 1000 {
return fmt.Errorf("Timeout while waiting for device %s to be removed", devname)
@@ -738,7 +760,7 @@ func (devices *DeviceSet) waitRemove(devname string) error {
// waitClose blocks until either:
// a) the device registered at <device_set_prefix>-<hash> is closed,
// or b) the 1 second timeout expires.
// or b) the 10 second timeout expires.
func (devices *DeviceSet) waitClose(hash string) error {
info := devices.Devices[hash]
if info == nil {
@@ -756,7 +778,9 @@ func (devices *DeviceSet) waitClose(hash string) error {
if devinfo.OpenCount == 0 {
break
}
time.Sleep(1 * time.Millisecond)
devices.Unlock()
time.Sleep(10 * time.Millisecond)
devices.Lock()
}
if i == 1000 {
return fmt.Errorf("Timeout while waiting for device %s to close", hash)
@@ -773,20 +797,26 @@ func (devices *DeviceSet) Shutdown() error {
defer utils.Debugf("[deviceset %s] shutdown END", devices.devicePrefix)
for _, info := range devices.Devices {
info.lock.Lock()
if info.mountCount > 0 {
if err := sysUnmount(info.mountPath, 0); err != nil {
utils.Debugf("Shutdown unmounting %s, error: %s\n", info.mountPath, err)
}
}
info.lock.Unlock()
}
for _, d := range devices.Devices {
d.lock.Lock()
if err := devices.waitClose(d.Hash); err != nil {
utils.Errorf("Warning: error waiting for device %s to unmount: %s\n", d.Hash, err)
}
if err := devices.deactivateDevice(d.Hash); err != nil {
utils.Debugf("Shutdown deactivate %s , error: %s\n", d.Hash, err)
}
d.lock.Unlock()
}
if err := devices.deactivatePool(); err != nil {
@@ -805,6 +835,9 @@ func (devices *DeviceSet) MountDevice(hash, path string) error {
return fmt.Errorf("Unknown device %s", hash)
}
info.lock.Lock()
defer info.lock.Unlock()
if info.mountCount > 0 {
if path != info.mountPath {
return fmt.Errorf("Trying to mount devmapper device in multple places (%s, %s)", info.mountPath, path)
@@ -851,6 +884,9 @@ func (devices *DeviceSet) UnmountDevice(hash string, mode UnmountMode) error {
return fmt.Errorf("UnmountDevice: no such device %s\n", hash)
}
info.lock.Lock()
defer info.lock.Unlock()
if mode == UnmountFloat {
if info.floating {
return fmt.Errorf("UnmountDevice: can't float floating reference %s\n", hash)
@@ -920,6 +956,10 @@ func (devices *DeviceSet) HasActivatedDevice(hash string) bool {
if info == nil {
return false
}
info.lock.Lock()
defer info.lock.Unlock()
devinfo, _ := getInfo(info.Name())
return devinfo != nil && devinfo.Exists != 0
}
@@ -974,6 +1014,9 @@ func (devices *DeviceSet) GetDeviceStatus(hash string) (*DevStatus, error) {
return nil, fmt.Errorf("No device %s", hash)
}
info.lock.Lock()
defer info.lock.Unlock()
status := &DevStatus{
DeviceId: info.DeviceId,
Size: info.Size,
+7
View File
@@ -90,6 +90,13 @@ func (d *Driver) Create(id, parent string) error {
}
func (d *Driver) Remove(id string) error {
if !d.DeviceSet.HasDevice(id) {
// Consider removing a non-existing device a no-op
// This is useful to be able to progress on container removal
// if the underlying device has gone away due to earlier errors
return nil
}
// Sink the float from create in case no Get() call was made
if err := d.DeviceSet.UnmountDevice(id, UnmountSink); err != nil {
return err
+30 -1
View File
@@ -930,7 +930,7 @@ run [ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]
// #2098 - Docker cidFiles only contain short version of the containerId
//sudo docker run --cidfile /tmp/docker_test.cid ubuntu echo "test"
// TestRunCidFile tests that run --cidfile returns the longid
func TestRunCidFile(t *testing.T) {
func TestRunCidFileCheckIDLength(t *testing.T) {
stdout, stdoutPipe := io.Pipe()
tmpDir, err := ioutil.TempDir("", "TestRunCidFile")
@@ -979,6 +979,35 @@ func TestRunCidFile(t *testing.T) {
}
// Ensure that CIDFile gets deleted if it's empty
// Perform this test by making `docker run` fail
func TestRunCidFileCleanupIfEmpty(t *testing.T) {
tmpDir, err := ioutil.TempDir("", "TestRunCidFile")
if err != nil {
t.Fatal(err)
}
tmpCidFile := path.Join(tmpDir, "cid")
cli := api.NewDockerCli(nil, ioutil.Discard, ioutil.Discard, testDaemonProto, testDaemonAddr)
defer cleanup(globalEngine, t)
c := make(chan struct{})
go func() {
defer close(c)
if err := cli.CmdRun("--cidfile", tmpCidFile, unitTestImageID); err == nil {
t.Fatal("running without a command should haveve failed")
}
if _, err := os.Stat(tmpCidFile); err == nil {
t.Fatalf("empty CIDFile '%s' should've been deleted", tmpCidFile)
}
}()
defer os.RemoveAll(tmpDir)
setTimeout(t, "CmdRun timed out", 5*time.Second, func() {
<-c
})
}
func TestContainerOrphaning(t *testing.T) {
// setup a temporary directory
+47 -22
View File
@@ -434,28 +434,6 @@ func TestOutput(t *testing.T) {
}
}
func TestContainerNetwork(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, _, err := runtime.Create(
&runconfig.Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"ping", "-c", "1", "127.0.0.1"},
},
"",
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
if err := container.Run(); err != nil {
t.Fatal(err)
}
if code := container.State.GetExitCode(); code != 0 {
t.Fatalf("Unexpected ping 127.0.0.1 exit code %d (expected 0)", code)
}
}
func TestKillDifferentUser(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
@@ -1523,6 +1501,53 @@ func TestVolumesFromWithVolumes(t *testing.T) {
}
}
func TestContainerNetwork(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, _, err := runtime.Create(
&runconfig.Config{
Image: GetTestImage(runtime).ID,
// If I change this to ping 8.8.8.8 it fails. Any idea why? - timthelion
Cmd: []string{"ping", "-c", "1", "127.0.0.1"},
},
"",
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
if err := container.Run(); err != nil {
t.Fatal(err)
}
if code := container.State.GetExitCode(); code != 0 {
t.Fatalf("Unexpected ping 127.0.0.1 exit code %d (expected 0)", code)
}
}
// Issue #4681
func TestLoopbackFunctionsWhenNetworkingIsDissabled(t *testing.T) {
runtime := mkRuntime(t)
defer nuke(runtime)
container, _, err := runtime.Create(
&runconfig.Config{
Image: GetTestImage(runtime).ID,
Cmd: []string{"ping", "-c", "1", "127.0.0.1"},
NetworkDisabled: true,
},
"",
)
if err != nil {
t.Fatal(err)
}
defer runtime.Destroy(container)
if err := container.Run(); err != nil {
t.Fatal(err)
}
if code := container.State.GetExitCode(); code != 0 {
t.Fatalf("Unexpected ping 127.0.0.1 exit code %d (expected 0)", code)
}
}
func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) {
eng := NewTestEngine(t)
runtime := mkRuntimeFromEngine(eng, t)
+57
View File
@@ -281,6 +281,63 @@ func TestCommit(t *testing.T) {
}
}
func TestMergeConfigOnCommit(t *testing.T) {
eng := NewTestEngine(t)
runtime := mkRuntimeFromEngine(eng, t)
defer runtime.Nuke()
container1, _, _ := mkContainer(runtime, []string{"-e", "FOO=bar", unitTestImageID, "echo test > /tmp/foo"}, t)
defer runtime.Destroy(container1)
config, _, _, err := runconfig.Parse([]string{container1.ID, "cat /tmp/foo"}, nil)
if err != nil {
t.Error(err)
}
job := eng.Job("commit", container1.ID)
job.Setenv("repo", "testrepo")
job.Setenv("tag", "testtag")
job.SetenvJson("config", config)
var newId string
job.Stdout.AddString(&newId)
if err := job.Run(); err != nil {
t.Error(err)
}
container2, _, _ := mkContainer(runtime, []string{newId}, t)
defer runtime.Destroy(container2)
job = eng.Job("inspect", container1.Name, "container")
baseContainer, _ := job.Stdout.AddEnv()
if err := job.Run(); err != nil {
t.Error(err)
}
job = eng.Job("inspect", container2.Name, "container")
commitContainer, _ := job.Stdout.AddEnv()
if err := job.Run(); err != nil {
t.Error(err)
}
baseConfig := baseContainer.GetSubEnv("Config")
commitConfig := commitContainer.GetSubEnv("Config")
if commitConfig.Get("Env") != baseConfig.Get("Env") {
t.Fatalf("Env config in committed container should be %v, was %v",
baseConfig.Get("Env"), commitConfig.Get("Env"))
}
if baseConfig.Get("Cmd") != "[\"echo test \\u003e /tmp/foo\"]" {
t.Fatalf("Cmd in base container should be [\"echo test \\u003e /tmp/foo\"], was %s",
baseConfig.Get("Cmd"))
}
if commitConfig.Get("Cmd") != "[\"cat /tmp/foo\"]" {
t.Fatalf("Cmd in committed container should be [\"cat /tmp/foo\"], was %s",
commitConfig.Get("Cmd"))
}
}
func TestRestartKillWait(t *testing.T) {
eng := NewTestEngine(t)
srv := mkServerFromEngine(eng, t)
+6
View File
@@ -5,6 +5,7 @@ import (
"io/ioutil"
"os"
"os/exec"
"path"
)
const DefaultProfilePath = "/etc/apparmor.d/docker"
@@ -85,6 +86,11 @@ func InstallDefaultProfile() error {
return nil
}
// Make sure /etc/apparmor.d exists
if err := os.MkdirAll(path.Dir(DefaultProfilePath), 0755); err != nil {
return err
}
if err := ioutil.WriteFile(DefaultProfilePath, []byte(DefaultProfile), 0644); err != nil {
return err
}
+24
View File
@@ -0,0 +1,24 @@
package network
import (
"fmt"
"github.com/dotcloud/docker/pkg/libcontainer"
)
// Loopback is a network strategy that provides a basic loopback device
type Loopback struct {
}
func (l *Loopback) Create(n *libcontainer.Network, nspid int, context libcontainer.Context) error {
return nil
}
func (l *Loopback) Initialize(config *libcontainer.Network, context libcontainer.Context) error {
if err := SetMtu("lo", config.Mtu); err != nil {
return fmt.Errorf("set lo mtu to %d %s", config.Mtu, err)
}
if err := InterfaceUp("lo"); err != nil {
return fmt.Errorf("lo up %s", err)
}
return nil
}
+2 -1
View File
@@ -10,7 +10,8 @@ var (
)
var strategies = map[string]NetworkStrategy{
"veth": &Veth{},
"veth": &Veth{},
"loopback": &Loopback{},
}
// NetworkStrategy represents a specific network configuration for
-6
View File
@@ -68,12 +68,6 @@ func (v *Veth) Initialize(config *libcontainer.Network, context libcontainer.Con
if err := InterfaceUp("eth0"); err != nil {
return fmt.Errorf("eth0 up %s", err)
}
if err := SetMtu("lo", config.Mtu); err != nil {
return fmt.Errorf("set lo mtu to %d %s", config.Mtu, err)
}
if err := InterfaceUp("lo"); err != nil {
return fmt.Errorf("lo up %s", err)
}
if config.Gateway != "" {
if err := SetDefaultGateway(config.Gateway); err != nil {
return fmt.Errorf("set gateway to %s %s", config.Gateway, err)
+8 -2
View File
@@ -48,7 +48,9 @@ func (ns *linuxNs) Init(container *libcontainer.Container, uncleanRootfs, consol
return fmt.Errorf("setctty %s", err)
}
}
if err := system.ParentDeathSignal(); err != nil {
// this is our best effort to let the process know that the parent has died and that it
// should it should act on it how it sees fit
if err := system.ParentDeathSignal(uintptr(syscall.SIGTERM)); err != nil {
return fmt.Errorf("parent death signal %s", err)
}
if err := setupNewMountNamespace(rootfs, console, container.ReadonlyFs, container.NoPivotRoot); err != nil {
@@ -124,7 +126,11 @@ func setupNetwork(container *libcontainer.Container, context libcontainer.Contex
if err != nil {
return err
}
return strategy.Initialize(config, context)
err1 := strategy.Initialize(config, context)
if err1 != nil {
return err1
}
}
return nil
}
+6 -6
View File
@@ -46,10 +46,8 @@ func setupNewMountNamespace(rootfs, console string, readonly, noPivotRoot bool)
if err := setupDev(rootfs); err != nil {
return err
}
if console != "" {
if err := setupPtmx(rootfs, console); err != nil {
return err
}
if err := setupPtmx(rootfs, console); err != nil {
return err
}
if err := system.Chdir(rootfs); err != nil {
return fmt.Errorf("chdir into %s %s", rootfs, err)
@@ -245,8 +243,10 @@ func setupPtmx(rootfs, console string) error {
if err := os.Symlink("pts/ptmx", ptmx); err != nil {
return fmt.Errorf("symlink dev ptmx %s", err)
}
if err := setupConsole(rootfs, console); err != nil {
return err
if console != "" {
if err := setupConsole(rootfs, console); err != nil {
return err
}
}
return nil
}
+6 -21
View File
@@ -5,15 +5,10 @@
*/
package listenbuffer
import (
"fmt"
"net"
"time"
)
import "net"
// NewListenBuffer returns a listener listening on addr with the protocol. It sets the
// timeout to wait on first connection before an error is returned
func NewListenBuffer(proto, addr string, activate chan struct{}, timeout time.Duration) (net.Listener, error) {
// NewListenBuffer returns a listener listening on addr with the protocol.
func NewListenBuffer(proto, addr string, activate chan struct{}) (net.Listener, error) {
wrapped, err := net.Listen(proto, addr)
if err != nil {
return nil, err
@@ -22,7 +17,6 @@ func NewListenBuffer(proto, addr string, activate chan struct{}, timeout time.Du
return &defaultListener{
wrapped: wrapped,
activate: activate,
timeout: timeout,
}, nil
}
@@ -30,7 +24,6 @@ type defaultListener struct {
wrapped net.Listener // the real listener to wrap
ready bool // is the listner ready to start accpeting connections
activate chan struct{}
timeout time.Duration // how long to wait before we consider this an error
}
func (l *defaultListener) Close() error {
@@ -47,15 +40,7 @@ func (l *defaultListener) Accept() (net.Conn, error) {
if l.ready {
return l.wrapped.Accept()
}
select {
case <-time.After(l.timeout):
// close the connection so any clients are disconnected
l.Close()
return nil, fmt.Errorf("timeout (%s) reached waiting for listener to become ready", l.timeout.String())
case <-l.activate:
l.ready = true
return l.Accept()
}
panic("unreachable")
<-l.activate
l.ready = true
return l.Accept()
}
+2 -1
View File
@@ -13,7 +13,8 @@ var (
func init() {
flag.Bool([]string{"#hp", "#-halp"}, false, "display the halp")
flag.BoolVar(&b, []string{"b"}, false, "a simple bool")
flag.BoolVar(&b, []string{"b", "#bal", "#bol", "-bal"}, false, "a simple bool")
flag.BoolVar(&b, []string{"g", "#gil"}, false, "a simple bool")
flag.BoolVar(&b2, []string{"#-bool"}, false, "a simple bool")
flag.IntVar(&i, []string{"-integer", "-number"}, -1, "a simple integer")
flag.StringVar(&str, []string{"s", "#hidden", "-string"}, "", "a simple string") //-s -hidden and --string will work, but -hidden won't be in the usage
+13 -2
View File
@@ -805,9 +805,20 @@ func (f *FlagSet) parseOne() (bool, string, error) {
f.actual = make(map[string]*Flag)
}
f.actual[name] = flag
for _, n := range flag.Names {
for i, n := range flag.Names {
if n == fmt.Sprintf("#%s", name) {
fmt.Fprintf(f.out(), "Warning: '-%s' is deprecated, it will be removed soon. See usage.\n", name)
replacement := ""
for j := i; j < len(flag.Names); j++ {
if flag.Names[j][0] != '#' {
replacement = flag.Names[j]
break
}
}
if replacement != "" {
fmt.Fprintf(f.out(), "Warning: '-%s' is deprecated, it will be replaced by '-%s' soon. See usage.\n", name, replacement)
} else {
fmt.Fprintf(f.out(), "Warning: '-%s' is deprecated, it will be removed soon. See usage.\n", name)
}
}
}
return true, "", nil
+19
View File
@@ -0,0 +1,19 @@
package signal
import (
"os"
"os/signal"
)
func CatchAll(sigc chan os.Signal) {
handledSigs := []os.Signal{}
for _, s := range SignalMap {
handledSigs = append(handledSigs, s)
}
signal.Notify(sigc, handledSigs...)
}
func StopCatch(sigc chan os.Signal) {
signal.Stop(sigc)
close(sigc)
}
+40
View File
@@ -0,0 +1,40 @@
package signal
import (
"syscall"
)
var SignalMap = map[string]syscall.Signal{
"ABRT": syscall.SIGABRT,
"ALRM": syscall.SIGALRM,
"BUG": syscall.SIGBUS,
"CHLD": syscall.SIGCHLD,
"CONT": syscall.SIGCONT,
"EMT": syscall.SIGEMT,
"FPE": syscall.SIGFPE,
"HUP": syscall.SIGHUP,
"ILL": syscall.SIGILL,
"INFO": syscall.SIGINFO,
"INT": syscall.SIGINT,
"IO": syscall.SIGIO,
"IOT": syscall.SIGIOT,
"KILL": syscall.SIGKILL,
"PIPE": syscall.SIGPIPE,
"PROF": syscall.SIGPROF,
"QUIT": syscall.SIGQUIT,
"SEGV": syscall.SIGSEGV,
"STOP": syscall.SIGSTOP,
"SYS": syscall.SIGSYS,
"TERM": syscall.SIGTERM,
"TRAP": syscall.SIGTRAP,
"TSTP": syscall.SIGTSTP,
"TTIN": syscall.SIGTTIN,
"TTOU": syscall.SIGTTOU,
"URG": syscall.SIGURG,
"USR1": syscall.SIGUSR1,
"USR2": syscall.SIGUSR2,
"VTALRM": syscall.SIGVTALRM,
"WINCH": syscall.SIGWINCH,
"XCPU": syscall.SIGXCPU,
"XFSZ": syscall.SIGXFSZ,
}
+44
View File
@@ -0,0 +1,44 @@
package signal
import (
"os"
"os/signal"
"syscall"
)
var SignalMap = map[string]syscall.Signal{
"ABRT": syscall.SIGABRT,
"ALRM": syscall.SIGALRM,
"BUF": syscall.SIGBUS,
"CHLD": syscall.SIGCHLD,
"CONT": syscall.SIGCONT,
"EMT": syscall.SIGEMT,
"FPE": syscall.SIGFPE,
"HUP": syscall.SIGHUP,
"ILL": syscall.SIGILL,
"INFO": syscall.SIGINFO,
"INT": syscall.SIGINT,
"IO": syscall.SIGIO,
"IOT": syscall.SIGIOT,
"KILL": syscall.SIGKILL,
"LWP": syscall.SIGLWP,
"PIPE": syscall.SIGPIPE,
"PROF": syscall.SIGPROF,
"QUIT": syscall.SIGQUIT,
"SEGV": syscall.SIGSEGV,
"STOP": syscall.SIGSTOP,
"SYS": syscall.SIGSYS,
"TERM": syscall.SIGTERM,
"THR": syscall.SIGTHR,
"TRAP": syscall.SIGTRAP,
"TSTP": syscall.SIGTSTP,
"TTIN": syscall.SIGTTIN,
"TTOU": syscall.SIGTTOU,
"URG": syscall.SIGURG,
"USR1": syscall.SIGUSR1,
"USR2": syscall.SIGUSR2,
"VTALRM": syscall.SIGVTALRM,
"WINCH": syscall.SIGWINCH,
"XCPU": syscall.SIGXCPU,
"XFSZ": syscall.SIGXFSZ,
}
+43
View File
@@ -0,0 +1,43 @@
package signal
import (
"syscall"
)
var SignalMap = map[string]syscall.Signal{
"ABRT": syscall.SIGABRT,
"ALRM": syscall.SIGALRM,
"BUS": syscall.SIGBUS,
"CHLD": syscall.SIGCHLD,
"CLD": syscall.SIGCLD,
"CONT": syscall.SIGCONT,
"FPE": syscall.SIGFPE,
"HUP": syscall.SIGHUP,
"ILL": syscall.SIGILL,
"INT": syscall.SIGINT,
"IO": syscall.SIGIO,
"IOT": syscall.SIGIOT,
"KILL": syscall.SIGKILL,
"PIPE": syscall.SIGPIPE,
"POLL": syscall.SIGPOLL,
"PROF": syscall.SIGPROF,
"PWR": syscall.SIGPWR,
"QUIT": syscall.SIGQUIT,
"SEGV": syscall.SIGSEGV,
"STKFLT": syscall.SIGSTKFLT,
"STOP": syscall.SIGSTOP,
"SYS": syscall.SIGSYS,
"TERM": syscall.SIGTERM,
"TRAP": syscall.SIGTRAP,
"TSTP": syscall.SIGTSTP,
"TTIN": syscall.SIGTTIN,
"TTOU": syscall.SIGTTOU,
"UNUSED": syscall.SIGUNUSED,
"URG": syscall.SIGURG,
"USR1": syscall.SIGUSR1,
"USR2": syscall.SIGUSR2,
"VTALRM": syscall.SIGVTALRM,
"WINCH": syscall.SIGWINCH,
"XCPU": syscall.SIGXCPU,
"XFSZ": syscall.SIGXFSZ,
}
+9
View File
@@ -0,0 +1,9 @@
// +build !linux,!darwin,!freebsd
package signal
import (
"syscall"
)
var SignalMap = map[string]syscall.Signal{}
+2 -2
View File
@@ -115,8 +115,8 @@ func Mknod(path string, mode uint32, dev int) error {
return syscall.Mknod(path, mode, dev)
}
func ParentDeathSignal() error {
if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_PDEATHSIG, uintptr(syscall.SIGKILL), 0); err != 0 {
func ParentDeathSignal(sig uintptr) error {
if _, _, err := syscall.RawSyscall(syscall.SYS_PRCTL, syscall.PR_SET_PDEATHSIG, sig, 0); err != 0 {
return err
}
return nil
+33 -47
View File
@@ -8,6 +8,7 @@ import (
"github.com/dotcloud/docker/dockerversion"
"github.com/dotcloud/docker/engine"
"github.com/dotcloud/docker/pkg/graphdb"
"github.com/dotcloud/docker/pkg/signal"
"github.com/dotcloud/docker/registry"
"github.com/dotcloud/docker/runconfig"
"github.com/dotcloud/docker/utils"
@@ -18,7 +19,7 @@ import (
"net/url"
"os"
"os/exec"
"os/signal"
gosignal "os/signal"
"path"
"path/filepath"
"runtime"
@@ -47,7 +48,7 @@ func InitServer(job *engine.Job) engine.Status {
}
job.Logf("Setting up signal traps")
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
gosignal.Notify(c, os.Interrupt, syscall.SIGTERM, syscall.SIGQUIT)
go func() {
sig := <-c
log.Printf("Received signal '%v', exiting\n", sig)
@@ -122,56 +123,30 @@ func (v *simpleVersionInfo) Version() string {
// for the container to exit.
// If a signal is given, then just send it to the container and return.
func (srv *Server) ContainerKill(job *engine.Job) engine.Status {
signalMap := map[string]syscall.Signal{
"HUP": syscall.SIGHUP,
"INT": syscall.SIGINT,
"QUIT": syscall.SIGQUIT,
"ILL": syscall.SIGILL,
"TRAP": syscall.SIGTRAP,
"ABRT": syscall.SIGABRT,
"BUS": syscall.SIGBUS,
"FPE": syscall.SIGFPE,
"KILL": syscall.SIGKILL,
"USR1": syscall.SIGUSR1,
"SEGV": syscall.SIGSEGV,
"USR2": syscall.SIGUSR2,
"PIPE": syscall.SIGPIPE,
"ALRM": syscall.SIGALRM,
"TERM": syscall.SIGTERM,
//"STKFLT": syscall.SIGSTKFLT,
"CHLD": syscall.SIGCHLD,
"CONT": syscall.SIGCONT,
"STOP": syscall.SIGSTOP,
"TSTP": syscall.SIGTSTP,
"TTIN": syscall.SIGTTIN,
"TTOU": syscall.SIGTTOU,
"URG": syscall.SIGURG,
"XCPU": syscall.SIGXCPU,
"XFSZ": syscall.SIGXFSZ,
"VTALRM": syscall.SIGVTALRM,
"PROF": syscall.SIGPROF,
"WINCH": syscall.SIGWINCH,
"IO": syscall.SIGIO,
//"PWR": syscall.SIGPWR,
"SYS": syscall.SIGSYS,
}
if n := len(job.Args); n < 1 || n > 2 {
return job.Errorf("Usage: %s CONTAINER [SIGNAL]", job.Name)
}
name := job.Args[0]
var sig uint64
var (
name = job.Args[0]
sig uint64
err error
)
// If we have a signal, look at it. Otherwise, do nothing
if len(job.Args) == 2 && job.Args[1] != "" {
sig = uint64(signalMap[job.Args[1]])
if sig == 0 {
var err error
// The largest legal signal is 31, so let's parse on 5 bits
sig, err = strconv.ParseUint(job.Args[1], 10, 5)
if err != nil {
// Check if we passed the singal as a number:
// The largest legal signal is 31, so let's parse on 5 bits
sig, err = strconv.ParseUint(job.Args[1], 10, 5)
if err != nil {
// The signal is not a number, treat it as a string
sig = uint64(signal.SignalMap[job.Args[1]])
if sig == 0 {
return job.Errorf("Invalid signal: %s", job.Args[1])
}
}
}
if container := srv.runtime.Get(name); container != nil {
// If no signal is passed, or SIGKILL, perform regular Kill (SIGKILL + wait())
if sig == 0 || syscall.Signal(sig) == syscall.SIGKILL {
@@ -1039,12 +1014,17 @@ func (srv *Server) ContainerCommit(job *engine.Job) engine.Status {
if container == nil {
return job.Errorf("No such container: %s", name)
}
var config runconfig.Config
if err := job.GetenvJson("config", &config); err != nil {
var config = container.Config
var newConfig runconfig.Config
if err := job.GetenvJson("config", &newConfig); err != nil {
return job.Error(err)
}
img, err := srv.runtime.Commit(container, job.Getenv("repo"), job.Getenv("tag"), job.Getenv("comment"), job.Getenv("author"), &config)
if err := runconfig.Merge(&newConfig, config); err != nil {
return job.Error(err)
}
img, err := srv.runtime.Commit(container, job.Getenv("repo"), job.Getenv("tag"), job.Getenv("comment"), job.Getenv("author"), &newConfig)
if err != nil {
return job.Error(err)
}
@@ -2390,7 +2370,13 @@ func (srv *Server) IsRunning() bool {
}
func (srv *Server) Close() error {
if srv == nil {
return nil
}
srv.SetRunning(false)
if srv.runtime == nil {
return nil
}
return srv.runtime.Close()
}
+1 -1
View File
@@ -85,7 +85,7 @@ func (jm *JSONMessage) Display(out io.Writer, isTerminal bool) error {
return jm.Error
}
var endl string
if isTerminal {
if isTerminal && jm.Stream == "" {
// <ESC>[2K = erase entire current line
fmt.Fprintf(out, "%c[2K\r", 27)
endl = "\r"
-11
View File
@@ -1,11 +0,0 @@
package utils
import (
"os"
"os/signal"
)
func StopCatch(sigc chan os.Signal) {
signal.Stop(sigc)
close(sigc)
}
-44
View File
@@ -1,44 +0,0 @@
package utils
import (
"os"
"os/signal"
"syscall"
)
func CatchAll(sigc chan os.Signal) {
signal.Notify(sigc,
syscall.SIGABRT,
syscall.SIGALRM,
syscall.SIGBUS,
syscall.SIGCHLD,
syscall.SIGCONT,
syscall.SIGEMT,
syscall.SIGFPE,
syscall.SIGHUP,
syscall.SIGILL,
syscall.SIGINFO,
syscall.SIGINT,
syscall.SIGIO,
syscall.SIGIOT,
syscall.SIGKILL,
syscall.SIGPIPE,
syscall.SIGPROF,
syscall.SIGQUIT,
syscall.SIGSEGV,
syscall.SIGSTOP,
syscall.SIGSYS,
syscall.SIGTERM,
syscall.SIGTRAP,
syscall.SIGTSTP,
syscall.SIGTTIN,
syscall.SIGTTOU,
syscall.SIGURG,
syscall.SIGUSR1,
syscall.SIGUSR2,
syscall.SIGVTALRM,
syscall.SIGWINCH,
syscall.SIGXCPU,
syscall.SIGXFSZ,
)
}
-47
View File
@@ -1,47 +0,0 @@
package utils
import (
"os"
"os/signal"
"syscall"
)
func CatchAll(sigc chan os.Signal) {
signal.Notify(sigc,
syscall.SIGABRT,
syscall.SIGALRM,
syscall.SIGBUS,
syscall.SIGCHLD,
syscall.SIGCLD,
syscall.SIGCONT,
syscall.SIGFPE,
syscall.SIGHUP,
syscall.SIGILL,
syscall.SIGINT,
syscall.SIGIO,
syscall.SIGIOT,
syscall.SIGKILL,
syscall.SIGPIPE,
syscall.SIGPOLL,
syscall.SIGPROF,
syscall.SIGPWR,
syscall.SIGQUIT,
syscall.SIGSEGV,
syscall.SIGSTKFLT,
syscall.SIGSTOP,
syscall.SIGSYS,
syscall.SIGTERM,
syscall.SIGTRAP,
syscall.SIGTSTP,
syscall.SIGTTIN,
syscall.SIGTTOU,
syscall.SIGUNUSED,
syscall.SIGURG,
syscall.SIGUSR1,
syscall.SIGUSR2,
syscall.SIGVTALRM,
syscall.SIGWINCH,
syscall.SIGXCPU,
syscall.SIGXFSZ,
)
}