From 6d6c11dcebbdaa40b009f4416d41e3d4abad998f Mon Sep 17 00:00:00 2001 From: Tonis Tiigi Date: Fri, 23 Dec 2016 22:57:30 -0800 Subject: [PATCH 01/26] Fix inspect object by invalid reference Signed-off-by: Tonis Tiigi (cherry picked from commit 3cd39aaeab37102e4b12decc0c36042e477e2fa6) Signed-off-by: Victor Vieux --- integration-cli/docker_cli_inspect_test.go | 8 ++++++++ plugin/store.go | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/integration-cli/docker_cli_inspect_test.go b/integration-cli/docker_cli_inspect_test.go index 4e732c5ba8b165cb8eda601f7f485ed932809cfa..32ed28afe1a6b51247aa9552f2767c67c14d50e5 100644 --- a/integration-cli/docker_cli_inspect_test.go +++ b/integration-cli/docker_cli_inspect_test.go @@ -456,3 +456,11 @@ func (s *DockerSuite) TestInspectUnknownObject(c *check.C) { c.Assert(out, checker.Contains, "Error: No such object: foobar") c.Assert(err.Error(), checker.Contains, "Error: No such object: foobar") } + +func (s *DockerSuite) TestInpectInvalidReference(c *check.C) { + // This test should work on both Windows and Linux + out, _, err := dockerCmdWithError("inspect", "FooBar") + c.Assert(err, checker.NotNil) + c.Assert(out, checker.Contains, "Error: No such object: FooBar") + c.Assert(err.Error(), checker.Contains, "Error: No such object: FooBar") +} diff --git a/plugin/store.go b/plugin/store.go index ba0eb034009b61e07ab072134ab12285fd61f053..bb57e8066548c04b23263444b24f8a22c612ffd0 100644 --- a/plugin/store.go +++ b/plugin/store.go @@ -227,7 +227,7 @@ func (ps *Store) resolvePluginID(idOrName string) (string, error) { ref, err := reference.ParseNamed(idOrName) if err != nil { - return "", errors.Wrapf(err, "failed to parse %v", idOrName) + return "", errors.WithStack(ErrNotFound(idOrName)) } if _, ok := ref.(reference.Canonical); ok { logrus.Warnf("canonical references cannot be resolved: %v", ref.String()) From 97b0bb730eecf9031ba57f0028833104ea442275 Mon Sep 17 00:00:00 2001 From: Tobias Gesellchen Date: Mon, 26 Dec 2016 15:18:03 +0100 Subject: [PATCH 02/26] fix swagger description for `DELETE /plugin/{name}` Signed-off-by: Tobias Gesellchen (cherry picked from commit e6b2829a7f59b59eb1c3653313bc3c6a56b47b0c) Signed-off-by: Victor Vieux --- api/swagger.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/api/swagger.yaml b/api/swagger.yaml index b44f0adb7aacea15cc5c12701b4458e8aa9797d3..871fe0c2258d085a425f667b40b47d44ce806003 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -6582,6 +6582,7 @@ paths: required: true type: "string" tags: ["Plugin"] + /plugins/{name}: delete: summary: "Remove a plugin" operationId: "PluginDelete" From 1c5cb466492535b6aad217e92896c65ed5f65446 Mon Sep 17 00:00:00 2001 From: Akihiro Suda Date: Tue, 8 Nov 2016 10:31:09 +0000 Subject: [PATCH 03/26] update experimental/README.md Signed-off-by: Akihiro Suda (cherry picked from commit eb11a10ddf5169c8c761005ebd921505fdb309a4) Signed-off-by: Victor Vieux --- experimental/README.md | 79 +++++++++++------------------------------- 1 file changed, 20 insertions(+), 59 deletions(-) diff --git a/experimental/README.md b/experimental/README.md index 0ee893deaf24ebae8757ea794c26a6c3d056fe5f..796080cca597c47f8b56a627173fc7a3e24238f5 100644 --- a/experimental/README.md +++ b/experimental/README.md @@ -9,65 +9,26 @@ issues associated with it. If necessary, links are provided to additional documentation on an issue. As an active Docker user and community member, please feel free to provide any feedback on these features you wish. -## Install Docker experimental - -Unlike the regular Docker binary, the experimental channels is built and -updated nightly on https://experimental.docker.com. From one day to the -next, new features may appear, while existing experimental features may be -refined or entirely removed. - -1. Verify that you have `curl` installed. - - $ which curl - - If `curl` isn't installed, install it after updating your manager: - - $ sudo apt-get update - $ sudo apt-get install curl - -2. Get the latest Docker package. - - $ curl -sSL https://experimental.docker.com/ | sh - - The system prompts you for your `sudo` password. Then, it downloads and - installs Docker and its dependencies. - - >**Note**: If your company is behind a filtering proxy, you may find that the - >`apt-key` - >command fails for the Docker repo during installation. To work around this, - >add the key directly using the following: - > - > $ curl -sSL https://experimental.docker.com/gpg | sudo apt-key add - - -3. Verify `docker` is installed correctly. - - $ sudo docker run hello-world - - This command downloads a test image and runs it in a container. - -### Get the Linux binary -To download the latest experimental `docker` binary for Linux, -use the following URLs: - - https://experimental.docker.com/builds/Linux/i386/docker-latest.tgz - - https://experimental.docker.com/builds/Linux/x86_64/docker-latest.tgz - -After downloading the appropriate binary, you can follow the instructions -[here](https://docs.docker.com/engine/installation/binaries/#/get-the-docker-engine-binaries) to run the `docker` daemon. - -> **Note** -> -> 1) You can get the MD5 and SHA256 hashes by appending .md5 and .sha256 to the URLs respectively -> -> 2) You can get the compressed binaries by appending .tgz to the URLs - -### Build an experimental binary -You can also build the experimental binary from the standard development environment by adding -`DOCKER_EXPERIMENTAL=1` to the environment where you run `make` to build Docker binaries. For example, -to build a Docker binary with the experimental features enabled: - - $ DOCKER_EXPERIMENTAL=1 make binary +## Use Docker experimental + +Experimental features are now included in the standard Docker binaries as of +version 1.13.0. +For enabling experimental features, you need to start the Docker daemon with +`--experimental` flag. +You can also enable the daemon flag via `/etc/docker/daemon.json`. e.g. + +```json +{ + "experimental": true +} +``` + +Then make sure the experimental flag is enabled: + +```bash +$ docker version -f '{{.Server.Experimental}}' +true +``` ## Current experimental features From 2c53989b4b39ed780076cb93f6d29762e03c1a6e Mon Sep 17 00:00:00 2001 From: Zhang Wei Date: Sat, 17 Dec 2016 22:01:59 +0800 Subject: [PATCH 04/26] Add missing "--default-runtime" flag in manpage Add missing flag and more descriptions in manpage. Signed-off-by: Zhang Wei (cherry picked from commit 977fd439857006ab34deebac384b621bf4dae7da) Signed-off-by: Victor Vieux --- docs/reference/commandline/dockerd.md | 22 +++++++++-------- man/dockerd.8.md | 34 ++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 11 deletions(-) diff --git a/docs/reference/commandline/dockerd.md b/docs/reference/commandline/dockerd.md index b8bc8b712c01ec9a6ed777df3b706637fb0f9016..24ac77611d45abc2178e0eabdf770d1cf0c38404 100644 --- a/docs/reference/commandline/dockerd.md +++ b/docs/reference/commandline/dockerd.md @@ -684,16 +684,18 @@ configuration file or using the `--add-runtime` command line argument. The following is an example adding 2 runtimes via the configuration: ```json -"default-runtime": "runc", -"runtimes": { - "runc": { - "path": "runc" - }, - "custom": { - "path": "/usr/local/bin/my-runc-replacement", - "runtimeArgs": [ - "--debug" - ] +{ + "default-runtime": "runc", + "runtimes": { + "runc": { + "path": "runc" + }, + "custom": { + "path": "/usr/local/bin/my-runc-replacement", + "runtimeArgs": [ + "--debug" + ] + } } } ``` diff --git a/man/dockerd.8.md b/man/dockerd.8.md index f99e7a7cab33fd7e108d8a06c38b48bf83f4f096..761dc6b9be0106a2e68b33bc1a5244206d3833ee 100644 --- a/man/dockerd.8.md +++ b/man/dockerd.8.md @@ -20,6 +20,7 @@ dockerd - Enable daemon mode [**-D**|**--debug**] [**--default-gateway**[=*DEFAULT-GATEWAY*]] [**--default-gateway-v6**[=*DEFAULT-GATEWAY-V6*]] +[**--default-runtime**[=*runc*]] [**--default-ulimit**[=*[]*]] [**--disable-legacy-registry**] [**--dns**[=*[]*]] @@ -84,7 +85,35 @@ following format. # OPTIONS **--add-runtime**=[] - Set additional OCI compatible runtime. + Runtimes can be registered with the daemon either via the +configuration file or using the `--add-runtime` command line argument. + + The following is an example adding 2 runtimes via the configuration: + +```json +{ + "default-runtime": "runc", + "runtimes": { + "runc": { + "path": "runc" + }, + "custom": { + "path": "/usr/local/bin/my-runc-replacement", + "runtimeArgs": [ + "--debug" + ] + } + } +} +``` + + This is the same example via the command line: + +```bash +$ sudo dockerd --add-runtime runc=runc --add-runtime custom=/usr/local/bin/my-runc-replacement +``` + + **Note**: defining runtime arguments via the command line is not supported. **--api-cors-header**="" Set CORS headers in the Engine API. Default is cors disabled. Give urls like @@ -132,6 +161,9 @@ following format. **--default-gateway-v6**="" IPv6 address of the container default gateway +**--default-runtime**="runc" + Set default runtime if there're more than one specified by `--add-runtime`. + **--default-ulimit**=[] Default ulimits for containers. From c25a4762efcaad8b113ab48f7d10409057c153af Mon Sep 17 00:00:00 2001 From: Harald Albers Date: Sun, 18 Dec 2016 06:31:25 -0800 Subject: [PATCH 05/26] Remove bash completion for `docker node ps --all|-a` Signed-off-by: Harald Albers (cherry picked from commit a54cc4f88da67175938ac2a3d643e3de6cb4d4de) Signed-off-by: Victor Vieux --- contrib/completion/bash/docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index e04bb231ee69b6a08828c5c0b0a3026f87953497..dddee351958cf60891712bca6066ba73f91d9384 100644 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -3139,7 +3139,7 @@ _docker_node_ps() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "--all -a --filter -f --help --no-resolve --no-trunc" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--filter -f --help --no-resolve --no-trunc" -- "$cur" ) ) ;; *) __docker_complete_nodes_plus_self From e7960584f219f1a016b360f6432f3cf7e42c8052 Mon Sep 17 00:00:00 2001 From: Harald Albers Date: Sun, 18 Dec 2016 06:47:54 -0800 Subject: [PATCH 06/26] Remove `--all|-a` from `docker node ps` reference Signed-off-by: Harald Albers (cherry picked from commit 364e9002375fca1799180dd76e8074d922dd4044) Signed-off-by: Victor Vieux --- docs/reference/commandline/node_ps.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/reference/commandline/node_ps.md b/docs/reference/commandline/node_ps.md index 48c3abd6a0830ef4a11093eb218d4d145da3b53d..7f07c5ea64406adb4e7fbd786b5ce0bb1a43050e 100644 --- a/docs/reference/commandline/node_ps.md +++ b/docs/reference/commandline/node_ps.md @@ -22,7 +22,6 @@ Usage: docker node ps [OPTIONS] [NODE...] List tasks running on one or more nodes, defaults to current node. Options: - -a, --all Display all instances -f, --filter value Filter output based on conditions provided --help Print usage --no-resolve Do not map IDs to Names From 39b3e39c40f4c7a94ad97af227757766c691038a Mon Sep 17 00:00:00 2001 From: Harald Albers Date: Mon, 19 Dec 2016 11:40:59 -0800 Subject: [PATCH 07/26] Remove bash completion for deprecated `docker daemon` Signed-off-by: Harald Albers (cherry picked from commit 536a9ec698b8a2f51102b2c57cd9c675873b9af4) Signed-off-by: Victor Vieux --- contrib/completion/bash/docker | 1 - 1 file changed, 1 deletion(-) diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index dddee351958cf60891712bca6066ba73f91d9384..246cd5f62e3f366f4d4ba7e7e125f40766b17130 100644 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -3955,7 +3955,6 @@ _docker() { container cp create - daemon diff events exec From 994b3928f6ebc09f183a562e01f799e4adf903fb Mon Sep 17 00:00:00 2001 From: Yanqiang Miao Date: Sat, 24 Dec 2016 15:03:38 +0800 Subject: [PATCH 08/26] Add 'volume prune' to the volume commands index Signed-off-by: Yanqiang Miao (cherry picked from commit 3d4ea98971d319e9dbbeefbd1e82a9c0feae8c70) Signed-off-by: Victor Vieux --- docs/reference/commandline/index.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/reference/commandline/index.md b/docs/reference/commandline/index.md index 3402f2419061d3c6bd23829231170a0a966e6440..037464570822dc5ea82ccd077970ebf6015e66b0 100644 --- a/docs/reference/commandline/index.md +++ b/docs/reference/commandline/index.md @@ -106,6 +106,7 @@ read the [`dockerd`](dockerd.md) reference page. | [volume create](volume_create.md) | Creates a new volume where containers can consume and store data | | [volume inspect](volume_inspect.md) | Display information about a volume | | [volume ls](volume_ls.md) | Lists all the volumes Docker knows about | +| [volume prune](volume_prune.md) | Remove all unused volumes | | [volume rm](volume_rm.md) | Remove one or more volumes | From c809c40647207995a3b9f502283320801fa45a59 Mon Sep 17 00:00:00 2001 From: Harald Albers Date: Sun, 25 Dec 2016 05:32:50 -0800 Subject: [PATCH 09/26] Add bash completion for `plugin install --alias` Signed-off-by: Harald Albers (cherry picked from commit 83158f8aff3ec01fa027556c48e364c5311a6839) Signed-off-by: Victor Vieux --- contrib/completion/bash/docker | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index 246cd5f62e3f366f4d4ba7e7e125f40766b17130..71a188b9c5e4c68755754b559ebfa590dfe02c35 100644 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -3266,9 +3266,15 @@ _docker_plugin_inspect() { } _docker_plugin_install() { + case "$prev" in + --alias) + return + ;; + esac + case "$cur" in -*) - COMPREPLY=( $( compgen -W "--disable --grant-all-permissions--help" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--alias --disable --grant-all-permissions --help" -- "$cur" ) ) ;; esac } From 8b155a910975c2c99c043587b7c9b5f559d67f87 Mon Sep 17 00:00:00 2001 From: yuexiao-wang Date: Tue, 27 Dec 2016 02:17:35 +0800 Subject: [PATCH 10/26] Update 'ID' field for 'docker plugin ls' Signed-off-by: yuexiao-wang (cherry picked from commit 1e6587ff280dc3dcac405a67af2ddfd83c78f983) Signed-off-by: Victor Vieux --- docs/extend/index.md | 4 ++-- docs/reference/commandline/plugin_disable.md | 8 ++++---- docs/reference/commandline/plugin_enable.md | 8 ++++---- docs/reference/commandline/plugin_install.md | 4 ++-- docs/reference/commandline/plugin_push.md | 5 ++--- 5 files changed, 14 insertions(+), 15 deletions(-) diff --git a/docs/extend/index.md b/docs/extend/index.md index fc31e74ce44a7ccbaf14bb367f604609c1e67bc0..e7a62ba7582265a989f5019b4a76fdb90189ab41 100644 --- a/docs/extend/index.md +++ b/docs/extend/index.md @@ -69,8 +69,8 @@ enabled, and use it to create a volume. ```bash $ docker plugin ls - NAME TAG ENABLED - vieux/sshfs latest true + ID NAME TAG DESCRIPTION ENABLED + 69553ca1d789 vieux/sshfs latest the `sshfs` plugin true ``` 3. Create a volume using the plugin. diff --git a/docs/reference/commandline/plugin_disable.md b/docs/reference/commandline/plugin_disable.md index 0d4ab7d308b3c62edb8b808a47d3c0fc988562ff..66b0ca946694b432c52cbb1f9c8096b4e2f92452 100644 --- a/docs/reference/commandline/plugin_disable.md +++ b/docs/reference/commandline/plugin_disable.md @@ -36,8 +36,8 @@ and enabled: ```bash $ docker plugin ls -NAME TAG DESCRIPTION ENABLED -tiborvass/no-remove latest A test plugin for Docker true +ID NAME TAG DESCRIPTION ENABLED +69553ca1d123 tiborvass/no-remove latest A test plugin for Docker true ``` To disable the plugin, use the following command: @@ -49,8 +49,8 @@ tiborvass/no-remove $ docker plugin ls -NAME TAG DESCRIPTION ENABLED -tiborvass/no-remove latest A test plugin for Docker false +ID NAME TAG DESCRIPTION ENABLED +69553ca1d123 tiborvass/no-remove latest A test plugin for Docker false ``` ## Related information diff --git a/docs/reference/commandline/plugin_enable.md b/docs/reference/commandline/plugin_enable.md index a1f94df0512cd7d06e45e10e0cbaadb93fb431d0..36fb7640ac84614961ea64d552db134944b72d58 100644 --- a/docs/reference/commandline/plugin_enable.md +++ b/docs/reference/commandline/plugin_enable.md @@ -35,8 +35,8 @@ but disabled: ```bash $ docker plugin ls -NAME TAG DESCRIPTION ENABLED -tiborvass/no-remove latest A test plugin for Docker false +ID NAME TAG DESCRIPTION ENABLED +69553ca1d123 tiborvass/no-remove latest A test plugin for Docker false ``` To enable the plugin, use the following command: @@ -48,8 +48,8 @@ tiborvass/no-remove $ docker plugin ls -NAME TAG DESCRIPTION ENABLED -tiborvass/no-remove latest A test plugin for Docker true +ID NAME TAG DESCRIPTION ENABLED +69553ca1d123 tiborvass/no-remove latest A test plugin for Docker true ``` ## Related information diff --git a/docs/reference/commandline/plugin_install.md b/docs/reference/commandline/plugin_install.md index 3a48aef2092553cf5e6da5b0f92468bb14e45fd4..502eb441bf77288efb7fa4168009132b9ad7e19c 100644 --- a/docs/reference/commandline/plugin_install.md +++ b/docs/reference/commandline/plugin_install.md @@ -54,8 +54,8 @@ After the plugin is installed, it appears in the list of plugins: ```bash $ docker plugin ls -NAME TAG DESCRIPTION ENABLED -tiborvass/no-remove latest A test plugin for Docker true +ID NAME TAG DESCRIPTION ENABLED +69553ca1d123 tiborvass/no-remove latest A test plugin for Docker true ``` ## Related information diff --git a/docs/reference/commandline/plugin_push.md b/docs/reference/commandline/plugin_push.md index 07f2a66a377ad45887721005b990589d0c989242..2747f4c4a9cd920df356a95175d66d297bec64ad 100644 --- a/docs/reference/commandline/plugin_push.md +++ b/docs/reference/commandline/plugin_push.md @@ -32,9 +32,8 @@ The following example shows how to push a sample `user/plugin`. ```bash $ docker plugin ls -NAME TAG DESCRIPTION ENABLED -user/plugin latest A sample plugin for Docker false - +ID NAME TAG DESCRIPTION ENABLED +69553ca1d456 user/plugin latest A sample plugin for Docker false $ docker plugin push user/plugin ``` From eefb2220c0c38cd036e5dec227fc4a7b7cf467e9 Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Thu, 22 Dec 2016 11:49:47 -0500 Subject: [PATCH 11/26] Fix usage of boltdb in volume restore bolt k/v pairs are only valid for the life of a transaction. This means the memory that the k/v pair is referencing may be invalid if it is accessed outside of the transaction. This can potentially cause a panic. For reference: https://godoc.org/github.com/boltdb/bolt#hdr-Caveats To fix this issue, unmarshal the stored data into volume meta before closing the transaction. Signed-off-by: Brian Goff (cherry picked from commit 4876a9047ebfd66294d88482a1b4b24634a632e6) Signed-off-by: Victor Vieux --- volume/store/db.go | 28 +++++++++++++++++++--------- volume/store/restore.go | 36 ++++++++++++++---------------------- 2 files changed, 33 insertions(+), 31 deletions(-) diff --git a/volume/store/db.go b/volume/store/db.go index 0dc41509a4b4d2d7c0fff035ca1afb96a7f6fb7e..c5fd1643f53f9b4ba1779e026769e3661a3fe121 100644 --- a/volume/store/db.go +++ b/volume/store/db.go @@ -3,17 +3,13 @@ package store import ( "encoding/json" + "github.com/Sirupsen/logrus" "github.com/boltdb/bolt" "github.com/pkg/errors" ) var volumeBucketName = []byte("volumes") -type dbEntry struct { - Key []byte - Value []byte -} - type volumeMetadata struct { Name string Driver string @@ -67,12 +63,26 @@ func removeMeta(tx *bolt.Tx, name string) error { return errors.Wrap(b.Delete([]byte(name)), "error removing volume metadata") } -func listEntries(tx *bolt.Tx) []*dbEntry { - var entries []*dbEntry +// listMeta is used during restore to get the list of volume metadata +// from the on-disk database. +// Any errors that occur are only logged. +func listMeta(tx *bolt.Tx) []volumeMetadata { + var ls []volumeMetadata b := tx.Bucket(volumeBucketName) b.ForEach(func(k, v []byte) error { - entries = append(entries, &dbEntry{k, v}) + if len(v) == 0 { + // don't try to unmarshal an empty value + return nil + } + + var m volumeMetadata + if err := json.Unmarshal(v, &m); err != nil { + // Just log the error + logrus.Errorf("Error while reading volume metadata for volume %q: %v", string(k), err) + return nil + } + ls = append(ls, m) return nil }) - return entries + return ls } diff --git a/volume/store/restore.go b/volume/store/restore.go index e20740ba30a2adc3452ce8b395b09cbd1653bbd7..c0c5b519bcdd3c47bcd51ad64a4259c6737bd611 100644 --- a/volume/store/restore.go +++ b/volume/store/restore.go @@ -1,7 +1,6 @@ package store import ( - "encoding/json" "sync" "github.com/Sirupsen/logrus" @@ -17,45 +16,38 @@ import ( // It does not probe the available drivers to find anything that may have been added // out of band. func (s *VolumeStore) restore() { - var entries []*dbEntry + var ls []volumeMetadata s.db.View(func(tx *bolt.Tx) error { - entries = listEntries(tx) + ls = listMeta(tx) return nil }) - chRemove := make(chan []byte, len(entries)) + chRemove := make(chan *volumeMetadata, len(ls)) var wg sync.WaitGroup - for _, entry := range entries { + for _, meta := range ls { wg.Add(1) // this is potentially a very slow operation, so do it in a goroutine - go func(entry *dbEntry) { + go func(meta volumeMetadata) { defer wg.Done() - var meta volumeMetadata - if len(entry.Value) != 0 { - if err := json.Unmarshal(entry.Value, &meta); err != nil { - logrus.Errorf("Error while reading volume metadata for volume %q: %v", string(entry.Key), err) - // don't return here, we can try with `getVolume` below - } - } var v volume.Volume var err error if meta.Driver != "" { - v, err = lookupVolume(meta.Driver, string(entry.Key)) + v, err = lookupVolume(meta.Driver, meta.Name) if err != nil && err != errNoSuchVolume { - logrus.WithError(err).WithField("driver", meta.Driver).WithField("volume", string(entry.Key)).Warn("Error restoring volume") + logrus.WithError(err).WithField("driver", meta.Driver).WithField("volume", meta.Name).Warn("Error restoring volume") return } if v == nil { // doesn't exist in the driver, remove it from the db - chRemove <- entry.Key + chRemove <- &meta return } } else { - v, err = s.getVolume(string(entry.Key)) + v, err = s.getVolume(meta.Name) if err != nil { if err == errNoSuchVolume { - chRemove <- entry.Key + chRemove <- &meta } return } @@ -75,15 +67,15 @@ func (s *VolumeStore) restore() { s.labels[v.Name()] = meta.Labels s.names[v.Name()] = v s.globalLock.Unlock() - }(entry) + }(meta) } wg.Wait() close(chRemove) s.db.Update(func(tx *bolt.Tx) error { - for k := range chRemove { - if err := removeMeta(tx, string(k)); err != nil { - logrus.Warnf("Error removing stale entry from volume db: %v", err) + for meta := range chRemove { + if err := removeMeta(tx, meta.Name); err != nil { + logrus.WithField("volume", meta.Name).Warnf("Error removing stale entry from volume db: %v", err) } } return nil From 428ae707599aa343aa058cb54c10bc65b50d5856 Mon Sep 17 00:00:00 2001 From: Alexander Morozov Date: Mon, 19 Dec 2016 09:56:20 -0800 Subject: [PATCH 12/26] commit: do not change container labels on commit Fix #29547 Signed-off-by: Alexander Morozov (cherry picked from commit ca6c6f0765aeccdb2730d03c05bd965906df8cd4) Signed-off-by: Victor Vieux --- daemon/commit.go | 7 +++---- integration-cli/docker_cli_commit_test.go | 13 +++++++++++++ 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/daemon/commit.go b/daemon/commit.go index 333f7f2f938a70a4ec7c528bff92a7a2ecd56b7e..1e7bffb1dc9a7095bf136f8482e25f2539e52853 100644 --- a/daemon/commit.go +++ b/daemon/commit.go @@ -65,11 +65,10 @@ func merge(userConf, imageConf *containertypes.Config) error { if userConf.Labels == nil { userConf.Labels = map[string]string{} } - if imageConf.Labels != nil { - for l := range userConf.Labels { - imageConf.Labels[l] = userConf.Labels[l] + for l, v := range imageConf.Labels { + if _, ok := userConf.Labels[l]; !ok { + userConf.Labels[l] = v } - userConf.Labels = imageConf.Labels } if len(userConf.Entrypoint) == 0 { diff --git a/integration-cli/docker_cli_commit_test.go b/integration-cli/docker_cli_commit_test.go index 72ff89f3dc1ed59079c1ee7bf637c9b78fa1719c..8008ae171670d681310c7ea5e62a29af94c015ca 100644 --- a/integration-cli/docker_cli_commit_test.go +++ b/integration-cli/docker_cli_commit_test.go @@ -142,3 +142,16 @@ func (s *DockerSuite) TestCommitChange(c *check.C) { } } } + +func (s *DockerSuite) TestCommitChangeLabels(c *check.C) { + dockerCmd(c, "run", "--name", "test", "--label", "some=label", "busybox", "true") + + imageID, _ := dockerCmd(c, "commit", + "--change", "LABEL some=label2", + "test", "test-commit") + imageID = strings.TrimSpace(imageID) + + c.Assert(inspectField(c, imageID, "Config.Labels"), checker.Equals, "map[some:label2]") + // check that container labels didn't change + c.Assert(inspectField(c, "test", "Config.Labels"), checker.Equals, "map[some:label]") +} From 5903ead08e3331c8368161078af0a0a3200a0ae5 Mon Sep 17 00:00:00 2001 From: Harald Albers Date: Sat, 31 Dec 2016 09:23:27 -0800 Subject: [PATCH 13/26] Fix bash completion for `plugin enable|disable` `docker plugin enable` and `docker plugin disable` only accept one plugin. Signed-off-by: Harald Albers (cherry picked from commit 390effdd11a64f445d9932b6dbc04113b4687dea) Signed-off-by: Victor Vieux --- contrib/completion/bash/docker | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index 71a188b9c5e4c68755754b559ebfa590dfe02c35..16c69e6ffb08c7de4dae0a23afa853e9bde74883 100644 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -3226,7 +3226,10 @@ _docker_plugin_disable() { COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) ;; *) - __docker_complete_plugins_installed + local counter=$(__docker_pos_first_nonflag) + if [ $cword -eq $counter ]; then + __docker_complete_plugins_installed + fi ;; esac } @@ -3243,7 +3246,10 @@ _docker_plugin_enable() { COMPREPLY=( $( compgen -W "--help --timeout" -- "$cur" ) ) ;; *) - __docker_complete_plugins_installed + local counter=$(__docker_pos_first_nonflag '--timeout') + if [ $cword -eq $counter ]; then + __docker_complete_plugins_installed + fi ;; esac } From ea00b1417094cc8dc15d2bc2320fde5fda6cf258 Mon Sep 17 00:00:00 2001 From: Harald Albers Date: Sat, 31 Dec 2016 09:28:03 -0800 Subject: [PATCH 14/26] Add bash completion for `plugin disable --force` Signed-off-by: Harald Albers (cherry picked from commit e1403453f0a173464ef209e18e661320100a7b42) Signed-off-by: Victor Vieux --- contrib/completion/bash/docker | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker index 16c69e6ffb08c7de4dae0a23afa853e9bde74883..52956f2ca8c072502ad4902e3f2133306ce1efdb 100644 --- a/contrib/completion/bash/docker +++ b/contrib/completion/bash/docker @@ -3223,7 +3223,7 @@ _docker_plugin_create() { _docker_plugin_disable() { case "$cur" in -*) - COMPREPLY=( $( compgen -W "--help" -- "$cur" ) ) + COMPREPLY=( $( compgen -W "--force -f --help" -- "$cur" ) ) ;; *) local counter=$(__docker_pos_first_nonflag) From e2b04a78182695473aab8a61641ba9e5a2fe2007 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Fri, 23 Dec 2016 11:16:15 -0800 Subject: [PATCH 15/26] Fix image's `CMD` after `WORKDIR` in Dockerfile This fix tries to fix 29667 where image's `CMD` is modified after `WORKDIR` in Dockerfile. The value of `b.runConfig.Cmd` was modified in the processing of `WORKDIR`, in order to fix 28902. However, the same `b.runConfig.Cmd` is passed to `commit()`. This fix restored the `b.runConfig.Cmd` before `commit()` the image for `WORKDIR`. A test has been added. This fix fixes 29667. This fix is related to 28902, 28909, 28514. Signed-off-by: Yong Tang (cherry picked from commit 083602384737635af9a89b75a6ca6d27f7515dc6) Signed-off-by: Victor Vieux --- builder/dockerfile/dispatchers.go | 10 +++--- integration-cli/docker_cli_build_test.go | 40 ++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 5 deletions(-) diff --git a/builder/dockerfile/dispatchers.go b/builder/dockerfile/dispatchers.go index 4f3dcd8cd33b66cbf0b1ce1309b0e3adf9b6001e..42eebd050dd74e4a64bc34f43a0194ec8f392e09 100644 --- a/builder/dockerfile/dispatchers.go +++ b/builder/dockerfile/dispatchers.go @@ -297,17 +297,17 @@ func workdir(b *Builder, args []string, attributes map[string]bool, original str } b.runConfig.Image = b.image - cmd := b.runConfig.Cmd - b.runConfig.Cmd = strslice.StrSlice(append(getShell(b.runConfig), fmt.Sprintf("#(nop) WORKDIR %s", b.runConfig.WorkingDir))) - defer func(cmd strslice.StrSlice) { b.runConfig.Cmd = cmd }(cmd) - if hit, err := b.probeCache(); err != nil { return err } else if hit { return nil } - container, err := b.docker.ContainerCreate(types.ContainerCreateConfig{Config: b.runConfig}) + // Actually copy the struct + workdirConfig := *b.runConfig + workdirConfig.Cmd = strslice.StrSlice(append(getShell(b.runConfig), fmt.Sprintf("#(nop) WORKDIR %s", b.runConfig.WorkingDir))) + + container, err := b.docker.ContainerCreate(types.ContainerCreateConfig{Config: &workdirConfig}) if err != nil { return err } diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go index c05e545b016a0a732217801de457858d91737fac..4bb4e659871282fae64be250d26a91e6b46ad700 100644 --- a/integration-cli/docker_cli_build_test.go +++ b/integration-cli/docker_cli_build_test.go @@ -7357,3 +7357,43 @@ func (s *DockerSuite) TestBuildWindowsEnvCaseInsensitive(c *check.C) { c.Fatalf("Case insensitive environment variables on Windows failed. Got %s", res) } } + +// Test case for 29667 +func (s *DockerSuite) TestBuildWorkdirImageCmd(c *check.C) { + testRequires(c, DaemonIsLinux) + + image := "testworkdirimagecmd" + dockerfile := ` +FROM busybox +WORKDIR /foo/bar +` + out, err := buildImage(image, dockerfile, true) + c.Assert(err, checker.IsNil, check.Commentf("Output: %s", out)) + + out, _ = dockerCmd(c, "inspect", "--format", "{{ json .Config.Cmd }}", image) + c.Assert(strings.TrimSpace(out), checker.Equals, `["sh"]`) + + image = "testworkdirlabelimagecmd" + dockerfile = ` +FROM busybox +WORKDIR /foo/bar +LABEL a=b +` + out, err = buildImage(image, dockerfile, true) + c.Assert(err, checker.IsNil, check.Commentf("Output: %s", out)) + + out, _ = dockerCmd(c, "inspect", "--format", "{{ json .Config.Cmd }}", image) + c.Assert(strings.TrimSpace(out), checker.Equals, `["sh"]`) +} + +// Test case for 28902/28090 +func (s *DockerSuite) TestBuildWorkdirCmd(c *check.C) { + testRequires(c, DaemonIsLinux) + + dockerFile := ` + FROM golang:1.7-alpine + WORKDIR / + ` + _, err := buildImage("testbuildworkdircmd", dockerFile, false) + c.Assert(err, checker.IsNil) +} From 7cbc4cb7f2c1b84241647650ec0f81beee7e8448 Mon Sep 17 00:00:00 2001 From: Sebastiaan van Stijn Date: Fri, 16 Dec 2016 23:48:27 +0100 Subject: [PATCH 16/26] fix powershell dco check Signed-off-by: Sebastiaan van Stijn (cherry picked from commit 611a633ba4e11215a23d8b405a537346b10d9657) Signed-off-by: Victor Vieux --- hack/make.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hack/make.ps1 b/hack/make.ps1 index c085902ab65817368b54552ecaef5e552b624360..335619d1745d6a876ce78be3e7200e8e3505ff40 100644 --- a/hack/make.ps1 +++ b/hack/make.ps1 @@ -184,7 +184,7 @@ Function Validate-DCO($headCommit, $upstreamCommit) { $usernameRegex='[a-zA-Z0-9][a-zA-Z0-9-]+' $dcoPrefix="Signed-off-by:" - $dcoRegex="^(Docker-DCO-1.1-)?$dcoPrefix ([^<]+) <([^<>@]+@[^<>]+)>( \\(github: ($githubUsernameRegex)\\))?$" + $dcoRegex="^(Docker-DCO-1.1-)?$dcoPrefix ([^<]+) <([^<>@]+@[^<>]+)>( \\(github: ($usernameRegex)\\))?$" $counts = Invoke-Expression "git diff --numstat $upstreamCommit...$headCommit" if ($LASTEXITCODE -ne 0) { Throw "Failed git diff --numstat" } From a2dc349c74b31ab167d8502178ffee7caae956ae Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Thu, 29 Dec 2016 17:28:28 -0500 Subject: [PATCH 17/26] Add quoted string flag Value. Signed-off-by: Daniel Nephin (cherry picked from commit e4c1f0772923c3069ce14a82d445cd55af3382bc) Signed-off-by: Victor Vieux --- opts/quotedstring.go | 30 ++++++++++++++++++++++++++++++ opts/quotedstring_test.go | 24 ++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 opts/quotedstring.go create mode 100644 opts/quotedstring_test.go diff --git a/opts/quotedstring.go b/opts/quotedstring.go new file mode 100644 index 0000000000000000000000000000000000000000..8ddeee80856b41707f8e7afa547dfd63b00b90c8 --- /dev/null +++ b/opts/quotedstring.go @@ -0,0 +1,30 @@ +package opts + +// QuotedString is a string that may have extra quotes around the value. The +// quotes are stripped from the value. +type QuotedString string + +// Set sets a new value +func (s *QuotedString) Set(val string) error { + *s = QuotedString(trimQuotes(val)) + return nil +} + +// Type returns the type of the value +func (s *QuotedString) Type() string { + return "string" +} + +func (s *QuotedString) String() string { + return string(*s) +} + +func trimQuotes(value string) string { + lastIndex := len(value) - 1 + for _, char := range []byte{'\'', '"'} { + if value[0] == char && value[lastIndex] == char { + return value[1:lastIndex] + } + } + return value +} diff --git a/opts/quotedstring_test.go b/opts/quotedstring_test.go new file mode 100644 index 0000000000000000000000000000000000000000..a508b9d210ab1d91f1e94be5e21837403a85545c --- /dev/null +++ b/opts/quotedstring_test.go @@ -0,0 +1,24 @@ +package opts + +import ( + "github.com/docker/docker/pkg/testutil/assert" + "testing" +) + +func TestQuotedStringSetWithQuotes(t *testing.T) { + qs := QuotedString("") + assert.NilError(t, qs.Set("\"something\"")) + assert.Equal(t, qs.String(), "something") +} + +func TestQuotedStringSetWithMismatchedQuotes(t *testing.T) { + qs := QuotedString("") + assert.NilError(t, qs.Set("\"something'")) + assert.Equal(t, qs.String(), "\"something'") +} + +func TestQuotedStringSetWithNoQuotes(t *testing.T) { + qs := QuotedString("") + assert.NilError(t, qs.Set("something")) + assert.Equal(t, qs.String(), "something") +} From 045e9834a55c142889958126b9c0583a1d13d61f Mon Sep 17 00:00:00 2001 From: Daniel Nephin Date: Tue, 3 Jan 2017 15:58:41 -0500 Subject: [PATCH 18/26] Trim quotes from TLS flags. Signed-off-by: Daniel Nephin (cherry picked from commit abe32de6b46825300f612864e6b4c98606a5bb0e) Signed-off-by: Victor Vieux Signed-off-by: Vincent Demeester --- cli/flags/common.go | 12 +++++++---- cli/flags/common_test.go | 42 +++++++++++++++++++++++++++++++++++++++ opts/quotedstring.go | 13 +++++++++--- opts/quotedstring_test.go | 10 +++++++--- 4 files changed, 67 insertions(+), 10 deletions(-) create mode 100644 cli/flags/common_test.go diff --git a/cli/flags/common.go b/cli/flags/common.go index 690e8da4b899bc859b1827ad67ef2668d04e5e91..e2f9da0732672402746c5fca0c2cf5fc4ef18533 100644 --- a/cli/flags/common.go +++ b/cli/flags/common.go @@ -59,11 +59,15 @@ func (commonOpts *CommonOptions) InstallFlags(flags *pflag.FlagSet) { // TODO use flag flags.String("identity"}, "i", "", "Path to libtrust key file") - commonOpts.TLSOptions = &tlsconfig.Options{} + commonOpts.TLSOptions = &tlsconfig.Options{ + CAFile: filepath.Join(dockerCertPath, DefaultCaFile), + CertFile: filepath.Join(dockerCertPath, DefaultCertFile), + KeyFile: filepath.Join(dockerCertPath, DefaultKeyFile), + } tlsOptions := commonOpts.TLSOptions - flags.StringVar(&tlsOptions.CAFile, "tlscacert", filepath.Join(dockerCertPath, DefaultCaFile), "Trust certs signed only by this CA") - flags.StringVar(&tlsOptions.CertFile, "tlscert", filepath.Join(dockerCertPath, DefaultCertFile), "Path to TLS certificate file") - flags.StringVar(&tlsOptions.KeyFile, "tlskey", filepath.Join(dockerCertPath, DefaultKeyFile), "Path to TLS key file") + flags.Var(opts.NewQuotedString(&tlsOptions.CAFile), "tlscacert", "Trust certs signed only by this CA") + flags.Var(opts.NewQuotedString(&tlsOptions.CertFile), "tlscert", "Path to TLS certificate file") + flags.Var(opts.NewQuotedString(&tlsOptions.KeyFile), "tlskey", "Path to TLS key file") hostOpt := opts.NewNamedListOptsRef("hosts", &commonOpts.Hosts, opts.ValidateHost) flags.VarP(hostOpt, "host", "H", "Daemon socket(s) to connect to") diff --git a/cli/flags/common_test.go b/cli/flags/common_test.go new file mode 100644 index 0000000000000000000000000000000000000000..81eaa38f43b08c4dac369f4b0edc327cf8b06f19 --- /dev/null +++ b/cli/flags/common_test.go @@ -0,0 +1,42 @@ +package flags + +import ( + "path/filepath" + "testing" + + "github.com/docker/docker/cliconfig" + "github.com/docker/docker/pkg/testutil/assert" + "github.com/spf13/pflag" +) + +func TestCommonOptionsInstallFlags(t *testing.T) { + flags := pflag.NewFlagSet("testing", pflag.ContinueOnError) + opts := NewCommonOptions() + opts.InstallFlags(flags) + + err := flags.Parse([]string{ + "--tlscacert=\"/foo/cafile\"", + "--tlscert=\"/foo/cert\"", + "--tlskey=\"/foo/key\"", + }) + assert.NilError(t, err) + assert.Equal(t, opts.TLSOptions.CAFile, "/foo/cafile") + assert.Equal(t, opts.TLSOptions.CertFile, "/foo/cert") + assert.Equal(t, opts.TLSOptions.KeyFile, "/foo/key") +} + +func defaultPath(filename string) string { + return filepath.Join(cliconfig.ConfigDir(), filename) +} + +func TestCommonOptionsInstallFlagsWithDefaults(t *testing.T) { + flags := pflag.NewFlagSet("testing", pflag.ContinueOnError) + opts := NewCommonOptions() + opts.InstallFlags(flags) + + err := flags.Parse([]string{}) + assert.NilError(t, err) + assert.Equal(t, opts.TLSOptions.CAFile, defaultPath("ca.pem")) + assert.Equal(t, opts.TLSOptions.CertFile, defaultPath("cert.pem")) + assert.Equal(t, opts.TLSOptions.KeyFile, defaultPath("key.pem")) +} diff --git a/opts/quotedstring.go b/opts/quotedstring.go index 8ddeee80856b41707f8e7afa547dfd63b00b90c8..fb1e5374bc3a46df7f7c7655593f499a7a8b0597 100644 --- a/opts/quotedstring.go +++ b/opts/quotedstring.go @@ -2,11 +2,13 @@ package opts // QuotedString is a string that may have extra quotes around the value. The // quotes are stripped from the value. -type QuotedString string +type QuotedString struct { + value *string +} // Set sets a new value func (s *QuotedString) Set(val string) error { - *s = QuotedString(trimQuotes(val)) + *s.value = trimQuotes(val) return nil } @@ -16,7 +18,7 @@ func (s *QuotedString) Type() string { } func (s *QuotedString) String() string { - return string(*s) + return string(*s.value) } func trimQuotes(value string) string { @@ -28,3 +30,8 @@ func trimQuotes(value string) string { } return value } + +// NewQuotedString returns a new quoted string option +func NewQuotedString(value *string) *QuotedString { + return &QuotedString{value: value} +} diff --git a/opts/quotedstring_test.go b/opts/quotedstring_test.go index a508b9d210ab1d91f1e94be5e21837403a85545c..0ebf04bbe044ba5906b41387e1fccc4a5c048e81 100644 --- a/opts/quotedstring_test.go +++ b/opts/quotedstring_test.go @@ -6,19 +6,23 @@ import ( ) func TestQuotedStringSetWithQuotes(t *testing.T) { - qs := QuotedString("") + value := "" + qs := NewQuotedString(&value) assert.NilError(t, qs.Set("\"something\"")) assert.Equal(t, qs.String(), "something") + assert.Equal(t, value, "something") } func TestQuotedStringSetWithMismatchedQuotes(t *testing.T) { - qs := QuotedString("") + value := "" + qs := NewQuotedString(&value) assert.NilError(t, qs.Set("\"something'")) assert.Equal(t, qs.String(), "\"something'") } func TestQuotedStringSetWithNoQuotes(t *testing.T) { - qs := QuotedString("") + value := "" + qs := NewQuotedString(&value) assert.NilError(t, qs.Set("something")) assert.Equal(t, qs.String(), "something") } From ff7934faf29a33e254a066b4a535d56627ea8a76 Mon Sep 17 00:00:00 2001 From: Harald Albers Date: Sat, 31 Dec 2016 09:55:04 -0800 Subject: [PATCH 19/26] Fix usage message of `plugin inspect` Signed-off-by: Harald Albers (cherry picked from commit 1b58d0bc51e2bfc9e268dab762d1d891c18890c9) Signed-off-by: Victor Vieux --- cli/command/plugin/inspect.go | 2 +- docs/reference/commandline/plugin_inspect.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/command/plugin/inspect.go b/cli/command/plugin/inspect.go index 46ec7b229b7b6ae2e2ea28d87929327c39cc9257..c2c7a0d6bc0daae7b7ceeab2e9759b4695615ed4 100644 --- a/cli/command/plugin/inspect.go +++ b/cli/command/plugin/inspect.go @@ -17,7 +17,7 @@ func newInspectCommand(dockerCli *command.DockerCli) *cobra.Command { var opts inspectOptions cmd := &cobra.Command{ - Use: "inspect [OPTIONS] PLUGIN|ID [PLUGIN|ID...]", + Use: "inspect [OPTIONS] PLUGIN [PLUGIN...]", Short: "Display detailed information on one or more plugins", Args: cli.RequiresMinArgs(1), RunE: func(cmd *cobra.Command, args []string) error { diff --git a/docs/reference/commandline/plugin_inspect.md b/docs/reference/commandline/plugin_inspect.md index ded6bd2ee23fe5321399a81a8b84954407d92a6f..01e231bf06762ab6c9820e9f0678b717c7a8c0f9 100644 --- a/docs/reference/commandline/plugin_inspect.md +++ b/docs/reference/commandline/plugin_inspect.md @@ -16,7 +16,7 @@ keywords: "plugin, inspect" # plugin inspect ```markdown -Usage: docker plugin inspect [OPTIONS] PLUGIN|ID [PLUGIN|ID...] +Usage: docker plugin inspect [OPTIONS] PLUGIN [PLUGIN...] Display detailed information on one or more plugins From def75b2c2c16ea809b5626930a62080897cbefed Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Thu, 15 Dec 2016 13:07:27 -0500 Subject: [PATCH 20/26] Fixes a race condition in client events monitoring In cases where there is high latency (ie, not-local network) `waitExitOrRemoved` was not receiving events for short-lived containers. This caused the client to hang while waiting for a notification that the container has stopped. This happens because `client.Events()` returns immediately and spins a goroutine up to process events. The problem here is it returns before the request to the events endpoint is even made. Even without high-latency issues, there is no guarantee that the goroutine is even scheduled by the time the function returns. Signed-off-by: Brian Goff (cherry picked from commit 47585996bf72bcfde9ef058522059bef352e83e0) Signed-off-by: Victor Vieux Signed-off-by: Vincent Demeester --- client/events.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/client/events.go b/client/events.go index c154f7dcf9434b931e128458ea901c934afabe06..af47aefa74c9b4863249844ad24f27920124b21b 100644 --- a/client/events.go +++ b/client/events.go @@ -22,17 +22,20 @@ func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-c messages := make(chan events.Message) errs := make(chan error, 1) + started := make(chan struct{}) go func() { defer close(errs) query, err := buildEventsQueryParams(cli.version, options) if err != nil { + close(started) errs <- err return } resp, err := cli.get(ctx, "/events", query, nil) if err != nil { + close(started) errs <- err return } @@ -40,6 +43,7 @@ func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-c decoder := json.NewDecoder(resp.body) + close(started) for { select { case <-ctx.Done(): @@ -61,6 +65,7 @@ func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-c } } }() + <-started return messages, errs } From d01138c16238457b02afd2166e72bc354d465dbd Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Mon, 26 Dec 2016 13:47:43 -0800 Subject: [PATCH 21/26] Remove `docker stack ps -a` to match removal of `docker service/node ps -a` In #28507 and #28885, `docker service/node ps -a` has been removed so that information about slots are show up even without `-a` flag. The output of `docker stack ps` reused the same output as `docker service/node ps`. However, the `-a` was still there. It might make sense to remove `docker stack ps -a` as well to bring consistency with `docker service/node ps`. This fix is related to #28507, #28885, and #25983. Signed-off-by: Yong Tang (cherry picked from commit 9155e14e77a8235791a6de752f6f43e83308e23d) Signed-off-by: Victor Vieux Signed-off-by: Vincent Demeester --- cli/command/stack/ps.go | 7 ------- docs/reference/commandline/stack_ps.md | 8 ++++---- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/cli/command/stack/ps.go b/cli/command/stack/ps.go index 7a5e069cbeb955386ddbfaea6abf4407244108bb..73ceb3312807c0c9a3de45d8dbdca337a33440c9 100644 --- a/cli/command/stack/ps.go +++ b/cli/command/stack/ps.go @@ -6,7 +6,6 @@ import ( "golang.org/x/net/context" "github.com/docker/docker/api/types" - "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" "github.com/docker/docker/cli/command/idresolver" @@ -16,7 +15,6 @@ import ( ) type psOptions struct { - all bool filter opts.FilterOpt noTrunc bool namespace string @@ -36,7 +34,6 @@ func newPsCommand(dockerCli *command.DockerCli) *cobra.Command { }, } flags := cmd.Flags() - flags.BoolVarP(&opts.all, "all", "a", false, "Display all tasks") flags.BoolVar(&opts.noTrunc, "no-trunc", false, "Do not truncate output") flags.BoolVar(&opts.noResolve, "no-resolve", false, "Do not map IDs to Names") flags.VarP(&opts.filter, "filter", "f", "Filter output based on conditions provided") @@ -51,10 +48,6 @@ func runPS(dockerCli *command.DockerCli, opts psOptions) error { filter := opts.filter.Value() filter.Add("label", labelNamespace+"="+opts.namespace) - if !opts.all && !filter.Include("desired-state") { - filter.Add("desired-state", string(swarm.TaskStateRunning)) - filter.Add("desired-state", string(swarm.TaskStateAccepted)) - } tasks, err := client.TaskList(ctx, types.TaskListOptions{Filters: filter}) if err != nil { diff --git a/docs/reference/commandline/stack_ps.md b/docs/reference/commandline/stack_ps.md index 75223e07d9a908653a0e27004321250c5025c18b..01dc63b7d9142bf181e16cf10c0e6ef470c7622c 100644 --- a/docs/reference/commandline/stack_ps.md +++ b/docs/reference/commandline/stack_ps.md @@ -21,10 +21,10 @@ Usage: docker stack ps [OPTIONS] STACK List the tasks in the stack Options: - -a, --all Display all tasks - -f, --filter value Filter output based on conditions provided - --no-resolve Do not map IDs to Names - --no-trunc Do not truncate output + -f, --filter filter Filter output based on conditions provided + --help Print usage + --no-resolve Do not map IDs to Names + --no-trunc Do not truncate output ``` Lists the tasks that are running as part of the specified stack. This From aa5ac38f41ae6fba5ce36f9c3dcc499d97badf0b Mon Sep 17 00:00:00 2001 From: Yanqiang Miao Date: Fri, 30 Dec 2016 11:58:39 +0800 Subject: [PATCH 22/26] Optimization a error description Signed-off-by: Yanqiang Miao (cherry picked from commit 6c021893aa12088c0ad5b18111cfa80d6008a78f) Signed-off-by: Victor Vieux Signed-off-by: Vincent Demeester --- plugin/store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugin/store.go b/plugin/store.go index bb57e8066548c04b23263444b24f8a22c612ffd0..5f95defdde33a5c503ac369f0cf32150c59ba22e 100644 --- a/plugin/store.go +++ b/plugin/store.go @@ -58,7 +58,7 @@ func (ps *Store) GetV2Plugin(refOrID string) (*v2.Plugin, error) { func (ps *Store) validateName(name string) error { for _, p := range ps.plugins { if p.Name() == name { - return errors.Errorf("%v already exists", name) + return errors.Errorf("plugin %q already exists", name) } } return nil From 68418871329441cc1267fe4e8178f0419ab28c50 Mon Sep 17 00:00:00 2001 From: Yong Tang Date: Sat, 19 Nov 2016 17:41:11 -0800 Subject: [PATCH 23/26] Add `--file` flag for `docker secret create` command This fix tries to address the issue raised in 28581 and 28927 where it is not possible to create a secret from a file (only through STDIN). This fix add a flag `--file` to `docker secret create` so that it is possible to create a secret from a file with: ``` docker secret create --file secret.in secret.name ``` or ``` echo TEST | docker secret create --file - secret.name ``` Related docs has been updated. An integration test has been added to cover the changes. This fix fixes 28581. This fix is related to 28927. Signed-off-by: Yong Tang (cherry picked from commit c6f0b7f448fac4d037d00f944a7908c60c04dff2) Signed-off-by: Victor Vieux Signed-off-by: Vincent Demeester --- cli/command/secret/create.go | 25 +++++++++++--- docs/reference/commandline/secret_create.md | 27 +++++++++++---- .../docker_cli_secret_create_test.go | 34 +++++++++++++++++++ 3 files changed, 75 insertions(+), 11 deletions(-) diff --git a/cli/command/secret/create.go b/cli/command/secret/create.go index 381a931415e42a8cfb4b87f0cb4c89514527d670..5d4dc34d12f7f46f573080c418cedc2043485ec9 100644 --- a/cli/command/secret/create.go +++ b/cli/command/secret/create.go @@ -2,13 +2,14 @@ package secret import ( "fmt" + "io" "io/ioutil" - "os" "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/cli" "github.com/docker/docker/cli/command" "github.com/docker/docker/opts" + "github.com/docker/docker/pkg/system" runconfigopts "github.com/docker/docker/runconfig/opts" "github.com/spf13/cobra" "golang.org/x/net/context" @@ -16,6 +17,7 @@ import ( type createOptions struct { name string + file string labels opts.ListOpts } @@ -26,7 +28,7 @@ func newSecretCreateCommand(dockerCli *command.DockerCli) *cobra.Command { cmd := &cobra.Command{ Use: "create [OPTIONS] SECRET", - Short: "Create a secret using stdin as content", + Short: "Create a secret from a file or STDIN as content", Args: cli.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { createOpts.name = args[0] @@ -35,6 +37,7 @@ func newSecretCreateCommand(dockerCli *command.DockerCli) *cobra.Command { } flags := cmd.Flags() flags.VarP(&createOpts.labels, "label", "l", "Secret labels") + flags.StringVarP(&createOpts.file, "file", "f", "", "Read from a file or STDIN ('-')") return cmd } @@ -43,9 +46,23 @@ func runSecretCreate(dockerCli *command.DockerCli, options createOptions) error client := dockerCli.Client() ctx := context.Background() - secretData, err := ioutil.ReadAll(os.Stdin) + if options.file == "" { + return fmt.Errorf("Please specify either a file name or STDIN ('-') with --file") + } + + var in io.Reader = dockerCli.In() + if options.file != "-" { + file, err := system.OpenSequential(options.file) + if err != nil { + return err + } + in = file + defer file.Close() + } + + secretData, err := ioutil.ReadAll(in) if err != nil { - return fmt.Errorf("Error reading content from STDIN: %v", err) + return fmt.Errorf("Error reading content from %q: %v", options.file, err) } spec := swarm.SecretSpec{ diff --git a/docs/reference/commandline/secret_create.md b/docs/reference/commandline/secret_create.md index 952ad26b2c953ee7637f3d588b9bbd793c082a57..ef2641a91c324cf725854ad2c60bb2aff521fd4b 100644 --- a/docs/reference/commandline/secret_create.md +++ b/docs/reference/commandline/secret_create.md @@ -16,15 +16,17 @@ keywords: ["secret, create"] # secret create ```Markdown -Usage: docker secret create [OPTIONS] SECRET +Usage: docker secret create [OPTIONS] SECRET + +Create a secret from a file or STDIN as content -Create a secret using stdin as content Options: - --help Print usage - -l, --label list Secret labels (default []) + -f, --file string Read from a file or STDIN ('-') + --help Print usage + -l, --label list Secret labels (default []) ``` -Creates a secret using standard input for the secret content. You must run this +Creates a secret using standard input or from a file for the secret content. You must run this command on a manager node. ## Examples @@ -32,7 +34,18 @@ command on a manager node. ### Create a secret ```bash -$ cat secret.json | docker secret create secret.json +$ cat secret.json | docker secret create -f - secret.json +mhv17xfe3gh6xc4rij5orpfds + +$ docker secret ls +ID NAME CREATED UPDATED SIZE +mhv17xfe3gh6xc4rij5orpfds secret.json 2016-10-27 23:25:43.909181089 +0000 UTC 2016-10-27 23:25:43.909181089 +0000 UTC 1679 +``` + +### Create a secret with a file + +```bash +$ docker secret create --file secret.in secret.json mhv17xfe3gh6xc4rij5orpfds $ docker secret ls @@ -43,7 +56,7 @@ mhv17xfe3gh6xc4rij5orpfds secret.json 2016-10-27 23:25:43.90918108 ### Create a secret with labels ```bash -$ cat secret.json | docker secret create secret.json --label env=dev --label rev=20161102 +$ cat secret.json | docker secret create secret.json -f - --label env=dev --label rev=20161102 jtn7g6aukl5ky7nr9gvwafoxh $ docker secret inspect secret.json diff --git a/integration-cli/docker_cli_secret_create_test.go b/integration-cli/docker_cli_secret_create_test.go index 9c45f8a0ae0d7c9da5bcf7c25dfef1b27661a9f5..5097f1e7071d72d16304c918d6d19183b4ee0d85 100644 --- a/integration-cli/docker_cli_secret_create_test.go +++ b/integration-cli/docker_cli_secret_create_test.go @@ -3,6 +3,10 @@ package main import ( + "io/ioutil" + "os" + "strings" + "github.com/docker/docker/api/types/swarm" "github.com/docker/docker/pkg/integration/checker" "github.com/go-check/check" @@ -104,3 +108,33 @@ func (s *DockerSwarmSuite) TestSecretCreateResolve(c *check.C) { c.Assert(out, checker.Not(checker.Contains), id) c.Assert(out, checker.Not(checker.Contains), fake) } + +func (s *DockerSwarmSuite) TestSecretCreateWithFile(c *check.C) { + d := s.AddDaemon(c, true, true) + + testFile, err := ioutil.TempFile("", "secretCreateTest") + c.Assert(err, checker.IsNil, check.Commentf("failed to create temporary file")) + defer os.Remove(testFile.Name()) + + testData := "TESTINGDATA" + _, err = testFile.Write([]byte(testData)) + c.Assert(err, checker.IsNil, check.Commentf("failed to write to temporary file")) + + testName := "test_secret" + out, err := d.Cmd("secret", "create", "--file", testFile.Name(), testName) + c.Assert(err, checker.IsNil) + c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "", check.Commentf(out)) + + id := strings.TrimSpace(out) + secret := d.getSecret(c, id) + c.Assert(secret.Spec.Name, checker.Equals, testName) + + testName = "test_secret_2" + out, err = d.Cmd("secret", "create", testName, "-f", testFile.Name()) + c.Assert(err, checker.IsNil) + c.Assert(strings.TrimSpace(out), checker.Not(checker.Equals), "", check.Commentf(out)) + + id = strings.TrimSpace(out) + secret = d.getSecret(c, id) + c.Assert(secret.Spec.Name, checker.Equals, testName) +} From 84f25c7cb821fbef70a87c432ce474b7b75be4ba Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Tue, 27 Dec 2016 11:07:22 -0500 Subject: [PATCH 24/26] Fix race/deadlock in v1 plugin handlers When a plugin is activated, and then `plugins.Handle` is called to register a new handler for a given plugin type, a deadlock occurs when for anything which calls `waitActive`, including `Get`, and `GetAll`. This happens because `Handle()` is setting `activated` to `false` to ensure that plugin handlers are run on next activation. Maybe these handlers should be called immediately for any plugins which are already registered... but to preserve the existing behavior while fixing the deadlock, track if handlers have been run on plugins and reset when a new handler is registered. The simplest way to reproduce the deadlock with Docker is to add a `-v /foo` to the test container created for the external graphdriver tests. Signed-off-by: Brian Goff (cherry picked from commit 2938dce794be7559ba73b4e9630015020a7fa937) Signed-off-by: Victor Vieux Signed-off-by: Vincent Demeester --- ...cker_cli_external_graphdriver_unix_test.go | 4 + pkg/plugins/plugin_test.go | 37 ++++++++++ pkg/plugins/plugins.go | 74 +++++++++++++------ 3 files changed, 92 insertions(+), 23 deletions(-) create mode 100644 pkg/plugins/plugin_test.go diff --git a/integration-cli/docker_cli_external_graphdriver_unix_test.go b/integration-cli/docker_cli_external_graphdriver_unix_test.go index 65814d19da71ba9b4416dd8b46454e4049b16b22..a794ca742dab1c61e69d45f1d726348a9cd39d9d 100644 --- a/integration-cli/docker_cli_external_graphdriver_unix_test.go +++ b/integration-cli/docker_cli_external_graphdriver_unix_test.go @@ -54,6 +54,10 @@ func (s *DockerExternalGraphdriverSuite) SetUpTest(c *check.C) { s.d = NewDaemon(c) } +func (s *DockerExternalGraphdriverSuite) OnTimeout(c *check.C) { + s.d.DumpStackAndQuit() +} + func (s *DockerExternalGraphdriverSuite) TearDownTest(c *check.C) { s.d.Stop() s.ds.TearDownTest(c) diff --git a/pkg/plugins/plugin_test.go b/pkg/plugins/plugin_test.go new file mode 100644 index 0000000000000000000000000000000000000000..ac810565f7b8fa334539508d667408b8d4e4e615 --- /dev/null +++ b/pkg/plugins/plugin_test.go @@ -0,0 +1,37 @@ +package plugins + +import ( + "path/filepath" + "runtime" + "sync" + "testing" + "time" +) + +// regression test for deadlock in handlers +func TestPluginAddHandler(t *testing.T) { + // make a plugin which is pre-activated + p := &Plugin{activateWait: sync.NewCond(&sync.Mutex{})} + p.Manifest = &Manifest{Implements: []string{"bananas"}} + storage.plugins["qwerty"] = p + + testActive(t, p) + Handle("bananas", func(_ string, _ *Client) {}) + testActive(t, p) +} + +func testActive(t *testing.T, p *Plugin) { + done := make(chan struct{}) + go func() { + p.waitActive() + close(done) + }() + + select { + case <-time.After(100 * time.Millisecond): + _, f, l, _ := runtime.Caller(1) + t.Fatalf("%s:%d: deadlock in waitActive", filepath.Base(f), l) + case <-done: + } + +} diff --git a/pkg/plugins/plugins.go b/pkg/plugins/plugins.go index acfb20999256b19235711726a69aa32afbaeaca1..125e6c7d66848065015cc5f8d314256ce35ae141 100644 --- a/pkg/plugins/plugins.go +++ b/pkg/plugins/plugins.go @@ -70,12 +70,12 @@ type Plugin struct { // Manifest of the plugin (see above) Manifest *Manifest `json:"-"` - // error produced by activation - activateErr error - // specifies if the activation sequence is completed (not if it is successful or not) - activated bool // wait for activation to finish activateWait *sync.Cond + // error produced by activation + activateErr error + // keeps track of callback handlers run against this plugin + handlersRun bool } // BasePath returns the path to which all paths returned by the plugin are relative to. @@ -112,19 +112,51 @@ func NewLocalPlugin(name, addr string) *Plugin { func (p *Plugin) activate() error { p.activateWait.L.Lock() - if p.activated { + + if p.activated() { + p.runHandlers() p.activateWait.L.Unlock() return p.activateErr } p.activateErr = p.activateWithLock() - p.activated = true + p.runHandlers() p.activateWait.L.Unlock() p.activateWait.Broadcast() return p.activateErr } +// runHandlers runs the registered handlers for the implemented plugin types +// This should only be run after activation, and while the activation lock is held. +func (p *Plugin) runHandlers() { + if !p.activated() { + return + } + + handlers.RLock() + if !p.handlersRun { + for _, iface := range p.Manifest.Implements { + hdlrs, handled := handlers.extpointHandlers[iface] + if !handled { + continue + } + for _, handler := range hdlrs { + handler(p.name, p.client) + } + } + p.handlersRun = true + } + handlers.RUnlock() + +} + +// activated returns if the plugin has already been activated. +// This should only be called with the activation lock held +func (p *Plugin) activated() bool { + return p.Manifest != nil +} + func (p *Plugin) activateWithLock() error { c, err := NewClient(p.Addr, p.TLSConfig) if err != nil { @@ -138,24 +170,12 @@ func (p *Plugin) activateWithLock() error { } p.Manifest = m - - handlers.RLock() - for _, iface := range m.Implements { - hdlrs, handled := handlers.extpointHandlers[iface] - if !handled { - continue - } - for _, handler := range hdlrs { - handler(p.name, p.client) - } - } - handlers.RUnlock() return nil } func (p *Plugin) waitActive() error { p.activateWait.L.Lock() - for !p.activated { + for !p.activated() { p.activateWait.Wait() } p.activateWait.L.Unlock() @@ -163,7 +183,7 @@ func (p *Plugin) waitActive() error { } func (p *Plugin) implements(kind string) bool { - if err := p.waitActive(); err != nil { + if p.Manifest == nil { return false } for _, driver := range p.Manifest.Implements { @@ -232,7 +252,7 @@ func Get(name, imp string) (*Plugin, error) { if err != nil { return nil, err } - if pl.implements(imp) { + if err := pl.waitActive(); err == nil && pl.implements(imp) { logrus.Debugf("%s implements: %s", name, imp) return pl, nil } @@ -249,9 +269,17 @@ func Handle(iface string, fn func(string, *Client)) { hdlrs = append(hdlrs, fn) handlers.extpointHandlers[iface] = hdlrs + + storage.Lock() for _, p := range storage.plugins { - p.activated = false + p.activateWait.L.Lock() + if p.activated() && p.implements(iface) { + p.handlersRun = false + } + p.activateWait.L.Unlock() } + storage.Unlock() + handlers.Unlock() } @@ -292,7 +320,7 @@ func GetAll(imp string) ([]*Plugin, error) { logrus.Error(pl.err) continue } - if pl.pl.implements(imp) { + if err := pl.pl.waitActive(); err == nil && pl.pl.implements(imp) { out = append(out, pl.pl) } } From 4e9dd0e51c684f188028b94af13e7ab6810703d9 Mon Sep 17 00:00:00 2001 From: Victor Vieux Date: Wed, 14 Dec 2016 00:35:34 -0800 Subject: [PATCH 25/26] replace no-remove by sample-volume-plugin in docs Signed-off-by: Victor Vieux (cherry picked from commit bcead9282e17f51b01c4edfa59221546f02aaa33) Signed-off-by: Victor Vieux Signed-off-by: Vincent Demeester --- api/swagger.yaml | 126 +++++-------------- docs/extend/config.md | 85 ++++++------- docs/reference/commandline/events.md | 4 +- docs/reference/commandline/plugin_disable.md | 14 +-- docs/reference/commandline/plugin_enable.md | 14 +-- docs/reference/commandline/plugin_inspect.md | 8 +- docs/reference/commandline/plugin_install.md | 14 +-- docs/reference/commandline/plugin_ls.md | 4 +- docs/reference/commandline/plugin_rm.md | 10 +- docs/reference/commandline/plugin_set.md | 8 +- man/docker-events.1.md | 4 +- 11 files changed, 109 insertions(+), 182 deletions(-) diff --git a/api/swagger.yaml b/api/swagger.yaml index 871fe0c2258d085a425f667b40b47d44ce806003..68a5420477fde12bd13aa414b8ac40f586514019 100644 --- a/api/swagger.yaml +++ b/api/swagger.yaml @@ -1497,74 +1497,39 @@ definitions: type: "string" example: Id: "5724e2c8652da337ab2eedd19fc6fc0ec908e4bd907c7421bf6a8dfc70c4c078" - Name: "tiborvass/no-remove" + Name: "tiborvass/sample-volume-plugin" Tag: "latest" Active: true - Config: - Mounts: - - Name: "" - Description: "" - Settable: null - Source: "/data" - Destination: "/data" - Type: "bind" - Options: - - "shared" - - "rbind" - - Name: "" - Description: "" - Settable: null - Source: null - Destination: "/foobar" - Type: "tmpfs" - Options: null + Settings: Env: - - "DEBUG=1" + - "DEBUG=0" Args: null Devices: null - Manifest: - ManifestVersion: "v0" - Description: "A test plugin for Docker" + Config: + Description: "A sample volume plugin for Docker" Documentation: "https://docs.docker.com/engine/extend/plugins/" Interface: Types: - "docker.volumedriver/1.0" Socket: "plugins.sock" Entrypoint: - - "plugin-no-remove" + - "/usr/bin/sample-volume-plugin" - "/data" WorkDir: "" User: {} Network: - Type: "host" - Capabilities: null - Mounts: - - Name: "" - Description: "" - Settable: null - Source: "/data" - Destination: "/data" - Type: "bind" - Options: - - "shared" - - "rbind" - - Name: "" - Description: "" - Settable: null - Source: null - Destination: "/foobar" - Type: "tmpfs" - Options: null - Devices: - - Name: "device" - Description: "a host device to mount" - Settable: null - Path: "/dev/cpu_dma_latency" + Type: "" + Linux: + Capabilities: null + DeviceCreation: false + Devices: null + Mounts: null + PropagatedMount: "/data" Env: - Name: "DEBUG" Description: "If set, prints debug messages" Settable: null - Value: "1" + Value: "0" Args: Name: "args" Description: "command line arguments" @@ -6366,74 +6331,39 @@ paths: $ref: "#/definitions/Plugin" example: - Id: "5724e2c8652da337ab2eedd19fc6fc0ec908e4bd907c7421bf6a8dfc70c4c078" - Name: "tiborvass/no-remove" + Name: "tiborvass/sample-volume-plugin" Tag: "latest" Active: true - Config: - Mounts: - - Name: "" - Description: "" - Settable: null - Source: "/data" - Destination: "/data" - Type: "bind" - Options: - - "shared" - - "rbind" - - Name: "" - Description: "" - Settable: null - Source: null - Destination: "/foobar" - Type: "tmpfs" - Options: null + Settings: Env: - - "DEBUG=1" + - "DEBUG=0" Args: null Devices: null - Manifest: - ManifestVersion: "v0" - Description: "A test plugin for Docker" + Config: + Description: "A sample volume plugin for Docker" Documentation: "https://docs.docker.com/engine/extend/plugins/" Interface: Types: - "docker.volumedriver/1.0" Socket: "plugins.sock" Entrypoint: - - "plugin-no-remove" + - "/usr/bin/sample-volume-plugin" - "/data" WorkDir: "" User: {} Network: - Type: "host" - Capabilities: null - Mounts: - - Name: "" - Description: "" - Settable: null - Source: "/data" - Destination: "/data" - Type: "bind" - Options: - - "shared" - - "rbind" - - Name: "" - Description: "" - Settable: null - Source: null - Destination: "/foobar" - Type: "tmpfs" - Options: null - Devices: - - Name: "device" - Description: "a host device to mount" - Settable: null - Path: "/dev/cpu_dma_latency" + Type: "" + Linux: + Capabilities: null + DeviceCreation: false + Devices: null + Mounts: null + PropagatedMount: "/data" Env: - Name: "DEBUG" Description: "If set, prints debug messages" Settable: null - Value: "1" + Value: "0" Args: Name: "args" Description: "command line arguments" diff --git a/docs/extend/config.md b/docs/extend/config.md index eca33803c2aff6663d446bfa01ce79492e9ec721..538dc6ac4753b1a779cefcf472116902d8a74524 100644 --- a/docs/extend/config.md +++ b/docs/extend/config.md @@ -171,52 +171,49 @@ Config provides the base accessible fields for working with V0 plugin format ## Example Config -*Example showing the 'tiborvass/no-remove' plugin config.* +*Example showing the 'tiborvass/sample-volume-plugin' plugin config.* ```json { - "description": "A test plugin for Docker", - "documentation": "https://docs.docker.com/engine/extend/plugins/", - "entrypoint": ["plugin-no-remove", "/data"], - "interface": { - "types": ["docker.volumedriver/1.0"], - "socket": "plugins.sock" - }, - "network": { - "type": "host" - }, - "mounts": [ - { - "source": "/data", - "destination": "/data", - "type": "bind", - "options": ["shared", "rbind"] - }, - { - "destination": "/foobar", - "type": "tmpfs" - } - ], - "args": { - "name": "args", - "description": "command line arguments", - "value": [] - }, - "env": [ - { - "name": "DEBUG", - "description": "If set, prints debug messages", - "value": "1" - } - ], - "linux": { - "devices": [ - { - "name": "device", - "description": "a host device to mount", - "path": "/dev/cpu_dma_latency" - } - ] - } + "Args": { + "Description": "", + "Name": "", + "Settable": null, + "Value": null + }, + "Description": "A sample volume plugin for Docker", + "Documentation": "https://docs.docker.com/engine/extend/plugins/", + "Entrypoint": [ + "/usr/bin/sample-volume-plugin", + "/data" + ], + "Env": [ + { + "Description": "", + "Name": "DEBUG", + "Settable": [ + "value" + ], + "Value": "0" + } + ], + "Interface": { + "Socket": "plugin.sock", + "Types": [ + "docker.volumedriver/1.0" + ] + }, + "Linux": { + "Capabilities": null, + "DeviceCreation": false, + "Devices": null + }, + "Mounts": null, + "Network": { + "Type": "" + }, + "PropagatedMount": "/data", + "User": {}, + "Workdir": "" } ``` diff --git a/docs/reference/commandline/events.md b/docs/reference/commandline/events.md index 24af2ab48265fddf95a2873bf0b2bbc6e7d86b7d..64c1536eaab9a89a270dcf145d47532a5583da12 100644 --- a/docs/reference/commandline/events.md +++ b/docs/reference/commandline/events.md @@ -194,8 +194,8 @@ relative to the current time on the client machine: 2015-12-23T21:38:25.119625123Z network connect 8b111217944ba0ba844a65b13efcd57dc494932ee2527577758f939315ba2c5b (name=test-event-network-local, container=b4be644031a3d90b400f88ab3d4bdf4dc23adb250e696b6328b85441abe2c54e, type=bridge) $ docker events --filter 'type=plugin' (experimental) - 2016-07-25T17:30:14.825557616Z plugin pull ec7b87f2ce84330fe076e666f17dfc049d2d7ae0b8190763de94e1f2d105993f (name=tiborvass/no-remove:latest) - 2016-07-25T17:30:14.888127370Z plugin enable ec7b87f2ce84330fe076e666f17dfc049d2d7ae0b8190763de94e1f2d105993f (name=tiborvass/no-remove:latest) + 2016-07-25T17:30:14.825557616Z plugin pull ec7b87f2ce84330fe076e666f17dfc049d2d7ae0b8190763de94e1f2d105993f (name=tiborvass/sample-volume-plugin:latest) + 2016-07-25T17:30:14.888127370Z plugin enable ec7b87f2ce84330fe076e666f17dfc049d2d7ae0b8190763de94e1f2d105993f (name=tiborvass/sample-volume-plugin:latest) **Format:** diff --git a/docs/reference/commandline/plugin_disable.md b/docs/reference/commandline/plugin_disable.md index 66b0ca946694b432c52cbb1f9c8096b4e2f92452..f054fd066a4826baf734228bcf51ab8ad81b678a 100644 --- a/docs/reference/commandline/plugin_disable.md +++ b/docs/reference/commandline/plugin_disable.md @@ -30,27 +30,27 @@ see [`docker plugin install`](plugin_install.md). Without the `-f` option, a plugin that has references (eg, volumes, networks) cannot be disabled. -The following example shows that the `no-remove` plugin is installed +The following example shows that the `sample-volume-plugin` plugin is installed and enabled: ```bash $ docker plugin ls -ID NAME TAG DESCRIPTION ENABLED -69553ca1d123 tiborvass/no-remove latest A test plugin for Docker true +ID NAME TAG DESCRIPTION ENABLED +69553ca1d123 tiborvass/sample-volume-plugin latest A test plugin for Docker true ``` To disable the plugin, use the following command: ```bash -$ docker plugin disable tiborvass/no-remove +$ docker plugin disable tiborvass/sample-volume-plugin -tiborvass/no-remove +tiborvass/sample-volume-plugin $ docker plugin ls -ID NAME TAG DESCRIPTION ENABLED -69553ca1d123 tiborvass/no-remove latest A test plugin for Docker false +ID NAME TAG DESCRIPTION ENABLED +69553ca1d123 tiborvass/sample-volume-plugin latest A test plugin for Docker false ``` ## Related information diff --git a/docs/reference/commandline/plugin_enable.md b/docs/reference/commandline/plugin_enable.md index 36fb7640ac84614961ea64d552db134944b72d58..060592ef07e845e6d5447ed477ef77975a5ce467 100644 --- a/docs/reference/commandline/plugin_enable.md +++ b/docs/reference/commandline/plugin_enable.md @@ -29,27 +29,27 @@ Enables a plugin. The plugin must be installed before it can be enabled, see [`docker plugin install`](plugin_install.md). -The following example shows that the `no-remove` plugin is installed, +The following example shows that the `sample-volume-plugin` plugin is installed, but disabled: ```bash $ docker plugin ls -ID NAME TAG DESCRIPTION ENABLED -69553ca1d123 tiborvass/no-remove latest A test plugin for Docker false +ID NAME TAG DESCRIPTION ENABLED +69553ca1d123 tiborvass/sample-volume-plugin latest A test plugin for Docker false ``` To enable the plugin, use the following command: ```bash -$ docker plugin enable tiborvass/no-remove +$ docker plugin enable tiborvass/sample-volume-plugin -tiborvass/no-remove +tiborvass/sample-volume-plugin $ docker plugin ls -ID NAME TAG DESCRIPTION ENABLED -69553ca1d123 tiborvass/no-remove latest A test plugin for Docker true +ID NAME TAG DESCRIPTION ENABLED +69553ca1d123 tiborvass/sample-volume-plugin latest A test plugin for Docker true ``` ## Related information diff --git a/docs/reference/commandline/plugin_inspect.md b/docs/reference/commandline/plugin_inspect.md index 01e231bf06762ab6c9820e9f0678b717c7a8c0f9..d40cd40e75e807e945eb0dbbd621df0cf93a7325 100644 --- a/docs/reference/commandline/plugin_inspect.md +++ b/docs/reference/commandline/plugin_inspect.md @@ -31,12 +31,12 @@ in a JSON array. Example output: ```bash -$ docker plugin inspect tiborvass/no-remove:latest +$ docker plugin inspect tiborvass/sample-volume-plugin:latest ``` ```JSON { "Id": "8c74c978c434745c3ade82f1bc0acf38d04990eaf494fa507c16d9f1daa99c21", - "Name": "tiborvass/no-remove:latest", + "Name": "tiborvass/sample-volume-plugin:latest", "Enabled": true, "Config": { "Mounts": [ @@ -79,7 +79,7 @@ $ docker plugin inspect tiborvass/no-remove:latest "Socket": "plugins.sock" }, "Entrypoint": [ - "plugin-no-remove", + "plugin-sample-volume-plugin", "/data" ], "Workdir": "", @@ -143,7 +143,7 @@ $ docker plugin inspect tiborvass/no-remove:latest ```bash -$ docker plugin inspect -f '{{.Id}}' tiborvass/no-remove:latest +$ docker plugin inspect -f '{{.Id}}' tiborvass/sample-volume-plugin:latest ``` ``` 8c74c978c434745c3ade82f1bc0acf38d04990eaf494fa507c16d9f1daa99c21 diff --git a/docs/reference/commandline/plugin_install.md b/docs/reference/commandline/plugin_install.md index 502eb441bf77288efb7fa4168009132b9ad7e19c..78dd23825ffeb8d7bdfd20c652e9f624e4ec06e3 100644 --- a/docs/reference/commandline/plugin_install.md +++ b/docs/reference/commandline/plugin_install.md @@ -33,20 +33,20 @@ the registry. Note that the minimum required registry version to distribute plugins is 2.3.0 -The following example installs `no-remove` plugin and [set](plugin_set.md) it's env variable +The following example installs `vieus/sshfs` plugin and [set](plugin_set.md) it's env variable `DEBUG` to 1. Install consists of pulling the plugin from Docker Hub, prompting the user to accept the list of privileges that the plugin needs, settings parameters and enabling the plugin. ```bash -$ docker plugin install tiborvass/no-remove DEBUG=1 +$ docker plugin install vieux/sshfs DEBUG=1 -Plugin "tiborvass/no-remove" is requesting the following privileges: +Plugin "vieux/sshfs" is requesting the following privileges: - network: [host] - - mount: [/data] - - device: [/dev/cpu_dma_latency] + - device: [/dev/fuse] + - capabilities: [CAP_SYS_ADMIN] Do you grant the above permissions? [y/N] y -tiborvass/no-remove +vieux/sshfs ``` After the plugin is installed, it appears in the list of plugins: @@ -55,7 +55,7 @@ After the plugin is installed, it appears in the list of plugins: $ docker plugin ls ID NAME TAG DESCRIPTION ENABLED -69553ca1d123 tiborvass/no-remove latest A test plugin for Docker true +69553ca1d123 vieux/sshfs latest sshFS plugin for Docker true ``` ## Related information diff --git a/docs/reference/commandline/plugin_ls.md b/docs/reference/commandline/plugin_ls.md index b727b53341d8879cc18be939ac7cb082068ebd10..e436213eccb123ce80ab11336a87e23d0dd71209 100644 --- a/docs/reference/commandline/plugin_ls.md +++ b/docs/reference/commandline/plugin_ls.md @@ -36,8 +36,8 @@ Example output: ```bash $ docker plugin ls -ID NAME TAG DESCRIPTION ENABLED -69553ca1d123 tiborvass/no-remove latest A test plugin for Docker true +ID NAME TAG DESCRIPTION ENABLED +69553ca1d123 tiborvass/sample-volume-plugin latest A test plugin for Docker true ``` ## Related information diff --git a/docs/reference/commandline/plugin_rm.md b/docs/reference/commandline/plugin_rm.md index 5a01dcaa1e90c0e59579120659af0d93260c622b..31029324b629016378eb40e20e475f5c56dbc3b2 100644 --- a/docs/reference/commandline/plugin_rm.md +++ b/docs/reference/commandline/plugin_rm.md @@ -33,14 +33,14 @@ a plugin using the [`docker plugin disable`](plugin_disable.md) before removing it (or use --force, use of force is not recommended, since it can affect functioning of running containers using the plugin). -The following example disables and removes the `no-remove:latest` plugin; +The following example disables and removes the `sample-volume-plugin:latest` plugin; ```bash -$ docker plugin disable tiborvass/no-remove -tiborvass/no-remove +$ docker plugin disable tiborvass/sample-volume-plugin +tiborvass/sample-volume-plugin -$ docker plugin rm tiborvass/no-remove:latest -tiborvass/no-remove +$ docker plugin rm tiborvass/sample-volume-plugin:latest +tiborvass/sample-volume-plugin ``` ## Related information diff --git a/docs/reference/commandline/plugin_set.md b/docs/reference/commandline/plugin_set.md index 9ea93aecf9a4a08ef2e7987da53e37c19e5d530c..c206a8a760c644eb54498178244ca648a612b106 100644 --- a/docs/reference/commandline/plugin_set.md +++ b/docs/reference/commandline/plugin_set.md @@ -33,15 +33,15 @@ The settings currently supported are: * args The following example change the env variable `DEBUG` on the -`no-remove` plugin. +`sample-volume-plugin` plugin. ```bash -$ docker plugin inspect -f {{.Settings.Env}} tiborvass/no-remove +$ docker plugin inspect -f {{.Settings.Env}} tiborvass/sample-volume-plugin [DEBUG=0] -$ docker plugin set tiborvass/no-remove DEBUG=1 +$ docker plugin set tiborvass/sample-volume-plugin DEBUG=1 -$ docker plugin inspect -f {{.Settings.Env}} tiborvass/no-remove +$ docker plugin inspect -f {{.Settings.Env}} tiborvass/sample-volume-plugin [DEBUG=1] ``` diff --git a/man/docker-events.1.md b/man/docker-events.1.md index c0909c6817641e8cf70d71cb1b9d82d3914b0813..51b042775a4c3849fe264c8240039b89d87d4dde 100644 --- a/man/docker-events.1.md +++ b/man/docker-events.1.md @@ -168,8 +168,8 @@ Lines. For information about JSON Lines, please refer to http://jsonlines.org/ . 2015-12-23T21:38:25.119625123Z network connect 8b111217944ba0ba844a65b13efcd57dc494932ee2527577758f939315ba2c5b (name=test-event-network-local, container=b4be644031a3d90b400f88ab3d4bdf4dc23adb250e696b6328b85441abe2c54e, type=bridge) $ docker events --filter 'type=plugin' (experimental) - 2016-07-25T17:30:14.825557616Z plugin pull ec7b87f2ce84330fe076e666f17dfc049d2d7ae0b8190763de94e1f2d105993f (name=tiborvass/no-remove:latest) - 2016-07-25T17:30:14.888127370Z plugin enable ec7b87f2ce84330fe076e666f17dfc049d2d7ae0b8190763de94e1f2d105993f (name=tiborvass/no-remove:latest) + 2016-07-25T17:30:14.825557616Z plugin pull ec7b87f2ce84330fe076e666f17dfc049d2d7ae0b8190763de94e1f2d105993f (name=tiborvass/sample-volume-plugin:latest) + 2016-07-25T17:30:14.888127370Z plugin enable ec7b87f2ce84330fe076e666f17dfc049d2d7ae0b8190763de94e1f2d105993f (name=tiborvass/sample-volume-plugin:latest) # HISTORY From a46dbbded906bc49ec58597375cca48d2922bbc5 Mon Sep 17 00:00:00 2001 From: Lei Jitang Date: Fri, 16 Dec 2016 20:57:05 -0500 Subject: [PATCH 26/26] Fix update clear the restart policy of monitor Signed-off-by: Lei Jitang (cherry picked from commit 737b5b1781da9d7f286bb2425720add0ff69e3e3) Signed-off-by: Victor Vieux Signed-off-by: Vincent Demeester --- daemon/update.go | 4 ++- .../docker_cli_update_unix_test.go | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/daemon/update.go b/daemon/update.go index 67c0e59bf1f862b632117d5dfc702f780d10ffd4..6e26eeb96abe4f956d6a1a971a75cd2b00a6caf3 100644 --- a/daemon/update.go +++ b/daemon/update.go @@ -67,7 +67,9 @@ func (daemon *Daemon) update(name string, hostConfig *container.HostConfig) erro } // if Restart Policy changed, we need to update container monitor - container.UpdateMonitor(hostConfig.RestartPolicy) + if hostConfig.RestartPolicy.Name != "" { + container.UpdateMonitor(hostConfig.RestartPolicy) + } // If container is not running, update hostConfig struct is enough, // resources will be updated when the container is started again. diff --git a/integration-cli/docker_cli_update_unix_test.go b/integration-cli/docker_cli_update_unix_test.go index fb695372f1e6eac605e786bf339baaf4ca261ea4..580ff02602106a803ddea8ebbb3de2a481d4fffc 100644 --- a/integration-cli/docker_cli_update_unix_test.go +++ b/integration-cli/docker_cli_update_unix_test.go @@ -5,7 +5,10 @@ package main import ( "encoding/json" "fmt" + "github.com/kr/pty" + "os/exec" "strings" + "time" "github.com/docker/docker/api/types" "github.com/docker/docker/pkg/integration/checker" @@ -250,3 +253,31 @@ func (s *DockerSuite) TestUpdateMemoryWithSwapMemory(c *check.C) { dockerCmd(c, "update", "--memory", "800M", "--memory-swap", "1000M", name) } + +func (s *DockerSuite) TestUpdateNotAffectMonitorRestartPolicy(c *check.C) { + testRequires(c, DaemonIsLinux, cpuShare) + + out, _ := dockerCmd(c, "run", "-tid", "--restart=always", "busybox", "sh") + id := strings.TrimSpace(string(out)) + dockerCmd(c, "update", "--cpu-shares", "512", id) + + cpty, tty, err := pty.Open() + c.Assert(err, checker.IsNil) + defer cpty.Close() + + cmd := exec.Command(dockerBinary, "attach", id) + cmd.Stdin = tty + + c.Assert(cmd.Start(), checker.IsNil) + defer cmd.Process.Kill() + + _, err = cpty.Write([]byte("exit\n")) + c.Assert(err, checker.IsNil) + + c.Assert(cmd.Wait(), checker.IsNil) + + // container should restart again and keep running + err = waitInspect(id, "{{.RestartCount}}", "1", 30*time.Second) + c.Assert(err, checker.IsNil) + c.Assert(waitRun(id), checker.IsNil) +}