1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Merge pull request #31754 from vieux/bump_17.03.1

bump to 17.03.1-rc1
This commit is contained in:
Victor Vieux 2017-03-13 23:25:41 -07:00 committed by GitHub
commit 59c6eb8c2f
22 changed files with 453 additions and 107 deletions

View file

@ -5,6 +5,38 @@ information on the list of deprecated flags and APIs please have a look at
https://docs.docker.com/engine/deprecated/ where target removal dates can also https://docs.docker.com/engine/deprecated/ where target removal dates can also
be found. be found.
## 17.03.1-ce (2017-03-20)
### Remote API (v1.27) & Client
* Fix autoremove on older api [#31692](https://github.com/docker/docker/pull/31692)
* Fix default network customization for a stack [#31258](https://github.com/docker/docker/pull/31258/)
* Correct CPU usage calculation in presence of offline CPUs and newer Linux [#31802](https://github.com/docker/docker/pull/31802)
* Fix issue where service healthcheck is `{}` in remote API [#30197](https://github.com/docker/docker/pull/30197)
### Runtime
* Update runc to 54296cf40ad8143b62dbcaa1d90e520a2136ddfe [#3166](https://github.com/docker/docker/pull/31666)
* Ignore cgroup2 mountpoints [opencontainers/runc#1266](https://github.com/opencontainers/runc/pull/1266)
* Update containerd to 595e75c212d19a81d2b808a518fe1afc1391dad5 [#31662](https://github.com/docker/docker/pull/31662)
* Register healtcheck service before calling restore() [docker/containerd#609](https://github.com/docker/containerd/pull/609)
* Fix `docker exec` not working after unattended upgrades that reload apparmor profiles [#31773](https://github.com/docker/docker/pull/31773)
* Fix unmounting layer without merge dir with Overlay2 [#31069](https://github.com/docker/docker/pull/31069)
* Do not ignore "volume in use" errors when force-delete [#31450](https://github.com/docker/docker/pull/31450)
### Swarm Mode
* Update swarmkit to 17756457ad6dc4d8a639a1f0b7a85d1b65a617bb [#31807](https://github.com/docker/docker/pull/31807)
* 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)
* Allow removal of a network when only dead tasks reference it [docker/swarmkit#2018](https://github.com/docker/swarmkit/pull/2018)
* Retry failed network allocations less aggressively [docker/swarmkit#2021](https://github.com/docker/swarmkit/pull/2021)
* Avoid network allocation for tasks that are no longer running [docker/swarmkit#2017](https://github.com/docker/swarmkit/pull/2017)
* 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)
### Windows
* Cleanup HCS on restore [#31503](https://github.com/docker/docker/pull/31503)
## 17.03.0-ce (2017-03-01) ## 17.03.0-ce (2017-03-01)
**IMPORTANT**: Starting with this release, Docker is on a monthly release cycle and uses a **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.
### Swarm Mode ### Swarm Mode
* Shutdown leaks an error when the container was never started [#31279](https://github.com/docker/docker/pull/31279) * Shutdown leaks an error when the container was never started [#31279](https://github.com/docker/docker/pull/31279)
### Swarm Mode
* Fix possibility of tasks getting stuck in the "NEW" state during a leader failover [docker/swarmkit#1938](https://github.com/docker/swarmkit/pull/1938) * Fix possibility of tasks getting stuck in the "NEW" state during a leader failover [docker/swarmkit#1938](https://github.com/docker/swarmkit/pull/1938)
* 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) * 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)
* 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) * 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)

View file

@ -1 +1 @@
17.03.0-ce 17.03.1-ce-rc1

View file

@ -118,8 +118,6 @@ tags:
Run new commands inside running containers. See the [command-line reference](https://docs.docker.com/engine/reference/commandline/exec/) for more information. Run new commands inside running containers. See the [command-line reference](https://docs.docker.com/engine/reference/commandline/exec/) for more information.
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`. 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`.
- name: "Secret"
x-displayName: "Secrets"
# Swarm things # Swarm things
- name: "Swarm" - name: "Swarm"
x-displayName: "Swarm" x-displayName: "Swarm"
@ -137,6 +135,10 @@ tags:
x-displayName: "Tasks" x-displayName: "Tasks"
description: | description: |
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. 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.
- name: "Secret"
x-displayName: "Secrets"
description: |
Secrets are sensitive data that can be used by services. Swarm mode must be enabled for these endpoints to work.
# System things # System things
- name: "Plugin" - name: "Plugin"
x-displayName: "Plugins" x-displayName: "Plugins"

View file

@ -271,7 +271,7 @@ func prettyPrintInfo(dockerCli *command.DockerCli, info types.Info) error {
fmt.Fprintf(dockerCli.Out(), " %s\n", attribute) fmt.Fprintf(dockerCli.Out(), " %s\n", attribute)
} }
// TODO: Engine labels with duplicate keys has been deprecated in 1.13 and will be error out // TODO: Engine labels with duplicate keys has been deprecated in 1.13 and will be error out
// after 3 release cycles (1.16). For now, a WARNING will be generated. The following will // after 3 release cycles (17.12). For now, a WARNING will be generated. The following will
// be removed eventually. // be removed eventually.
labelMap := map[string]string{} labelMap := map[string]string{}
for _, label := range info.Labels { for _, label := range info.Labels {

View file

@ -17,6 +17,8 @@ import (
"github.com/docker/go-connections/nat" "github.com/docker/go-connections/nat"
) )
const defaultNetwork = "default"
// Services from compose-file types to engine API types // Services from compose-file types to engine API types
// TODO: fix secrets API so that SecretAPIClient is not required here // TODO: fix secrets API so that SecretAPIClient is not required here
func Services( func Services(
@ -157,18 +159,15 @@ func convertServiceNetworks(
name string, name string,
) ([]swarm.NetworkAttachmentConfig, error) { ) ([]swarm.NetworkAttachmentConfig, error) {
if len(networks) == 0 { if len(networks) == 0 {
return []swarm.NetworkAttachmentConfig{ networks = map[string]*composetypes.ServiceNetworkConfig{
{ defaultNetwork: {},
Target: namespace.Scope("default"), }
Aliases: []string{name},
},
}, nil
} }
nets := []swarm.NetworkAttachmentConfig{} nets := []swarm.NetworkAttachmentConfig{}
for networkName, network := range networks { for networkName, network := range networks {
networkConfig, ok := networkConfigs[networkName] networkConfig, ok := networkConfigs[networkName]
if !ok { if !ok && networkName != defaultNetwork {
return []swarm.NetworkAttachmentConfig{}, fmt.Errorf( return []swarm.NetworkAttachmentConfig{}, fmt.Errorf(
"service %q references network %q, which is not declared", name, networkName) "service %q references network %q, which is not declared", name, networkName)
} }

View file

@ -145,10 +145,9 @@ func TestConvertHealthcheckDisableWithTest(t *testing.T) {
func TestConvertServiceNetworksOnlyDefault(t *testing.T) { func TestConvertServiceNetworksOnlyDefault(t *testing.T) {
networkConfigs := networkMap{} networkConfigs := networkMap{}
networks := map[string]*composetypes.ServiceNetworkConfig{}
configs, err := convertServiceNetworks( configs, err := convertServiceNetworks(
networks, networkConfigs, NewNamespace("foo"), "service") nil, networkConfigs, NewNamespace("foo"), "service")
expected := []swarm.NetworkAttachmentConfig{ expected := []swarm.NetworkAttachmentConfig{
{ {
@ -201,6 +200,31 @@ func TestConvertServiceNetworks(t *testing.T) {
assert.DeepEqual(t, []swarm.NetworkAttachmentConfig(sortedConfigs), expected) assert.DeepEqual(t, []swarm.NetworkAttachmentConfig(sortedConfigs), expected)
} }
func TestConvertServiceNetworksCustomDefault(t *testing.T) {
networkConfigs := networkMap{
"default": composetypes.NetworkConfig{
External: composetypes.External{
External: true,
Name: "custom",
},
},
}
networks := map[string]*composetypes.ServiceNetworkConfig{}
configs, err := convertServiceNetworks(
networks, networkConfigs, NewNamespace("foo"), "service")
expected := []swarm.NetworkAttachmentConfig{
{
Target: "custom",
Aliases: []string{"service"},
},
}
assert.NilError(t, err)
assert.DeepEqual(t, []swarm.NetworkAttachmentConfig(configs), expected)
}
type byTargetSort []swarm.NetworkAttachmentConfig type byTargetSort []swarm.NetworkAttachmentConfig
func (s byTargetSort) Len() int { func (s byTargetSort) Len() int {

View file

@ -433,7 +433,7 @@ func loadDaemonCliConfig(opts daemonOptions) (*daemon.Config, error) {
// This is deprecated in 1.13, and, be removed after 3 release cycles. // This is deprecated in 1.13, and, be removed after 3 release cycles.
// The following will check the conflict of labels, and report a warning for deprecation. // The following will check the conflict of labels, and report a warning for deprecation.
// //
// TODO: After 3 release cycles (1.16) an error will be returned, and labels will be // TODO: After 3 release cycles (17.12) an error will be returned, and labels will be
// sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels): // sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels):
// //
// newLabels, err := daemon.GetConflictFreeLabels(config.Labels) // newLabels, err := daemon.GetConflictFreeLabels(config.Labels)

View file

@ -570,7 +570,7 @@ __docker_subcommands() {
$(__docker_to_extglob "$subcommands") ) $(__docker_to_extglob "$subcommands") )
subcommand_pos=$counter subcommand_pos=$counter
local subcommand=${words[$counter]} local subcommand=${words[$counter]}
local completions_func=_docker_${command}_${subcommand} local completions_func=_docker_${command}_${subcommand//-/_}
declare -F $completions_func >/dev/null && $completions_func declare -F $completions_func >/dev/null && $completions_func
return 0 return 0
;; ;;
@ -605,38 +605,25 @@ __docker_complete_local_interfaces() {
COMPREPLY=( $( compgen -W "$(__docker_local_interfaces) $additional_interface" -- "$cur" ) ) COMPREPLY=( $( compgen -W "$(__docker_local_interfaces) $additional_interface" -- "$cur" ) )
} }
__docker_complete_capabilities() { # __docker_complete_capabilities_addable completes Linux capabilities which are
# The list of capabilities is defined in types.go, ALL was added manually. # not granted by default and may be added.
# see https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities
__docker_complete_capabilities_addable() {
COMPREPLY=( $( compgen -W " COMPREPLY=( $( compgen -W "
ALL ALL
AUDIT_CONTROL AUDIT_CONTROL
AUDIT_WRITE
AUDIT_READ
BLOCK_SUSPEND BLOCK_SUSPEND
CHOWN
DAC_OVERRIDE
DAC_READ_SEARCH DAC_READ_SEARCH
FOWNER
FSETID
IPC_LOCK IPC_LOCK
IPC_OWNER IPC_OWNER
KILL
LEASE LEASE
LINUX_IMMUTABLE LINUX_IMMUTABLE
MAC_ADMIN MAC_ADMIN
MAC_OVERRIDE MAC_OVERRIDE
MKNOD
NET_ADMIN NET_ADMIN
NET_BIND_SERVICE
NET_BROADCAST NET_BROADCAST
NET_RAW
SETFCAP
SETGID
SETPCAP
SETUID
SYS_ADMIN SYS_ADMIN
SYS_BOOT SYS_BOOT
SYS_CHROOT
SYSLOG SYSLOG
SYS_MODULE SYS_MODULE
SYS_NICE SYS_NICE
@ -650,7 +637,30 @@ __docker_complete_capabilities() {
" -- "$cur" ) ) " -- "$cur" ) )
} }
__docker_complete_detach-keys() { # __docker_complete_capabilities_droppable completes Linux capability options which are
# allowed by default and can be dropped.
# see https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities
__docker_complete_capabilities_droppable() {
COMPREPLY=( $( compgen -W "
ALL
AUDIT_WRITE
CHOWN
DAC_OVERRIDE
FOWNER
FSETID
KILL
MKNOD
NET_BIND_SERVICE
NET_RAW
SETFCAP
SETGID
SETPCAP
SETUID
SYS_CHROOT
" -- "$cur" ) )
}
__docker_complete_detach_keys() {
case "$prev" in case "$prev" in
--detach-keys) --detach-keys)
case "$cur" in case "$cur" in
@ -1047,7 +1057,7 @@ _docker_container() {
} }
_docker_container_attach() { _docker_container_attach() {
__docker_complete_detach-keys && return __docker_complete_detach_keys && return
case "$cur" in case "$cur" in
-*) -*)
@ -1154,7 +1164,7 @@ _docker_container_diff() {
} }
_docker_container_exec() { _docker_container_exec() {
__docker_complete_detach-keys && return __docker_complete_detach_keys && return
case "$prev" in case "$prev" in
--env|-e) --env|-e)
@ -1498,7 +1508,7 @@ _docker_container_run() {
--rm --rm
--sig-proxy=false --sig-proxy=false
" "
__docker_complete_detach-keys && return __docker_complete_detach_keys && return
fi fi
local all_options="$options_with_args $boolean_options" local all_options="$options_with_args $boolean_options"
@ -1538,8 +1548,12 @@ _docker_container_run() {
COMPREPLY=( $( compgen -W 'stdin stdout stderr' -- "$cur" ) ) COMPREPLY=( $( compgen -W 'stdin stdout stderr' -- "$cur" ) )
return return
;; ;;
--cap-add|--cap-drop) --cap-add)
__docker_complete_capabilities __docker_complete_capabilities_addable
return
;;
--cap-drop)
__docker_complete_capabilities_droppable
return return
;; ;;
--cidfile|--env-file|--init-path|--label-file) --cidfile|--env-file|--init-path|--label-file)
@ -1686,7 +1700,7 @@ _docker_container_run() {
} }
_docker_container_start() { _docker_container_start() {
__docker_complete_detach-keys && return __docker_complete_detach_keys && return
case "$prev" in case "$prev" in
--checkpoint) --checkpoint)
@ -3141,7 +3155,7 @@ _docker_swarm_join() {
esac esac
} }
_docker_swarm_join-token() { _docker_swarm_join_token() {
case "$cur" in case "$cur" in
-*) -*)
COMPREPLY=( $( compgen -W "--help --quiet -q --rotate" -- "$cur" ) ) COMPREPLY=( $( compgen -W "--help --quiet -q --rotate" -- "$cur" ) )
@ -3171,7 +3185,7 @@ _docker_swarm_unlock() {
esac esac
} }
_docker_swarm_unlock-key() { _docker_swarm_unlock_key() {
case "$cur" in case "$cur" in
-*) -*)
COMPREPLY=( $( compgen -W "--help --quiet -q --rotate" -- "$cur" ) ) COMPREPLY=( $( compgen -W "--help --quiet -q --rotate" -- "$cur" ) )
@ -4289,7 +4303,7 @@ _docker() {
command_pos=0 command_pos=0
fi fi
local completions_func=_docker_${command} local completions_func=_docker_${command//-/_}
declare -F $completions_func >/dev/null && $completions_func declare -F $completions_func >/dev/null && $completions_func
eval "$previous_extglob_setting" eval "$previous_extglob_setting"

View file

@ -205,7 +205,7 @@ func (r *controller) Start(ctx context.Context) error {
} }
// no health check // no health check
if ctnr.Config == nil || ctnr.Config.Healthcheck == nil { if ctnr.Config == nil || ctnr.Config.Healthcheck == nil || len(ctnr.Config.Healthcheck.Test) == 0 || ctnr.Config.Healthcheck.Test[0] == "NONE" {
if err := r.adapter.activateServiceBinding(); err != nil { if err := r.adapter.activateServiceBinding(); err != nil {
log.G(ctx).WithError(err).Errorf("failed to activate service binding for container %s which has no healthcheck config", r.adapter.container.name()) log.G(ctx).WithError(err).Errorf("failed to activate service binding for container %s which has no healthcheck config", r.adapter.container.name())
return err return err
@ -213,12 +213,6 @@ func (r *controller) Start(ctx context.Context) error {
return nil return nil
} }
healthCmd := ctnr.Config.Healthcheck.Test
if len(healthCmd) == 0 || healthCmd[0] == "NONE" {
return nil
}
// wait for container to be healthy // wait for container to be healthy
eventq := r.adapter.events(ctx) eventq := r.adapter.events(ctx)

View file

@ -279,7 +279,7 @@ func ReloadConfiguration(configFile string, flags *pflag.FlagSet, reload func(*C
// This is deprecated in 1.13, and, be removed after 3 release cycles. // This is deprecated in 1.13, and, be removed after 3 release cycles.
// The following will check the conflict of labels, and report a warning for deprecation. // The following will check the conflict of labels, and report a warning for deprecation.
// //
// TODO: After 3 release cycles (1.16) an error will be returned, and labels will be // TODO: After 3 release cycles (17.12) an error will be returned, and labels will be
// sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels): // sanitized to consolidate duplicate key-value pairs (config.Labels = newLabels):
// //
// newLabels, err := GetConflictFreeLabels(newConfig.Labels) // newLabels, err := GetConflictFreeLabels(newConfig.Labels)

View file

@ -8,11 +8,12 @@ import (
"time" "time"
"github.com/Sirupsen/logrus" "github.com/Sirupsen/logrus"
"github.com/docker/docker/api/errors" apierrors "github.com/docker/docker/api/errors"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/container" "github.com/docker/docker/container"
"github.com/docker/docker/layer" "github.com/docker/docker/layer"
volumestore "github.com/docker/docker/volume/store" volumestore "github.com/docker/docker/volume/store"
"github.com/pkg/errors"
) )
// ContainerRm removes the container id from the filesystem. An error // ContainerRm removes the container id from the filesystem. An error
@ -29,7 +30,7 @@ func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig)
// Container state RemovalInProgress should be used to avoid races. // Container state RemovalInProgress should be used to avoid races.
if inProgress := container.SetRemovalInProgress(); inProgress { if inProgress := container.SetRemovalInProgress(); inProgress {
err := fmt.Errorf("removal of container %s is already in progress", name) err := fmt.Errorf("removal of container %s is already in progress", name)
return errors.NewBadRequestError(err) return apierrors.NewBadRequestError(err)
} }
defer container.ResetRemovalInProgress() defer container.ResetRemovalInProgress()
@ -80,7 +81,7 @@ func (daemon *Daemon) cleanupContainer(container *container.Container, forceRemo
if container.IsRunning() { if container.IsRunning() {
if !forceRemove { if !forceRemove {
err := fmt.Errorf("You cannot remove a running container %s. Stop the container before attempting removal or use -f", container.ID) err := fmt.Errorf("You cannot remove a running container %s. Stop the container before attempting removal or use -f", container.ID)
return errors.NewRequestConflictError(err) return apierrors.NewRequestConflictError(err)
} }
if err := daemon.Kill(container); err != nil { if err := daemon.Kill(container); err != nil {
return fmt.Errorf("Could not kill running container %s, cannot remove - %v", container.ID, err) 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
// This is called directly from the Engine API // This is called directly from the Engine API
func (daemon *Daemon) VolumeRm(name string, force bool) error { func (daemon *Daemon) VolumeRm(name string, force bool) error {
err := daemon.volumeRm(name) err := daemon.volumeRm(name)
if err != nil && volumestore.IsInUse(err) {
return apierrors.NewRequestConflictError(err)
}
if err == nil || force { if err == nil || force {
daemon.volumes.Purge(name) daemon.volumes.Purge(name)
return nil return nil
@ -157,11 +161,7 @@ func (daemon *Daemon) volumeRm(name string) error {
} }
if err := daemon.volumes.Remove(v); err != nil { if err := daemon.volumes.Remove(v); err != nil {
if volumestore.IsInUse(err) { return errors.Wrap(err, "unable to remove volume")
err := fmt.Errorf("Unable to remove volume, volume still in use: %v", err)
return errors.NewRequestConflictError(err)
}
return fmt.Errorf("Error while removing volume %s: %v", name, err)
} }
daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()}) daemon.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()})
return nil return nil

View file

@ -5,6 +5,7 @@ import (
"github.com/docker/docker/daemon/caps" "github.com/docker/docker/daemon/caps"
"github.com/docker/docker/daemon/exec" "github.com/docker/docker/daemon/exec"
"github.com/docker/docker/libcontainerd" "github.com/docker/docker/libcontainerd"
"github.com/opencontainers/runc/libcontainer/apparmor"
"github.com/opencontainers/runtime-spec/specs-go" "github.com/opencontainers/runtime-spec/specs-go"
) )
@ -23,5 +24,27 @@ func execSetPlatformOpt(c *container.Container, ec *exec.Config, p *libcontainer
if ec.Privileged { if ec.Privileged {
p.Capabilities = caps.GetAllCapabilities() p.Capabilities = caps.GetAllCapabilities()
} }
if apparmor.IsEnabled() {
var appArmorProfile string
if c.AppArmorProfile != "" {
appArmorProfile = c.AppArmorProfile
} else if c.HostConfig.Privileged {
appArmorProfile = "unconfined"
} else {
appArmorProfile = "docker-default"
}
if appArmorProfile == "docker-default" {
// Unattended upgrades and other fun services can unload AppArmor
// profiles inadvertently. Since we cannot store our profile in
// /etc/apparmor.d, nor can we practically add other ways of
// telling the system to keep our profile loaded, in order to make
// sure that we keep the default profile enabled we dynamically
// reload it if necessary.
if err := ensureDefaultAppArmorProfile(); err != nil {
return err
}
}
}
return nil return nil
} }

View file

@ -144,7 +144,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, err return nil, err
} }
if !supportsDType { if !supportsDType {
// not a fatal error until v1.16 (#27443) // not a fatal error until v17.12 (#27443)
logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay", backingFs)) logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay", backingFs))
} }

View file

@ -30,7 +30,7 @@ import (
"github.com/docker/docker/pkg/mount" "github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/parsers" "github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/parsers/kernel" "github.com/docker/docker/pkg/parsers/kernel"
"github.com/docker/go-units" units "github.com/docker/go-units"
"github.com/opencontainers/runc/libcontainer/label" "github.com/opencontainers/runc/libcontainer/label"
) )
@ -170,7 +170,7 @@ func Init(home string, options []string, uidMaps, gidMaps []idtools.IDMap) (grap
return nil, err return nil, err
} }
if !supportsDType { if !supportsDType {
// not a fatal error until v1.16 (#27443) // not a fatal error until v17.12 (#27443)
logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay2", backingFs)) logrus.Warn(overlayutils.ErrDTypeNotSupported("overlay2", backingFs))
} }
@ -553,7 +553,17 @@ func (d *Driver) Get(id string, mountLabel string) (s string, err error) {
// Put unmounts the mount path created for the give id. // Put unmounts the mount path created for the give id.
func (d *Driver) Put(id string) error { func (d *Driver) Put(id string) error {
mountpoint := path.Join(d.dir(id), "merged") dir := d.dir(id)
_, err := ioutil.ReadFile(path.Join(dir, lowerFile))
if err != nil {
// If no lower, no mount happened and just return directly
if os.IsNotExist(err) {
return nil
}
return err
}
mountpoint := path.Join(dir, "merged")
if count := d.ctr.Decrement(mountpoint); count > 0 { if count := d.ctr.Decrement(mountpoint); count > 0 {
return nil return nil
} }

View file

@ -13,6 +13,6 @@ func ErrDTypeNotSupported(driver, backingFs string) error {
if backingFs == "xfs" { if backingFs == "xfs" {
msg += " Reformat the filesystem with ftype=1 to enable d_type support." msg += " Reformat the filesystem with ftype=1 to enable d_type support."
} }
msg += " Running without d_type support will no longer be supported in Docker 1.16." msg += " Running without d_type support will no longer be supported in Docker 17.12."
return errors.New(msg) return errors.New(msg)
} }

View file

@ -74,7 +74,7 @@ The currently supported filters are:
* id (network's id) * id (network's id)
* label (`label=<key>` or `label=<key>=<value>`) * label (`label=<key>` or `label=<key>=<value>`)
* name (network's name) * name (network's name)
* type (custom|builtin) * type (`custom|builtin`)
#### Driver #### Driver

View file

@ -35,7 +35,7 @@ Options:
- name=<string> a container's name - name=<string> a container's name
- network=(<network-id>|<network-name>) - network=(<network-id>|<network-name>)
- since=(<container-name>|<container-id>) - since=(<container-name>|<container-id>)
- status=(created|restarting|removing|running|paused|exited) - status=(created|restarting|removing|running|paused|exited)
- volume=(<volume name>|<mount point destination>) - volume=(<volume name>|<mount point destination>)
--format string Pretty-print containers using a Go template --format string Pretty-print containers using a Go template
--help Print usage --help Print usage
@ -84,11 +84,11 @@ The currently supported filters are:
* label (`label=<key>` or `label=<key>=<value>`) * label (`label=<key>` or `label=<key>=<value>`)
* name (container's name) * name (container's name)
* exited (int - the code of exited containers. Only useful with `--all`) * exited (int - the code of exited containers. Only useful with `--all`)
* status (created|restarting|running|removing|paused|exited|dead) * status (`created|restarting|running|removing|paused|exited|dead`)
* ancestor (`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) - filters containers that were created from the given image or a descendant. * ancestor (`<image-name>[:<tag>]`, `<image id>` or `<image@digest>`) - filters containers that were created from the given image or a descendant.
* before (container's id or name) - filters containers created before given id or name * before (container's id or name) - filters containers created before given id or name
* since (container's id or name) - filters containers created since given id or name * since (container's id or name) - filters containers created since given id or name
* isolation (default|process|hyperv) (Windows daemon only) * isolation (`default|process|hyperv`) (Windows daemon only)
* volume (volume name or mount point) - filters containers that mount volumes. * volume (volume name or mount point) - filters containers that mount volumes.
* network (network id or name) - filters containers connected to the provided network * network (network id or name) - filters containers connected to the provided network
* health (starting|healthy|unhealthy|none) - filters containers based on healthcheck status * health (starting|healthy|unhealthy|none) - filters containers based on healthcheck status

View file

@ -249,12 +249,69 @@ For more information about named volumes, see
The following table describes options which apply to both bind-mounts and named The following table describes options which apply to both bind-mounts and named
volumes in a service: volumes in a service:
| Option | Required | Description <table>
|:-----------------------------------------|:--------------------------|:----------------------------------------------------------------------------------------- <tr>
| **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> <th>Option</th>
| **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> <th>Required</th>
| **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. <th>Description</th>
| **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> </tr>
<tr>
<td><b>types</b></td>
<td></td>
<td>
<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.
<ul>
<li><tt>volume</tt>: mounts a [managed volume](volume_create.md) into the container.</li>
<li><tt>bind</tt>: bind-mounts a directory or file from the host into the container.</li>
<li><tt>tmpfs</tt>: mount a tmpfs in the container</li>
</ul></p>
</td>
</tr>
<tr>
<td><b>src</b> or <b>source</b></td>
<td>for <tt>type=bind</tt> only></td>
<td>
<ul>
<li>
<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>).
If the named volume does not exist, it is automatically created. If no <tt>src</tt> 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 <i>container</i>
is destroyed (which is upon <tt>service update</tt>, or when scaling or re-balancing the service)
</li>
<li>
<tt>type=bind</tt>: <tt>src</tt> is required, and specifies an absolute path to the file or directory to bind-mount
(for example, <tt>src=/path/on/host/</tt>). An error is produced if the file or directory does not exist.
</li>
<li>
<tt>type=tmpfs</tt>: <tt>src</tt> is not supported.
</li>
</ul>
</td>
</tr>
<tr>
<td><p><b>dst</b> or <b>destination</b> or <b>target</b></p></td>
<td>yes</td>
<td>
<p>Mount path inside the container, for example <tt>/some/path/in/container/</tt>.
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.</p>
</td>
</tr>
<tr>
<td><p><b>readonly</b> or <b>ro</b></p></td>
<td></td>
<td>
<p>The Engine mounts binds and volumes <tt>read-write</tt> unless <tt>readonly</tt> option
is given when mounting the bind or volume.
<ul>
<li><tt>true</tt> or <tt>1</tt> or no value: Mounts the bind or volume read-only.</li>
<li><tt>false</tt> or <tt>0</tt>: Mounts the bind or volume read-write.</li>
</ul></p>
</td>
</tr>
</table>
#### Bind Propagation #### Bind Propagation
@ -294,22 +351,84 @@ For more information about bind propagation, see the
[Linux kernel documentation for shared subtree](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt). [Linux kernel documentation for shared subtree](https://www.kernel.org/doc/Documentation/filesystems/sharedsubtree.txt).
#### Options for Named Volumes #### Options for Named Volumes
The following options can only be used for named volumes (`type=volume`); The following options can only be used for named volumes (`type=volume`);
| Option | Description
|:----------------------|:-------------------------------------------------------------------------------------------------------------------- <table>
| **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. <tr>
| **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/). <th>Option</th>
| **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> <th>Description</th>
| **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. </tr>
<tr>
<td><b>volume-driver</b></td>
<td>
<p>Name of the volume-driver plugin to use for the volume. Defaults to
<tt>"local"</tt>, to use the local volume driver to create the volume if the
volume does not exist.</p>
</td>
</tr>
<tr>
<td><b>volume-label</b></td>
<td>
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
<a href="https://docs.docker.com/engine/userguide/labels-custom-metadata/">apply custom metadata</a>.
</td>
</tr>
<tr>
<td><b>volume-nocopy</b></td>
<td>
By default, if you attach an empty volume to a container, and files or
directories already existed at the mount-path in the container (<tt>dst</tt>),
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.
A value is optional:
<ul>
<li><tt>true</tt> or <tt>1</tt>: Default if you do not provide a value. Disables copying.</li>
<li><tt>false</tt> or <tt>0</tt>: Enables copying.</li>
</ul>
</td>
</tr>
<tr>
<td><b>volume-opt</b></td>
<td>
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,
<tt>volume-opt=some-option=some-value,some-other-option=some-other-value</tt>.
For available options for a given driver, refer to that driver's
documentation.
</td>
</tr>
</table>
#### Options for tmpfs #### Options for tmpfs
The following options can only be used for tmpfs mounts (`type=tmpfs`); The following options can only be used for tmpfs mounts (`type=tmpfs`);
| Option | Description
|:----------------------|:-------------------------------------------------------------------------------------------------------------------- <table>
| **tmpfs-size** | Size of the tmpfs mount in bytes. Unlimited by default in Linux. <tr>
| **tmpfs-mode** | File mode of the tmpfs in octal. (e.g. `"700"` or `"0700"`.) Defaults to ``"1777"`` in Linux. <th>Option</th>
<th>Description</th>
</tr>
<tr>
<td><b>tmpfs-size</b></td>
<td>Size of the tmpfs mount in bytes. Unlimited by default in Linux.</td>
</tr>
<tr>
<td><b>tmpfs-mode</b></td>
<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>
</tr>
</table>
#### Differences between "--mount" and "--volume" #### Differences between "--mount" and "--volume"
@ -412,13 +531,40 @@ constraint expressions. Multiple constraints find nodes that satisfy every
expression (AND match). Constraints can match node or Docker Engine labels as expression (AND match). Constraints can match node or Docker Engine labels as
follows: follows:
| node attribute | matches | example |
|:----------------|:--------------------------|:------------------------------------------------| <table>
| node.id | node ID | `node.id == 2ivku8v2gvtg4` | <tr>
| node.hostname | node hostname | `node.hostname != node-2` | <th>node attribute</th>
| node.role | node role: manager | `node.role == manager` | <th>matches</th>
| node.labels | user defined node labels | `node.labels.security == high` | <th>example</th>
| engine.labels | Docker Engine's labels | `engine.labels.operatingsystem == ubuntu 14.04` | </tr>
<tr>
<td><tt>node.id</tt></td>
<td>Node ID</td>
<td><tt>node.id == 2ivku8v2gvtg4</tt></td>
</tr>
<tr>
<td><tt>node.hostname</tt></td>
<td>Node hostname</td>
<td><tt>node.hostname != node-2</tt></td>
</tr>
<tr>
<td<tt>node.role</tt></td>
<td><tt>node role: manager</tt></td>
<td><tt>node.role == manager</tt></td>
</tr>
<tr>
<td><tt>node.labels</tt></td>
<td>user defined node labels</td>
<td><tt>node.labels.security == high</tt></td>
</tr>
<tr>
<td><tt>engine.labels</tt></td>
<td>Docker Engine's labels</td>
<td><tt>engine.labels.operatingsystem == ubuntu 14.04</tt></td>
</tr>
</table>
`engine.labels` apply to Docker Engine labels like operating system, `engine.labels` apply to Docker Engine labels like operating system,
drivers, etc. Swarm administrators add `node.labels` for operational purposes by drivers, etc. Swarm administrators add `node.labels` for operational purposes by
@ -530,15 +676,42 @@ The supported flags are the following :
Valid placeholders for the Go template are listed below: Valid placeholders for the Go template are listed below:
Placeholder | Description
----------------- | -------------------------------------------- <table>
`.Service.ID` | Service ID <tr>
`.Service.Name` | Service name <th>Placeholder</th>
`.Service.Labels` | Service labels <th>Description</th>
`.Node.ID` | Node ID </tr>
`.Task.ID` | Task ID <tr>
`.Task.Name` | Task name <td><tt>.Service.ID</tt></td>
`.Task.Slot` | Task slot <td>Service ID</td>
</tr>
<tr>
<td><tt>.Service.Name</tt></td>
<td>Service name</td>
</tr>
<tr>
<td><tt>.Service.Labels</tt></td>
<td>Service labels</td>
</tr>
<tr>
<td><tt>.Node.ID</tt></td>
<td>Node ID</td>
</tr>
<tr>
<td><tt>.Task.ID</tt></td>
<td>Task ID</td>
</tr>
<tr>
<td><tt>.Task.Name</tt></td>
<td>Task name</td>
</tr>
<tr>
<td><tt>.Task.Slot</tt></td>
<td>Task slot</td>
</tr>
</table>
#### Template example #### Template example

View file

@ -27,12 +27,12 @@ Options:
-q, --quiet Only display IDs -q, --quiet Only display IDs
``` ```
### Description ## Description
Lists the services that are running as part of the specified stack. This Lists the services that are running as part of the specified stack. This
command has to be run targeting a manager node. command has to be run targeting a manager node.
### Examples ## Examples
The following command shows all services in the `myapp` stack: The following command shows all services in the `myapp` stack:

View file

@ -15,6 +15,7 @@ import (
"time" "time"
"github.com/docker/docker/api/types" "github.com/docker/docker/api/types"
"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/swarm" "github.com/docker/docker/api/types/swarm"
"github.com/docker/docker/pkg/integration/checker" "github.com/docker/docker/pkg/integration/checker"
"github.com/go-check/check" "github.com/go-check/check"
@ -1365,3 +1366,26 @@ func (s *DockerSwarmSuite) TestAPIDuplicateNetworks(c *check.C) {
c.Assert(r2.Scope, checker.Equals, "swarm") c.Assert(r2.Scope, checker.Equals, "swarm")
} }
// Test case for 30178
func (s *DockerSwarmSuite) TestAPISwarmHealthcheckNone(c *check.C) {
d := s.AddDaemon(c, true, true)
out, err := d.Cmd("network", "create", "-d", "overlay", "lb")
c.Assert(err, checker.IsNil, check.Commentf(out))
instances := 1
d.createService(c, simpleTestService, setInstances(instances), func(s *swarm.Service) {
s.Spec.TaskTemplate.ContainerSpec.Healthcheck = &container.HealthConfig{}
s.Spec.TaskTemplate.Networks = []swarm.NetworkAttachmentConfig{
{Target: "lb"},
}
})
waitAndAssert(c, defaultReconciliationTimeout, d.checkActiveContainerCount, checker.Equals, instances)
containers := d.activeContainers()
out, err = d.Cmd("exec", containers[0], "ping", "-c1", "-W3", "top")
c.Assert(err, checker.IsNil, check.Commentf(out))
}

View file

@ -398,14 +398,54 @@ func (s *DockerSuite) TestVolumeCLIRmForce(c *check.C) {
out, _, err := runCommandWithOutput(exec.Command("rm", "-rf", path)) out, _, err := runCommandWithOutput(exec.Command("rm", "-rf", path))
c.Assert(err, check.IsNil) c.Assert(err, check.IsNil)
dockerCmd(c, "volume", "rm", "-f", "test") dockerCmd(c, "volume", "rm", "-f", name)
out, _ = dockerCmd(c, "volume", "ls") out, _ = dockerCmd(c, "volume", "ls")
c.Assert(out, checker.Not(checker.Contains), name) c.Assert(out, checker.Not(checker.Contains), name)
dockerCmd(c, "volume", "create", "test") dockerCmd(c, "volume", "create", name)
out, _ = dockerCmd(c, "volume", "ls") out, _ = dockerCmd(c, "volume", "ls")
c.Assert(out, checker.Contains, name) c.Assert(out, checker.Contains, name)
} }
// TestVolumeCLIRmForceInUse verifies that repeated `docker volume rm -f` calls does not remove a volume
// if it is in use. Test case for https://github.com/docker/docker/issues/31446
func (s *DockerSuite) TestVolumeCLIRmForceInUse(c *check.C) {
name := "testvolume"
out, _ := dockerCmd(c, "volume", "create", name)
id := strings.TrimSpace(out)
c.Assert(id, checker.Equals, name)
prefix, slash := getPrefixAndSlashFromDaemonPlatform()
out, e := dockerCmd(c, "create", "-v", "testvolume:"+prefix+slash+"foo", "busybox")
cid := strings.TrimSpace(out)
_, _, err := dockerCmdWithError("volume", "rm", "-f", name)
c.Assert(err, check.NotNil)
c.Assert(err.Error(), checker.Contains, "volume is in use")
out, _ = dockerCmd(c, "volume", "ls")
c.Assert(out, checker.Contains, name)
// The original issue did not _remove_ the volume from the list
// the first time. But a second call to `volume rm` removed it.
// Calling `volume rm` a second time to confirm it's not removed
// when calling twice.
_, _, err = dockerCmdWithError("volume", "rm", "-f", name)
c.Assert(err, check.NotNil)
c.Assert(err.Error(), checker.Contains, "volume is in use")
out, _ = dockerCmd(c, "volume", "ls")
c.Assert(out, checker.Contains, name)
// Verify removing the volume after the container is removed works
_, e = dockerCmd(c, "rm", cid)
c.Assert(e, check.Equals, 0)
_, e = dockerCmd(c, "volume", "rm", "-f", name)
c.Assert(e, check.Equals, 0)
out, e = dockerCmd(c, "volume", "ls")
c.Assert(e, check.Equals, 0)
c.Assert(out, checker.Not(checker.Contains), name)
}
func (s *DockerSuite) TestVolumeCliInspectWithVolumeOpts(c *check.C) { func (s *DockerSuite) TestVolumeCliInspectWithVolumeOpts(c *check.C) {
testRequires(c, DaemonIsLinux) testRequires(c, DaemonIsLinux)

View file

@ -552,8 +552,22 @@ func (clnt *client) Stats(containerID string) (*Stats, error) {
// Restore is the handler for restoring a container // Restore is the handler for restoring a container
func (clnt *client) Restore(containerID string, _ StdioCallback, unusedOnWindows ...CreateOption) error { func (clnt *client) Restore(containerID string, _ StdioCallback, unusedOnWindows ...CreateOption) error {
// TODO Windows: Implement this. For now, just tell the backend the container exited.
logrus.Debugf("libcontainerd: Restore(%s)", containerID) logrus.Debugf("libcontainerd: Restore(%s)", containerID)
// TODO Windows: On RS1, a re-attach isn't possible.
// However, there is a scenario in which there is an issue.
// Consider a background container. The daemon dies unexpectedly.
// HCS will still have the compute service alive and running.
// For consistence, we call in to shoot it regardless if HCS knows about it
// We explicitly just log a warning if the terminate fails.
// Then we tell the backend the container exited.
if hc, err := hcsshim.OpenContainer(containerID); err == nil {
if err := hc.Terminate(); err != nil {
if !hcsshim.IsPending(err) {
logrus.Warnf("libcontainerd: failed to terminate %s on restore - %q", containerID, err)
}
}
}
return clnt.backend.StateChanged(containerID, StateInfo{ return clnt.backend.StateChanged(containerID, StateInfo{
CommonStateInfo: CommonStateInfo{ CommonStateInfo: CommonStateInfo{
State: StateExit, State: StateExit,