bump to 17.03.1-rc1
Victor Vieux authored on 2017/03/14 15:25:41... | ... |
@@ -5,6 +5,38 @@ information on the list of deprecated flags and APIs please have a look at |
5 | 5 |
https://docs.docker.com/engine/deprecated/ where target removal dates can also |
6 | 6 |
be found. |
7 | 7 |
|
8 |
+## 17.03.1-ce (2017-03-20) |
|
9 |
+ |
|
10 |
+### Remote API (v1.27) & Client |
|
11 |
+ |
|
12 |
+* Fix autoremove on older api [#31692](https://github.com/docker/docker/pull/31692) |
|
13 |
+* Fix default network customization for a stack [#31258](https://github.com/docker/docker/pull/31258/) |
|
14 |
+* Correct CPU usage calculation in presence of offline CPUs and newer Linux [#31802](https://github.com/docker/docker/pull/31802) |
|
15 |
+* Fix issue where service healthcheck is `{}` in remote API [#30197](https://github.com/docker/docker/pull/30197) |
|
16 |
+ |
|
17 |
+### Runtime |
|
18 |
+ |
|
19 |
+* Update runc to 54296cf40ad8143b62dbcaa1d90e520a2136ddfe [#3166](https://github.com/docker/docker/pull/31666) |
|
20 |
+ * Ignore cgroup2 mountpoints [opencontainers/runc#1266](https://github.com/opencontainers/runc/pull/1266) |
|
21 |
+* Update containerd to 595e75c212d19a81d2b808a518fe1afc1391dad5 [#31662](https://github.com/docker/docker/pull/31662) |
|
22 |
+ * Register healtcheck service before calling restore() [docker/containerd#609](https://github.com/docker/containerd/pull/609) |
|
23 |
+* Fix `docker exec` not working after unattended upgrades that reload apparmor profiles [#31773](https://github.com/docker/docker/pull/31773) |
|
24 |
+* Fix unmounting layer without merge dir with Overlay2 [#31069](https://github.com/docker/docker/pull/31069) |
|
25 |
+* Do not ignore "volume in use" errors when force-delete [#31450](https://github.com/docker/docker/pull/31450) |
|
26 |
+ |
|
27 |
+### Swarm Mode |
|
28 |
+ |
|
29 |
+* Update swarmkit to 17756457ad6dc4d8a639a1f0b7a85d1b65a617bb [#31807](https://github.com/docker/docker/pull/31807) |
|
30 |
+ * Scheduler now correctly considers tasks which have been assigned to a node but aren't yet running [docker/swarmkit#1980](https://github.com/docker/swarmkit/pull/1980) |
|
31 |
+ * Allow removal of a network when only dead tasks reference it [docker/swarmkit#2018](https://github.com/docker/swarmkit/pull/2018) |
|
32 |
+ * Retry failed network allocations less aggressively [docker/swarmkit#2021](https://github.com/docker/swarmkit/pull/2021) |
|
33 |
+ * Avoid network allocation for tasks that are no longer running [docker/swarmkit#2017](https://github.com/docker/swarmkit/pull/2017) |
|
34 |
+ * Bookkeeping fixes inside network allocator allocator [docker/swarmkit#2019](https://github.com/docker/swarmkit/pull/2019) [docker/swarmkit#2020](https://github.com/docker/swarmkit/pull/2020) |
|
35 |
+ |
|
36 |
+### Windows |
|
37 |
+ |
|
38 |
+* Cleanup HCS on restore [#31503](https://github.com/docker/docker/pull/31503) |
|
39 |
+ |
|
8 | 40 |
## 17.03.0-ce (2017-03-01) |
9 | 41 |
|
10 | 42 |
**IMPORTANT**: Starting with this release, Docker is on a monthly release cycle and uses a |
... | ... |
@@ -45,9 +77,6 @@ Upgrading from Docker 1.13.1 to 17.03.0 is expected to be simple and low-risk. |
45 | 45 |
### Swarm Mode |
46 | 46 |
|
47 | 47 |
* Shutdown leaks an error when the container was never started [#31279](https://github.com/docker/docker/pull/31279) |
48 |
- |
|
49 |
-### Swarm Mode |
|
50 |
- |
|
51 | 48 |
* Fix possibility of tasks getting stuck in the "NEW" state during a leader failover [docker/swarmkit#1938](https://github.com/docker/swarmkit/pull/1938) |
52 | 49 |
* Fix extraneous task creations for global services that led to confusing replica counts in `docker service ls` [docker/swarmkit#1957](https://github.com/docker/swarmkit/pull/1957) |
53 | 50 |
* Fix problem that made rolling updates slow when `task-history-limit` was set to 1 [docker/swarmkit#1948](https://github.com/docker/swarmkit/pull/1948) |
... | ... |
@@ -118,8 +118,6 @@ tags: |
118 | 118 |
Run new commands inside running containers. See the [command-line reference](https://docs.docker.com/engine/reference/commandline/exec/) for more information. |
119 | 119 |
|
120 | 120 |
To exec a command in a container, you first need to create an exec instance, then start it. These two API endpoints are wrapped up in a single command-line command, `docker exec`. |
121 |
- - name: "Secret" |
|
122 |
- x-displayName: "Secrets" |
|
123 | 121 |
# Swarm things |
124 | 122 |
- name: "Swarm" |
125 | 123 |
x-displayName: "Swarm" |
... | ... |
@@ -137,6 +135,10 @@ tags: |
137 | 137 |
x-displayName: "Tasks" |
138 | 138 |
description: | |
139 | 139 |
A task is a container running on a swarm. It is the atomic scheduling unit of swarm. Swarm mode must be enabled for these endpoints to work. |
140 |
+ - name: "Secret" |
|
141 |
+ x-displayName: "Secrets" |
|
142 |
+ description: | |
|
143 |
+ Secrets are sensitive data that can be used by services. Swarm mode must be enabled for these endpoints to work. |
|
140 | 144 |
# System things |
141 | 145 |
- name: "Plugin" |
142 | 146 |
x-displayName: "Plugins" |
... | ... |
@@ -271,7 +271,7 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error { |
271 | 271 |
fmt.Fprintf(dockerCli.Out(), " %s\n", attribute) |
272 | 272 |
} |
273 | 273 |
// TODO: Engine labels with duplicate keys has been deprecated in 1.13 and will be error out |
274 |
- // after 3 release cycles (1.16). For now, a WARNING will be generated. The following will |
|
274 |
+ // after 3 release cycles (17.12). For now, a WARNING will be generated. The following will |
|
275 | 275 |
// be removed eventually. |
276 | 276 |
labelMap := map[string]string{} |
277 | 277 |
for _, label := range info.Labels { |
... | ... |
@@ -17,6 +17,8 @@ import ( |
17 | 17 |
"github.com/docker/go-connections/nat" |
18 | 18 |
) |
19 | 19 |
|
20 |
+const defaultNetwork = "default" |
|
21 |
+ |
|
20 | 22 |
// Services from compose-file types to engine API types |
21 | 23 |
// TODO: fix secrets API so that SecretAPIClient is not required here |
22 | 24 |
func Services( |
... | ... |
@@ -157,18 +159,15 @@ func convertServiceNetworks( |
157 | 157 |
name string, |
158 | 158 |
) ([]swarm.NetworkAttachmentConfig, error) { |
159 | 159 |
if len(networks) == 0 { |
160 |
- return []swarm.NetworkAttachmentConfig{ |
|
161 |
- { |
|
162 |
- Target: namespace.Scope("default"), |
|
163 |
- Aliases: []string{name}, |
|
164 |
- }, |
|
165 |
- }, nil |
|
160 |
+ networks = map[string]*composetypes.ServiceNetworkConfig{ |
|
161 |
+ defaultNetwork: {}, |
|
162 |
+ } |
|
166 | 163 |
} |
167 | 164 |
|
168 | 165 |
nets := []swarm.NetworkAttachmentConfig{} |
169 | 166 |
for networkName, network := range networks { |
170 | 167 |
networkConfig, ok := networkConfigs[networkName] |
171 |
- if !ok { |
|
168 |
+ if !ok && networkName != defaultNetwork { |
|
172 | 169 |
return []swarm.NetworkAttachmentConfig{}, fmt.Errorf( |
173 | 170 |
"service %q references network %q, which is not declared", name, networkName) |
174 | 171 |
} |
... | ... |
@@ -145,10 +145,9 @@ func TestConvertHealthcheckDisableWithTest(t *testing.T) { |
145 | 145 |
|
146 | 146 |
func TestConvertServiceNetworksOnlyDefault(t *testing.T) { |
147 | 147 |
networkConfigs := networkMap{} |
148 |
- networks := map[string]*composetypes.ServiceNetworkConfig{} |
|
149 | 148 |
|
150 | 149 |
configs, err := convertServiceNetworks( |
151 |
- networks, networkConfigs, NewNamespace("foo"), "service") |
|
150 |
+ nil, networkConfigs, NewNamespace("foo"), "service") |
|
152 | 151 |
|
153 | 152 |
expected := []swarm.NetworkAttachmentConfig{ |
154 | 153 |
{ |
... | ... |
@@ -201,6 +200,31 @@ func TestConvertServiceNetworks(t *testing.T) { |
201 | 201 |
assert.DeepEqual(t, []swarm.NetworkAttachmentConfig(sortedConfigs), expected) |
202 | 202 |
} |
203 | 203 |
|
204 |
+func TestConvertServiceNetworksCustomDefault(t *testing.T) { |
|
205 |
+ networkConfigs := networkMap{ |
|
206 |
+ "default": composetypes.NetworkConfig{ |
|
207 |
+ External: composetypes.External{ |
|
208 |
+ External: true, |
|
209 |
+ Name: "custom", |
|
210 |
+ }, |
|
211 |
+ }, |
|
212 |
+ } |
|
213 |
+ networks := map[string]*composetypes.ServiceNetworkConfig{} |
|
214 |
+ |
|
215 |
+ configs, err := convertServiceNetworks( |
|
216 |
+ networks, networkConfigs, NewNamespace("foo"), "service") |
|
217 |
+ |
|
218 |
+ expected := []swarm.NetworkAttachmentConfig{ |
|
219 |
+ { |
|
220 |
+ Target: "custom", |
|
221 |
+ Aliases: []string{"service"}, |
|
222 |
+ }, |
|
223 |
+ } |
|
224 |
+ |
|
225 |
+ assert.NilError(t, err) |
|
226 |
+ assert.DeepEqual(t, []swarm.NetworkAttachmentConfig(configs), expected) |
|
227 |
+} |
|
228 |
+ |
|
204 | 229 |
type byTargetSort []swarm.NetworkAttachmentConfig |
205 | 230 |
|
206 | 231 |
func (s byTargetSort) Len() int { |
... | ... |
@@ -433,7 +433,7 @@ func loadDaemonCliConfig(opts daemonOptions) (*daemon.Config, error) { |
433 | 433 |
// This is deprecated in 1.13, and, be removed after 3 release cycles. |
434 | 434 |
// The following will check the conflict of labels, and report a warning for deprecation. |
435 | 435 |
// |
436 |
- // TODO: After 3 release cycles (1.16) an error will be returned, and labels will be |
|
436 |
+ // TODO: After 3 release cycles (17.12) an error will be returned, and labels will be |
|
437 | 437 |
// sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels): |
438 | 438 |
// |
439 | 439 |
// newLabels, err := daemon.GetConflictFreeLabels(config.Labels) |
... | ... |
@@ -570,7 +570,7 @@ __docker_subcommands() { |
570 | 570 |
$(__docker_to_extglob "$subcommands") ) |
571 | 571 |
subcommand_pos=$counter |
572 | 572 |
local subcommand=${words[$counter]} |
573 |
- local completions_func=_docker_${command}_${subcommand} |
|
573 |
+ local completions_func=_docker_${command}_${subcommand//-/_} |
|
574 | 574 |
declare -F $completions_func >/dev/null && $completions_func |
575 | 575 |
return 0 |
576 | 576 |
;; |
... | ... |
@@ -605,38 +605,25 @@ __docker_complete_local_interfaces() { |
605 | 605 |
COMPREPLY=( $( compgen -W "$(__docker_local_interfaces) $additional_interface" -- "$cur" ) ) |
606 | 606 |
} |
607 | 607 |
|
608 |
-__docker_complete_capabilities() { |
|
609 |
- # The list of capabilities is defined in types.go, ALL was added manually. |
|
608 |
+# __docker_complete_capabilities_addable completes Linux capabilities which are |
|
609 |
+# not granted by default and may be added. |
|
610 |
+# see https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities |
|
611 |
+__docker_complete_capabilities_addable() { |
|
610 | 612 |
COMPREPLY=( $( compgen -W " |
611 | 613 |
ALL |
612 | 614 |
AUDIT_CONTROL |
613 |
- AUDIT_WRITE |
|
614 |
- AUDIT_READ |
|
615 | 615 |
BLOCK_SUSPEND |
616 |
- CHOWN |
|
617 |
- DAC_OVERRIDE |
|
618 | 616 |
DAC_READ_SEARCH |
619 |
- FOWNER |
|
620 |
- FSETID |
|
621 | 617 |
IPC_LOCK |
622 | 618 |
IPC_OWNER |
623 |
- KILL |
|
624 | 619 |
LEASE |
625 | 620 |
LINUX_IMMUTABLE |
626 | 621 |
MAC_ADMIN |
627 | 622 |
MAC_OVERRIDE |
628 |
- MKNOD |
|
629 | 623 |
NET_ADMIN |
630 |
- NET_BIND_SERVICE |
|
631 | 624 |
NET_BROADCAST |
632 |
- NET_RAW |
|
633 |
- SETFCAP |
|
634 |
- SETGID |
|
635 |
- SETPCAP |
|
636 |
- SETUID |
|
637 | 625 |
SYS_ADMIN |
638 | 626 |
SYS_BOOT |
639 |
- SYS_CHROOT |
|
640 | 627 |
SYSLOG |
641 | 628 |
SYS_MODULE |
642 | 629 |
SYS_NICE |
... | ... |
@@ -650,7 +637,30 @@ __docker_complete_capabilities() { |
650 | 650 |
" -- "$cur" ) ) |
651 | 651 |
} |
652 | 652 |
|
653 |
-__docker_complete_detach-keys() { |
|
653 |
+# __docker_complete_capabilities_droppable completes Linux capability options which are |
|
654 |
+# allowed by default and can be dropped. |
|
655 |
+# see https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities |
|
656 |
+__docker_complete_capabilities_droppable() { |
|
657 |
+ COMPREPLY=( $( compgen -W " |
|
658 |
+ ALL |
|
659 |
+ AUDIT_WRITE |
|
660 |
+ CHOWN |
|
661 |
+ DAC_OVERRIDE |
|
662 |
+ FOWNER |
|
663 |
+ FSETID |
|
664 |
+ KILL |
|
665 |
+ MKNOD |
|
666 |
+ NET_BIND_SERVICE |
|
667 |
+ NET_RAW |
|
668 |
+ SETFCAP |
|
669 |
+ SETGID |
|
670 |
+ SETPCAP |
|
671 |
+ SETUID |
|
672 |
+ SYS_CHROOT |
|
673 |
+ " -- "$cur" ) ) |
|
674 |
+} |
|
675 |
+ |
|
676 |
+__docker_complete_detach_keys() { |
|
654 | 677 |
case "$prev" in |
655 | 678 |
--detach-keys) |
656 | 679 |
case "$cur" in |
... | ... |
@@ -1047,7 +1057,7 @@ _docker_container() { |
1047 | 1047 |
} |
1048 | 1048 |
|
1049 | 1049 |
_docker_container_attach() { |
1050 |
- __docker_complete_detach-keys && return |
|
1050 |
+ __docker_complete_detach_keys && return |
|
1051 | 1051 |
|
1052 | 1052 |
case "$cur" in |
1053 | 1053 |
-*) |
... | ... |
@@ -1154,7 +1164,7 @@ _docker_container_diff() { |
1154 | 1154 |
} |
1155 | 1155 |
|
1156 | 1156 |
_docker_container_exec() { |
1157 |
- __docker_complete_detach-keys && return |
|
1157 |
+ __docker_complete_detach_keys && return |
|
1158 | 1158 |
|
1159 | 1159 |
case "$prev" in |
1160 | 1160 |
--env|-e) |
... | ... |
@@ -1498,7 +1508,7 @@ _docker_container_run() { |
1498 | 1498 |
--rm |
1499 | 1499 |
--sig-proxy=false |
1500 | 1500 |
" |
1501 |
- __docker_complete_detach-keys && return |
|
1501 |
+ __docker_complete_detach_keys && return |
|
1502 | 1502 |
fi |
1503 | 1503 |
|
1504 | 1504 |
local all_options="$options_with_args $boolean_options" |
... | ... |
@@ -1538,8 +1548,12 @@ _docker_container_run() { |
1538 | 1538 |
COMPREPLY=( $( compgen -W 'stdin stdout stderr' -- "$cur" ) ) |
1539 | 1539 |
return |
1540 | 1540 |
;; |
1541 |
- --cap-add|--cap-drop) |
|
1542 |
- __docker_complete_capabilities |
|
1541 |
+ --cap-add) |
|
1542 |
+ __docker_complete_capabilities_addable |
|
1543 |
+ return |
|
1544 |
+ ;; |
|
1545 |
+ --cap-drop) |
|
1546 |
+ __docker_complete_capabilities_droppable |
|
1543 | 1547 |
return |
1544 | 1548 |
;; |
1545 | 1549 |
--cidfile|--env-file|--init-path|--label-file) |
... | ... |
@@ -1686,7 +1700,7 @@ _docker_container_run() { |
1686 | 1686 |
} |
1687 | 1687 |
|
1688 | 1688 |
_docker_container_start() { |
1689 |
- __docker_complete_detach-keys && return |
|
1689 |
+ __docker_complete_detach_keys && return |
|
1690 | 1690 |
|
1691 | 1691 |
case "$prev" in |
1692 | 1692 |
--checkpoint) |
... | ... |
@@ -3141,7 +3155,7 @@ _docker_swarm_join() { |
3141 | 3141 |
esac |
3142 | 3142 |
} |
3143 | 3143 |
|
3144 |
-_docker_swarm_join-token() { |
|
3144 |
+_docker_swarm_join_token() { |
|
3145 | 3145 |
case "$cur" in |
3146 | 3146 |
-*) |
3147 | 3147 |
COMPREPLY=( $( compgen -W "--help --quiet -q --rotate" -- "$cur" ) ) |
... | ... |
@@ -3171,7 +3185,7 @@ _docker_swarm_unlock() { |
3171 | 3171 |
esac |
3172 | 3172 |
} |
3173 | 3173 |
|
3174 |
-_docker_swarm_unlock-key() { |
|
3174 |
+_docker_swarm_unlock_key() { |
|
3175 | 3175 |
case "$cur" in |
3176 | 3176 |
-*) |
3177 | 3177 |
COMPREPLY=( $( compgen -W "--help --quiet -q --rotate" -- "$cur" ) ) |
... | ... |
@@ -4289,7 +4303,7 @@ _docker() { |
4289 | 4289 |
command_pos=0 |
4290 | 4290 |
fi |
4291 | 4291 |
|
4292 |
- local completions_func=_docker_${command} |
|
4292 |
+ local completions_func=_docker_${command//-/_} |
|
4293 | 4293 |
declare -F $completions_func >/dev/null && $completions_func |
4294 | 4294 |
|
4295 | 4295 |
eval "$previous_extglob_setting" |
... | ... |
@@ -205,7 +205,7 @@ func (r *controller) Start(ctx context.Context) error { |
205 | 205 |
} |
206 | 206 |
|
207 | 207 |
// no health check |
208 |
- if ctnr.Config == nil || ctnr.Config.Healthcheck == nil { |
|
208 |
+ if ctnr.Config == nil || ctnr.Config.Healthcheck == nil || len(ctnr.Config.Healthcheck.Test) == 0 || ctnr.Config.Healthcheck.Test[0] == "NONE" { |
|
209 | 209 |
if err := r.adapter.activateServiceBinding(); err != nil { |
210 | 210 |
log.G(ctx).WithError(err).Errorf("failed to activate service binding for container %s which has no healthcheck config", r.adapter.container.name()) |
211 | 211 |
return err |
... | ... |
@@ -213,12 +213,6 @@ func (r *controller) Start(ctx context.Context) error { |
213 | 213 |
return nil |
214 | 214 |
} |
215 | 215 |
|
216 |
- healthCmd := ctnr.Config.Healthcheck.Test |
|
217 |
- |
|
218 |
- if len(healthCmd) == 0 || healthCmd[0] == "NONE" { |
|
219 |
- return nil |
|
220 |
- } |
|
221 |
- |
|
222 | 216 |
// wait for container to be healthy |
223 | 217 |
eventq := r.adapter.events(ctx) |
224 | 218 |
|
... | ... |
@@ -279,7 +279,7 @@ func ReloadConfiguration(configFile string, flags *pflag.FlagSet, reload func(*C |
279 | 279 |
// This is deprecated in 1.13, and, be removed after 3 release cycles. |
280 | 280 |
// The following will check the conflict of labels, and report a warning for deprecation. |
281 | 281 |
// |
282 |
- // TODO: After 3 release cycles (1.16) an error will be returned, and labels will be |
|
282 |
+ // TODO: After 3 release cycles (17.12) an error will be returned, and labels will be |
|
283 | 283 |
// sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels): |
284 | 284 |
// |
285 | 285 |
// newLabels, err := GetConflictFreeLabels(newConfig.Labels) |
... | ... |
@@ -8,11 +8,12 @@ import ( |
8 | 8 |
"time" |
9 | 9 |
|
10 | 10 |
"github.com/Sirupsen/logrus" |
11 |
- "github.com/docker/docker/api/errors" |
|
11 |
+ apierrors "github.com/docker/docker/api/errors" |
|
12 | 12 |
"github.com/docker/docker/api/types" |
13 | 13 |
"github.com/docker/docker/container" |
14 | 14 |
"github.com/docker/docker/layer" |
15 | 15 |
volumestore "github.com/docker/docker/volume/store" |
16 |
+ "github.com/pkg/errors" |
|
16 | 17 |
) |
17 | 18 |
|
18 | 19 |
// ContainerRm removes the container id from the filesystem. An error |
... | ... |
@@ -29,7 +30,7 @@ func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig) |
29 | 29 |
// Container state RemovalInProgress should be used to avoid races. |
30 | 30 |
if inProgress := container.SetRemovalInProgress(); inProgress { |
31 | 31 |
err := fmt.Errorf("removal of container %s is already in progress", name) |
32 |
- return errors.NewBadRequestError(err) |
|
32 |
+ return apierrors.NewBadRequestError(err) |
|
33 | 33 |
} |
34 | 34 |
defer container.ResetRemovalInProgress() |
35 | 35 |
|
... | ... |
@@ -80,7 +81,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo |
80 | 80 |
if container.IsRunning() { |
81 | 81 |
if !forceRemove { |
82 | 82 |
err := fmt.Errorf("You cannot remove a running container %s. Stop the container before attempting removal or use -f", container.ID) |
83 |
- return errors.NewRequestConflictError(err) |
|
83 |
+ return apierrors.NewRequestConflictError(err) |
|
84 | 84 |
} |
85 | 85 |
if err := daemon.Kill(container); err != nil { |
86 | 86 |
return fmt.Errorf("Could not kill running container %s, cannot remove - %v", container.ID, err) |
... | ... |
@@ -143,6 +144,9 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo |
143 | 143 |
// This is called directly from the Engine API |
144 | 144 |
func (daemon *Daemon) VolumeRm(name string, force bool) error { |
145 | 145 |
err := daemon.volumeRm(name) |
146 |
+ if err != nil && volumestore.IsInUse(err) { |
|
147 |
+ return apierrors.NewRequestConflictError(err) |
|
148 |
+ } |
|
146 | 149 |
if err == nil || force { |
147 | 150 |
daemon.volumes.Purge(name) |
148 | 151 |
return nil |
... | ... |
@@ -157,11 +161,7 @@ func (daemon *Daemon) volumeRm(name string) error { |
157 | 157 |
} |
158 | 158 |
|
159 | 159 |
if err := daemon.volumes.Remove(v); err != nil { |
160 |
- if volumestore.IsInUse(err) { |
|
161 |
- err := fmt.Errorf("Unable to remove volume, volume still in use: %v", err) |
|
162 |
- return errors.NewRequestConflictError(err) |
|
163 |
- } |
|
164 |
- return fmt.Errorf("Error while removing volume %s: %v", name, err) |
|
160 |
+ return errors.Wrap(err, "unable to remove volume") |
|
165 | 161 |
} |
166 | 162 |
daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()}) |
167 | 163 |
return nil |
... | ... |
@@ -5,6 +5,7 @@ import ( |
5 | 5 |
"github.com/docker/docker/daemon/caps" |
6 | 6 |
"github.com/docker/docker/daemon/exec" |
7 | 7 |
"github.com/docker/docker/libcontainerd" |
8 |
+ "github.com/opencontainers/runc/libcontainer/apparmor" |
|
8 | 9 |
"github.com/opencontainers/runtime-spec/specs-go" |
9 | 10 |
) |
10 | 11 |
|
... | ... |
@@ -23,5 +24,27 @@ func execSetPlatformOpt(c *container.Container, ec *exec.Config, p *libcontainer |
23 | 23 |
if ec.Privileged { |
24 | 24 |
p.Capabilities = caps.GetAllCapabilities() |
25 | 25 |
} |
26 |
+ if apparmor.IsEnabled() { |
|
27 |
+ var appArmorProfile string |
|
28 |
+ if c.AppArmorProfile != "" { |
|
29 |
+ appArmorProfile = c.AppArmorProfile |
|
30 |
+ } else if c.HostConfig.Privileged { |
|
31 |
+ appArmorProfile = "unconfined" |
|
32 |
+ } else { |
|
33 |
+ appArmorProfile = "docker-default" |
|
34 |
+ } |
|
35 |
+ |
|
36 |
+ if appArmorProfile == "docker-default" { |
|
37 |
+ // Unattended upgrades and other fun services can unload AppArmor |
|
38 |
+ // profiles inadvertently. Since we cannot store our profile in |
|
39 |
+ // /etc/apparmor.d, nor can we practically add other ways of |
|
40 |
+ // telling the system to keep our profile loaded, in order to make |
|
41 |
+ // sure that we keep the default profile enabled we dynamically |
|
42 |
+ // reload it if necessary. |
|
43 |
+ if err := ensureDefaultAppArmorProfile(); err != nil { |
|
44 |
+ return err |
|
45 |
+ } |
|
46 |
+ } |
|
47 |
+ } |
|
26 | 48 |
return nil |
27 | 49 |
} |
... | ... |
@@ -144,7 +144,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap |
144 | 144 |
return nil, err |
145 | 145 |
} |
146 | 146 |
if !supportsDType { |
147 |
- // not a fatal error until v1.16 (#27443) |
|
147 |
+ // not a fatal error until v17.12 (#27443) |
|
148 | 148 |
logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay", backingFs)) |
149 | 149 |
} |
150 | 150 |
|
... | ... |
@@ -30,7 +30,7 @@ import ( |
30 | 30 |
"github.com/docker/docker/pkg/mount" |
31 | 31 |
"github.com/docker/docker/pkg/parsers" |
32 | 32 |
"github.com/docker/docker/pkg/parsers/kernel" |
33 |
- "github.com/docker/go-units" |
|
33 |
+ units "github.com/docker/go-units" |
|
34 | 34 |
|
35 | 35 |
"github.com/opencontainers/runc/libcontainer/label" |
36 | 36 |
) |
... | ... |
@@ -170,7 +170,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap |
170 | 170 |
return nil, err |
171 | 171 |
} |
172 | 172 |
if !supportsDType { |
173 |
- // not a fatal error until v1.16 (#27443) |
|
173 |
+ // not a fatal error until v17.12 (#27443) |
|
174 | 174 |
logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay2", backingFs)) |
175 | 175 |
} |
176 | 176 |
|
... | ... |
@@ -553,7 +553,17 @@ func (d *Driver) Get(id string, mountLabel string) (s string, err error) { |
553 | 553 |
|
554 | 554 |
// Put unmounts the mount path created for the give id. |
555 | 555 |
func (d *Driver) Put(id string) error { |
556 |
- mountpoint := path.Join(d.dir(id), "merged") |
|
556 |
+ dir := d.dir(id) |
|
557 |
+ _, err := ioutil.ReadFile(path.Join(dir, lowerFile)) |
|
558 |
+ if err != nil { |
|
559 |
+ // If no lower, no mount happened and just return directly |
|
560 |
+ if os.IsNotExist(err) { |
|
561 |
+ return nil |
|
562 |
+ } |
|
563 |
+ return err |
|
564 |
+ } |
|
565 |
+ |
|
566 |
+ mountpoint := path.Join(dir, "merged") |
|
557 | 567 |
if count := d.ctr.Decrement(mountpoint); count > 0 { |
558 | 568 |
return nil |
559 | 569 |
} |
... | ... |
@@ -13,6 +13,6 @@ func ErrDTypeNotSupported(driver, backingFs string) error { |
13 | 13 |
if backingFs == "xfs" { |
14 | 14 |
msg += " Reformat the filesystem with ftype=1 to enable d_type support." |
15 | 15 |
} |
16 |
- msg += " Running without d_type support will no longer be supported in Docker 1.16." |
|
16 |
+ msg += " Running without d_type support will no longer be supported in Docker 17.12." |
|
17 | 17 |
return errors.New(msg) |
18 | 18 |
} |
... | ... |
@@ -35,7 +35,7 @@ Options: |
35 | 35 |
- name=<string> a container's name |
36 | 36 |
- network=(<network-id>|<network-name>) |
37 | 37 |
- since=(<container-name>|<container-id>) |
38 |
- - status=(created|restarting|removing|running|paused|exited) |
|
38 |
+ - status=(created|restarting|removing|running|paused|exited) |
|
39 | 39 |
- volume=(<volume name>|<mount point destination>) |
40 | 40 |
--format string Pretty-print containers using a Go template |
41 | 41 |
--help Print usage |
... | ... |
@@ -84,11 +84,11 @@ The currently supported filters are: |
84 | 84 |
* label (`label=<key>` or `label=<key>=<value>`) |
85 | 85 |
* name (container's name) |
86 | 86 |
* exited (int - the code of exited containers. Only useful with `--all`) |
87 |
-* status (created|restarting|running|removing|paused|exited|dead) |
|
87 |
+* status (`created|restarting|running|removing|paused|exited|dead`) |
|
88 | 88 |
* ancestor (`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) - filters containers that were created from the given image or a descendant. |
89 | 89 |
* before (container's id or name) - filters containers created before given id or name |
90 | 90 |
* since (container's id or name) - filters containers created since given id or name |
91 |
-* isolation (default|process|hyperv) (Windows daemon only) |
|
91 |
+* isolation (`default|process|hyperv`) (Windows daemon only) |
|
92 | 92 |
* volume (volume name or mount point) - filters containers that mount volumes. |
93 | 93 |
* network (network id or name) - filters containers connected to the provided network |
94 | 94 |
* health (starting|healthy|unhealthy|none) - filters containers based on healthcheck status |
... | ... |
@@ -249,12 +249,69 @@ For more information about named volumes, see |
249 | 249 |
The following table describes options which apply to both bind-mounts and named |
250 | 250 |
volumes in a service: |
251 | 251 |
|
252 |
-| Option | Required | Description |
|
253 |
-|:-----------------------------------------|:--------------------------|:----------------------------------------------------------------------------------------- |
|
254 |
-| **type** | | The type of mount, can be either `volume`, `bind`, or `tmpfs`. Defaults to `volume` if no type is specified.<ul><li>`volume`: mounts a [managed volume](volume_create.md) into the container.</li><li>`bind`: bind-mounts a directory or file from the host into the container.</li><li>`tmpfs`: mount a tmpfs in the container</li></ul> |
|
255 |
-| **src** or **source** | for `type=bind` only | <ul><li>`type=volume`: `src` is an optional way to specify the name of the volume (for example, `src=my-volume`). If the named volume does not exist, it is automatically created. If no `src` is specified, the volume is assigned a random name which is guaranteed to be unique on the host, but may not be unique cluster-wide. A randomly-named volume has the same lifecycle as its container and is destroyed when the *container* is destroyed (which is upon `service update`, or when scaling or re-balancing the service).</li><li>`type=bind`: `src` is required, and specifies an absolute path to the file or directory to bind-mount (for example, `src=/path/on/host/`). An error is produced if the file or directory does not exist.</li><li>`type=tmpfs`: `src` is not supported.</li></ul> |
|
256 |
-| **dst** or **destination** or **target** | yes | Mount path inside the container, for example `/some/path/in/container/`. If the path does not exist in the container's filesystem, the Engine creates a directory at the specified location before mounting the volume or bind-mount. |
|
257 |
-| **readonly** or **ro** | | The Engine mounts binds and volumes `read-write` unless `readonly` option is given when mounting the bind or volume.<br /><br /><ul><li>`true` or `1` or no value: Mounts the bind or volume read-only.</li><li>`false` or `0`: Mounts the bind or volume read-write.</li></ul> |
|
252 |
+<table> |
|
253 |
+ <tr> |
|
254 |
+ <th>Option</th> |
|
255 |
+ <th>Required</th> |
|
256 |
+ <th>Description</th> |
|
257 |
+ </tr> |
|
258 |
+ <tr> |
|
259 |
+ <td><b>types</b></td> |
|
260 |
+ <td></td> |
|
261 |
+ <td> |
|
262 |
+ <p>The type of mount, can be either <tt>volume</tt>, <tt>bind</tt>, or <tt>tmpfs</tt>. Defaults to <tt>volume</tt> if no type is specified. |
|
263 |
+ <ul> |
|
264 |
+ <li><tt>volume</tt>: mounts a [managed volume](volume_create.md) into the container.</li> |
|
265 |
+ <li><tt>bind</tt>: bind-mounts a directory or file from the host into the container.</li> |
|
266 |
+ <li><tt>tmpfs</tt>: mount a tmpfs in the container</li> |
|
267 |
+ </ul></p> |
|
268 |
+ </td> |
|
269 |
+ </tr> |
|
270 |
+ <tr> |
|
271 |
+ <td><b>src</b> or <b>source</b></td> |
|
272 |
+ <td>for <tt>type=bind</tt> only></td> |
|
273 |
+ <td> |
|
274 |
+ <ul> |
|
275 |
+ <li> |
|
276 |
+ <tt>type=volume</tt>: <tt>src</tt> is an optional way to specify the name of the volume (for example, <tt>src=my-volume</tt>). |
|
277 |
+ If the named volume does not exist, it is automatically created. If no <tt>src</tt> is specified, the volume is |
|
278 |
+ assigned a random name which is guaranteed to be unique on the host, but may not be unique cluster-wide. |
|
279 |
+ A randomly-named volume has the same lifecycle as its container and is destroyed when the <i>container</i> |
|
280 |
+ is destroyed (which is upon <tt>service update</tt>, or when scaling or re-balancing the service) |
|
281 |
+ </li> |
|
282 |
+ <li> |
|
283 |
+ <tt>type=bind</tt>: <tt>src</tt> is required, and specifies an absolute path to the file or directory to bind-mount |
|
284 |
+ (for example, <tt>src=/path/on/host/</tt>). An error is produced if the file or directory does not exist. |
|
285 |
+ </li> |
|
286 |
+ <li> |
|
287 |
+ <tt>type=tmpfs</tt>: <tt>src</tt> is not supported. |
|
288 |
+ </li> |
|
289 |
+ </ul> |
|
290 |
+ </td> |
|
291 |
+ </tr> |
|
292 |
+ <tr> |
|
293 |
+ <td><p><b>dst</b> or <b>destination</b> or <b>target</b></p></td> |
|
294 |
+ <td>yes</td> |
|
295 |
+ <td> |
|
296 |
+ <p>Mount path inside the container, for example <tt>/some/path/in/container/</tt>. |
|
297 |
+ If the path does not exist in the container's filesystem, the Engine creates |
|
298 |
+ a directory at the specified location before mounting the volume or bind-mount.</p> |
|
299 |
+ </td> |
|
300 |
+ </tr> |
|
301 |
+ <tr> |
|
302 |
+ <td><p><b>readonly</b> or <b>ro</b></p></td> |
|
303 |
+ <td></td> |
|
304 |
+ <td> |
|
305 |
+ <p>The Engine mounts binds and volumes <tt>read-write</tt> unless <tt>readonly</tt> option |
|
306 |
+ is given when mounting the bind or volume. |
|
307 |
+ <ul> |
|
308 |
+ <li><tt>true</tt> or <tt>1</tt> or no value: Mounts the bind or volume read-only.</li> |
|
309 |
+ <li><tt>false</tt> or <tt>0</tt>: Mounts the bind or volume read-write.</li> |
|
310 |
+ </ul></p> |
|
311 |
+ </td> |
|
312 |
+ </tr> |
|
313 |
+</table> |
|
314 |
+ |
|
258 | 315 |
|
259 | 316 |
#### Bind Propagation |
260 | 317 |
|
... | ... |
@@ -294,22 +351,84 @@ For more information about bind propagation, see the |
294 | 294 |
[Linux kernel documentation for shared subtree](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt). |
295 | 295 |
|
296 | 296 |
#### Options for Named Volumes |
297 |
+ |
|
297 | 298 |
The following options can only be used for named volumes (`type=volume`); |
298 | 299 |
|
299 |
-| Option | Description |
|
300 |
-|:----------------------|:-------------------------------------------------------------------------------------------------------------------- |
|
301 |
-| **volume-driver** | Name of the volume-driver plugin to use for the volume. Defaults to ``"local"``, to use the local volume driver to create the volume if the volume does not exist. |
|
302 |
-| **volume-label** | One or more custom metadata ("labels") to apply to the volume upon creation. For example, `volume-label=mylabel=hello-world,my-other-label=hello-mars`. For more information about labels, refer to [apply custom metadata](https://docs.docker.com/engine/userguide/labels-custom-metadata/). |
|
303 |
-| **volume-nocopy** | By default, if you attach an empty volume to a container, and files or directories already existed at the mount-path in the container (`dst`), the Engine copies those files and directories into the volume, allowing the host to access them. Set `volume-nocopy` to disables copying files from the container's filesystem to the volume and mount the empty volume.<br /><br />A value is optional:<ul><li>`true` or `1`: Default if you do not provide a value. Disables copying.</li><li>`false` or `0`: Enables copying.</li></ul> |
|
304 |
-| **volume-opt** | Options specific to a given volume driver, which will be passed to the driver when creating the volume. Options are provided as a comma-separated list of key/value pairs, for example, `volume-opt=some-option=some-value,some-other-option=some-other-value`. For available options for a given driver, refer to that driver's documentation. |
|
300 |
+ |
|
301 |
+<table> |
|
302 |
+ <tr> |
|
303 |
+ <th>Option</th> |
|
304 |
+ <th>Description</th> |
|
305 |
+ </tr> |
|
306 |
+ <tr> |
|
307 |
+ <td><b>volume-driver</b></td> |
|
308 |
+ <td> |
|
309 |
+ <p>Name of the volume-driver plugin to use for the volume. Defaults to |
|
310 |
+ <tt>"local"</tt>, to use the local volume driver to create the volume if the |
|
311 |
+ volume does not exist.</p> |
|
312 |
+ </td> |
|
313 |
+ </tr> |
|
314 |
+ <tr> |
|
315 |
+ <td><b>volume-label</b></td> |
|
316 |
+ <td> |
|
317 |
+ One or more custom metadata ("labels") to apply to the volume upon |
|
318 |
+ creation. For example, |
|
319 |
+ `volume-label=mylabel=hello-world,my-other-label=hello-mars`. For more |
|
320 |
+ information about labels, refer to |
|
321 |
+ <a href="https://docs.docker.com/engine/userguide/labels-custom-metadata/">apply custom metadata</a>. |
|
322 |
+ </td> |
|
323 |
+ </tr> |
|
324 |
+ <tr> |
|
325 |
+ <td><b>volume-nocopy</b></td> |
|
326 |
+ <td> |
|
327 |
+ By default, if you attach an empty volume to a container, and files or |
|
328 |
+ directories already existed at the mount-path in the container (<tt>dst</tt>), |
|
329 |
+ the Engine copies those files and directories into the volume, allowing |
|
330 |
+ the host to access them. Set `volume-nocopy` to disables copying files |
|
331 |
+ from the container's filesystem to the volume and mount the empty volume. |
|
332 |
+ |
|
333 |
+ A value is optional: |
|
334 |
+ |
|
335 |
+ <ul> |
|
336 |
+ <li><tt>true</tt> or <tt>1</tt>: Default if you do not provide a value. Disables copying.</li> |
|
337 |
+ <li><tt>false</tt> or <tt>0</tt>: Enables copying.</li> |
|
338 |
+ </ul> |
|
339 |
+ </td> |
|
340 |
+ </tr> |
|
341 |
+ <tr> |
|
342 |
+ <td><b>volume-opt</b></td> |
|
343 |
+ <td> |
|
344 |
+ Options specific to a given volume driver, which will be passed to the |
|
345 |
+ driver when creating the volume. Options are provided as a comma-separated |
|
346 |
+ list of key/value pairs, for example, |
|
347 |
+ <tt>volume-opt=some-option=some-value,some-other-option=some-other-value</tt>. |
|
348 |
+ For available options for a given driver, refer to that driver's |
|
349 |
+ documentation. |
|
350 |
+ </td> |
|
351 |
+ </tr> |
|
352 |
+</table> |
|
353 |
+ |
|
305 | 354 |
|
306 | 355 |
#### Options for tmpfs |
356 |
+ |
|
307 | 357 |
The following options can only be used for tmpfs mounts (`type=tmpfs`); |
308 | 358 |
|
309 |
-| Option | Description |
|
310 |
-|:----------------------|:-------------------------------------------------------------------------------------------------------------------- |
|
311 |
-| **tmpfs-size** | Size of the tmpfs mount in bytes. Unlimited by default in Linux. |
|
312 |
-| **tmpfs-mode** | File mode of the tmpfs in octal. (e.g. `"700"` or `"0700"`.) Defaults to ``"1777"`` in Linux. |
|
359 |
+ |
|
360 |
+<table> |
|
361 |
+ <tr> |
|
362 |
+ <th>Option</th> |
|
363 |
+ <th>Description</th> |
|
364 |
+ </tr> |
|
365 |
+ <tr> |
|
366 |
+ <td><b>tmpfs-size</b></td> |
|
367 |
+ <td>Size of the tmpfs mount in bytes. Unlimited by default in Linux.</td> |
|
368 |
+ </tr> |
|
369 |
+ <tr> |
|
370 |
+ <td><b>tmpfs-mode</b></td> |
|
371 |
+ <td>File mode of the tmpfs in octal. (e.g. <tt>"700"</tt> or <tt>"0700"</tt>.) Defaults to <tt>"1777"</tt> in Linux.</td> |
|
372 |
+ </tr> |
|
373 |
+</table> |
|
374 |
+ |
|
313 | 375 |
|
314 | 376 |
#### Differences between "--mount" and "--volume" |
315 | 377 |
|
... | ... |
@@ -412,13 +531,40 @@ constraint expressions. Multiple constraints find nodes that satisfy every |
412 | 412 |
expression (AND match). Constraints can match node or Docker Engine labels as |
413 | 413 |
follows: |
414 | 414 |
|
415 |
-| node attribute | matches | example | |
|
416 |
-|:----------------|:--------------------------|:------------------------------------------------| |
|
417 |
-| node.id | node ID | `node.id == 2ivku8v2gvtg4` | |
|
418 |
-| node.hostname | node hostname | `node.hostname != node-2` | |
|
419 |
-| node.role | node role: manager | `node.role == manager` | |
|
420 |
-| node.labels | user defined node labels | `node.labels.security == high` | |
|
421 |
-| engine.labels | Docker Engine's labels | `engine.labels.operatingsystem == ubuntu 14.04` | |
|
415 |
+ |
|
416 |
+<table> |
|
417 |
+ <tr> |
|
418 |
+ <th>node attribute</th> |
|
419 |
+ <th>matches</th> |
|
420 |
+ <th>example</th> |
|
421 |
+ </tr> |
|
422 |
+ <tr> |
|
423 |
+ <td><tt>node.id</tt></td> |
|
424 |
+ <td>Node ID</td> |
|
425 |
+ <td><tt>node.id == 2ivku8v2gvtg4</tt></td> |
|
426 |
+ </tr> |
|
427 |
+ <tr> |
|
428 |
+ <td><tt>node.hostname</tt></td> |
|
429 |
+ <td>Node hostname</td> |
|
430 |
+ <td><tt>node.hostname != node-2</tt></td> |
|
431 |
+ </tr> |
|
432 |
+ <tr> |
|
433 |
+ <td<tt>node.role</tt></td> |
|
434 |
+ <td><tt>node role: manager</tt></td> |
|
435 |
+ <td><tt>node.role == manager</tt></td> |
|
436 |
+ </tr> |
|
437 |
+ <tr> |
|
438 |
+ <td><tt>node.labels</tt></td> |
|
439 |
+ <td>user defined node labels</td> |
|
440 |
+ <td><tt>node.labels.security == high</tt></td> |
|
441 |
+ </tr> |
|
442 |
+ <tr> |
|
443 |
+ <td><tt>engine.labels</tt></td> |
|
444 |
+ <td>Docker Engine's labels</td> |
|
445 |
+ <td><tt>engine.labels.operatingsystem == ubuntu 14.04</tt></td> |
|
446 |
+ </tr> |
|
447 |
+</table> |
|
448 |
+ |
|
422 | 449 |
|
423 | 450 |
`engine.labels` apply to Docker Engine labels like operating system, |
424 | 451 |
drivers, etc. Swarm administrators add `node.labels` for operational purposes by |
... | ... |
@@ -530,15 +676,42 @@ The supported flags are the following : |
530 | 530 |
|
531 | 531 |
Valid placeholders for the Go template are listed below: |
532 | 532 |
|
533 |
-Placeholder | Description |
|
534 |
-`.Service.ID` | Service ID |
|
535 |
-`.Service.Name` | Service name |
|
536 |
-`.Service.Labels` | Service labels |
|
537 |
-`.Node.ID` | Node ID |
|
538 |
-`.Task.ID` | Task ID |
|
539 |
-`.Task.Name` | Task name |
|
540 |
-`.Task.Slot` | Task slot |
|
533 |
+ |
|
534 |
+<table> |
|
535 |
+ <tr> |
|
536 |
+ <th>Placeholder</th> |
|
537 |
+ <th>Description</th> |
|
538 |
+ </tr> |
|
539 |
+ <tr> |
|
540 |
+ <td><tt>.Service.ID</tt></td> |
|
541 |
+ <td>Service ID</td> |
|
542 |
+ </tr> |
|
543 |
+ <tr> |
|
544 |
+ <td><tt>.Service.Name</tt></td> |
|
545 |
+ <td>Service name</td> |
|
546 |
+ </tr> |
|
547 |
+ <tr> |
|
548 |
+ <td><tt>.Service.Labels</tt></td> |
|
549 |
+ <td>Service labels</td> |
|
550 |
+ </tr> |
|
551 |
+ <tr> |
|
552 |
+ <td><tt>.Node.ID</tt></td> |
|
553 |
+ <td>Node ID</td> |
|
554 |
+ </tr> |
|
555 |
+ <tr> |
|
556 |
+ <td><tt>.Task.ID</tt></td> |
|
557 |
+ <td>Task ID</td> |
|
558 |
+ </tr> |
|
559 |
+ <tr> |
|
560 |
+ <td><tt>.Task.Name</tt></td> |
|
561 |
+ <td>Task name</td> |
|
562 |
+ </tr> |
|
563 |
+ <tr> |
|
564 |
+ <td><tt>.Task.Slot</tt></td> |
|
565 |
+ <td>Task slot</td> |
|
566 |
+ </tr> |
|
567 |
+</table> |
|
568 |
+ |
|
541 | 569 |
|
542 | 570 |
#### Template example |
543 | 571 |
|
... | ... |
@@ -27,12 +27,12 @@ Options: |
27 | 27 |
-q, --quiet Only display IDs |
28 | 28 |
``` |
29 | 29 |
|
30 |
-### Description |
|
30 |
+## Description |
|
31 | 31 |
|
32 | 32 |
Lists the services that are running as part of the specified stack. This |
33 | 33 |
command has to be run targeting a manager node. |
34 | 34 |
|
35 |
-### Examples |
|
35 |
+## Examples |
|
36 | 36 |
|
37 | 37 |
The following command shows all services in the `myapp` stack: |
38 | 38 |
|
... | ... |
@@ -15,6 +15,7 @@ import ( |
15 | 15 |
"time" |
16 | 16 |
|
17 | 17 |
"github.com/docker/docker/api/types" |
18 |
+ "github.com/docker/docker/api/types/container" |
|
18 | 19 |
"github.com/docker/docker/api/types/swarm" |
19 | 20 |
"github.com/docker/docker/pkg/integration/checker" |
20 | 21 |
"github.com/go-check/check" |
... | ... |
@@ -1365,3 +1366,26 @@ func (s *DockerSwarmSuite) TestAPIDuplicateNetworks(c *check.C) { |
1365 | 1365 |
|
1366 | 1366 |
c.Assert(r2.Scope, checker.Equals, "swarm") |
1367 | 1367 |
} |
1368 |
+ |
|
1369 |
+// Test case for 30178 |
|
1370 |
+func (s *DockerSwarmSuite) TestAPISwarmHealthcheckNone(c *check.C) { |
|
1371 |
+ d := s.AddDaemon(c, true, true) |
|
1372 |
+ |
|
1373 |
+ out, err := d.Cmd("network", "create", "-d", "overlay", "lb") |
|
1374 |
+ c.Assert(err, checker.IsNil, check.Commentf(out)) |
|
1375 |
+ |
|
1376 |
+ instances := 1 |
|
1377 |
+ d.createService(c, simpleTestService, setInstances(instances), func(s *swarm.Service) { |
|
1378 |
+ s.Spec.TaskTemplate.ContainerSpec.Healthcheck = &container.HealthConfig{} |
|
1379 |
+ s.Spec.TaskTemplate.Networks = []swarm.NetworkAttachmentConfig{ |
|
1380 |
+ {Target: "lb"}, |
|
1381 |
+ } |
|
1382 |
+ }) |
|
1383 |
+ |
|
1384 |
+ waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, instances) |
|
1385 |
+ |
|
1386 |
+ containers := d.activeContainers() |
|
1387 |
+ |
|
1388 |
+ out, err = d.Cmd("exec", containers[0], "ping", "-c1", "-W3", "top") |
|
1389 |
+ c.Assert(err, checker.IsNil, check.Commentf(out)) |
|
1390 |
+} |
... | ... |
@@ -398,14 +398,54 @@ func (s *DockerSuite) TestVolumeCLIRmForce(c *check.C) { |
398 | 398 |
out, _, err := runCommandWithOutput(exec.Command("rm", "-rf", path)) |
399 | 399 |
c.Assert(err, check.IsNil) |
400 | 400 |
|
401 |
- dockerCmd(c, "volume", "rm", "-f", "test") |
|
401 |
+ dockerCmd(c, "volume", "rm", "-f", name) |
|
402 | 402 |
out, _ = dockerCmd(c, "volume", "ls") |
403 | 403 |
c.Assert(out, checker.Not(checker.Contains), name) |
404 |
- dockerCmd(c, "volume", "create", "test") |
|
404 |
+ dockerCmd(c, "volume", "create", name) |
|
405 | 405 |
out, _ = dockerCmd(c, "volume", "ls") |
406 | 406 |
c.Assert(out, checker.Contains, name) |
407 | 407 |
} |
408 | 408 |
|
409 |
+// TestVolumeCLIRmForceInUse verifies that repeated `docker volume rm -f` calls does not remove a volume |
|
410 |
+// if it is in use. Test case for https://github.com/docker/docker/issues/31446 |
|
411 |
+func (s *DockerSuite) TestVolumeCLIRmForceInUse(c *check.C) { |
|
412 |
+ name := "testvolume" |
|
413 |
+ out, _ := dockerCmd(c, "volume", "create", name) |
|
414 |
+ id := strings.TrimSpace(out) |
|
415 |
+ c.Assert(id, checker.Equals, name) |
|
416 |
+ |
|
417 |
+ prefix, slash := getPrefixAndSlashFromDaemonPlatform() |
|
418 |
+ out, e := dockerCmd(c, "create", "-v", "testvolume:"+prefix+slash+"foo", "busybox") |
|
419 |
+ cid := strings.TrimSpace(out) |
|
420 |
+ |
|
421 |
+ _, _, err := dockerCmdWithError("volume", "rm", "-f", name) |
|
422 |
+ c.Assert(err, check.NotNil) |
|
423 |
+ c.Assert(err.Error(), checker.Contains, "volume is in use") |
|
424 |
+ out, _ = dockerCmd(c, "volume", "ls") |
|
425 |
+ c.Assert(out, checker.Contains, name) |
|
426 |
+ |
|
427 |
+ // The original issue did not _remove_ the volume from the list |
|
428 |
+ // the first time. But a second call to `volume rm` removed it. |
|
429 |
+ // Calling `volume rm` a second time to confirm it's not removed |
|
430 |
+ // when calling twice. |
|
431 |
+ _, _, err = dockerCmdWithError("volume", "rm", "-f", name) |
|
432 |
+ c.Assert(err, check.NotNil) |
|
433 |
+ c.Assert(err.Error(), checker.Contains, "volume is in use") |
|
434 |
+ out, _ = dockerCmd(c, "volume", "ls") |
|
435 |
+ c.Assert(out, checker.Contains, name) |
|
436 |
+ |
|
437 |
+ // Verify removing the volume after the container is removed works |
|
438 |
+ _, e = dockerCmd(c, "rm", cid) |
|
439 |
+ c.Assert(e, check.Equals, 0) |
|
440 |
+ |
|
441 |
+ _, e = dockerCmd(c, "volume", "rm", "-f", name) |
|
442 |
+ c.Assert(e, check.Equals, 0) |
|
443 |
+ |
|
444 |
+ out, e = dockerCmd(c, "volume", "ls") |
|
445 |
+ c.Assert(e, check.Equals, 0) |
|
446 |
+ c.Assert(out, checker.Not(checker.Contains), name) |
|
447 |
+} |
|
448 |
+ |
|
409 | 449 |
func (s *DockerSuite) TestVolumeCliInspectWithVolumeOpts(c *check.C) { |
410 | 450 |
testRequires(c, DaemonIsLinux) |
411 | 451 |
|
... | ... |
@@ -552,8 +552,22 @@ func (clnt *client) Stats(containerID string) (*Stats, error) { |
552 | 552 |
|
553 | 553 |
// Restore is the handler for restoring a container |
554 | 554 |
func (clnt *client) Restore(containerID string, _ StdioCallback, unusedOnWindows ...CreateOption) error { |
555 |
- // TODO Windows: Implement this. For now, just tell the backend the container exited. |
|
556 | 555 |
logrus.Debugf("libcontainerd: Restore(%s)", containerID) |
556 |
+ |
|
557 |
+ // TODO Windows: On RS1, a re-attach isn't possible. |
|
558 |
+ // However, there is a scenario in which there is an issue. |
|
559 |
+ // Consider a background container. The daemon dies unexpectedly. |
|
560 |
+ // HCS will still have the compute service alive and running. |
|
561 |
+ // For consistence, we call in to shoot it regardless if HCS knows about it |
|
562 |
+ // We explicitly just log a warning if the terminate fails. |
|
563 |
+ // Then we tell the backend the container exited. |
|
564 |
+ if hc, err := hcsshim.OpenContainer(containerID); err == nil { |
|
565 |
+ if err := hc.Terminate(); err != nil { |
|
566 |
+ if !hcsshim.IsPending(err) { |
|
567 |
+ logrus.Warnf("libcontainerd: failed to terminate %s on restore - %q", containerID, err) |
|
568 |
+ } |
|
569 |
+ } |
|
570 |
+ } |
|
557 | 571 |
return clnt.backend.StateChanged(containerID, StateInfo{ |
558 | 572 |
CommonStateInfo: CommonStateInfo{ |
559 | 573 |
State: StateExit, |