Browse code

Merge pull request #31754 from vieux/bump_17.03.1

bump to 17.03.1-rc1

Victor Vieux authored on 2017/03/14 15:25:41
Showing 22 changed files
... ...
@@ -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)
... ...
@@ -1 +1 @@
1
-17.03.0-ce
1
+17.03.1-ce-rc1
... ...
@@ -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
 }
... ...
@@ -74,7 +74,7 @@ The currently supported filters are:
74 74
 * id (network's id)
75 75
 * label (`label=<key>` or `label=<key>=<value>`)
76 76
 * name (network's name)
77
-* type (custom|builtin)
77
+* type (`custom|builtin`)
78 78
 
79 79
 #### Driver
80 80
 
... ...
@@ -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`&nbsp;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,