Compare commits

...

254 Commits

Author SHA1 Message Date
Tibor Vass
9968dd63a4 Bump version to 1.10.3-rc2
Signed-off-by: Tibor Vass <tibor@docker.com>
2016-03-09 15:34:00 -05:00
Tibor Vass
20f81dde9b Merge pull request #21068 from tiborvass/revert-commits-from-1.10.3-rc1
Revert 3 commits from 1.10.3 rc1
2016-03-09 15:13:24 -05:00
Tibor Vass
320d17b2a2 Update CHANGELOG with reverts
Signed-off-by: Tibor Vass <tibor@docker.com>
2016-03-09 13:38:57 -05:00
Tibor Vass
0dbbaf76ab Revert "Use multiple keyservers in install script"
This reverts commit 4b2e7f0562.

Signed-off-by: Tibor Vass <tibor@docker.com>
2016-03-09 13:32:18 -05:00
Tibor Vass
0e4f9457c0 Revert "Do not wait for container on stop if the process doesn't exist."
This reverts commit 1a10104d85.

Signed-off-by: Tibor Vass <tibor@docker.com>
2016-03-09 13:31:32 -05:00
Tibor Vass
f4dd90f40a Revert "Add synchronization and closure to IO pipes in userns path"
This reverts commit 54ab6ff79e.

Signed-off-by: Tibor Vass <tibor@docker.com>
2016-03-09 13:29:42 -05:00
Tibor Vass
1b61e3a90d Merge pull request #21038 from jfrazelle/patch-for-bump
[bump_branch]: only add the suites that exist we dont need the script for this
2016-03-08 15:01:22 -05:00
Jessica Frazelle
5803516ec4 only add the suites that exist we dont need the script for this
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
2016-03-08 11:38:30 -08:00
Tibor Vass
0fc4a0d165 Merge pull request #21030 from runcom/fix-daemon-panic
distribution: registry: do not access the errors slice if it's empty
2016-03-08 11:44:12 -05:00
Antonio Murdaca
0186f4d422 distribution: registry: do not access the errors slice if it's empty
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
2016-03-08 16:04:34 +01:00
Tibor Vass
831238928c Merge pull request #21011 from tiborvass/1.10.3-cherrypicks
1.10.3 cherrypicks
2016-03-08 06:52:57 -05:00
Tibor Vass
f334602538 Update CHANGELOG for 1.10.3
Signed-off-by: Tibor Vass <tibor@docker.com>
2016-03-07 23:54:30 -05:00
Tibor Vass
e1211c7325 Support TLS remote test daemon
This will allow us to have a windows-to-linux CI, where the linux host
can be anywhere, connecting with TLS.

Signed-off-by: Tibor Vass <tibor@docker.com>
(cherry picked from commit f4a1e3db99)
2016-03-07 23:54:29 -05:00
David Calavera
1a10104d85 Do not wait for container on stop if the process doesn't exist.
This fixes an issue that caused the client to hang forever if the
process died before the code arrived to exit the `Kill` function.

Signed-off-by: David Calavera <david.calavera@gmail.com>
(cherry picked from commit 1a729c3dd8)
2016-03-07 18:15:29 -05:00
Justin Cormack
ac47ad8ea4 Add some uses of personality syscall to default seccomp filter
We generally want to filter the personality(2) syscall, as it
allows disabling ASLR, and turning on some poorly supported
emulations that have been the target of CVEs. However the use
cases for reading the current value, setting the default
PER_LINUX personality, and setting PER_LINUX32 for 32 bit
emulation are fine.

See issue #20634

Signed-off-by: Justin Cormack <justin.cormack@docker.com>
(cherry picked from commit 39b799ac53)
2016-03-07 16:36:41 -05:00
Justin Cormack
eceeae4d7c Add ipc syscall to default seccomp profile
On 32 bit x86 this is a multiplexing syscall for the system V
ipc syscalls such as shmget, and so needs to be allowed for
shared memory access for 32 bit binaries.

Fixes #20733

Signed-off-by: Justin Cormack <justin.cormack@docker.com>
(cherry picked from commit 31410a6d79)
2016-03-07 16:33:09 -05:00
Dan Walsh
516ef83f30 Do not relabel if user did not request it for non local volumes
Signed-off-by: Dan Walsh <dwalsh@redhat.com>
(cherry picked from commit 843a119d49)
2016-03-07 16:31:31 -05:00
Aaron Lehmann
f05d42ee03 Fix concurrent uploads that share layers
Concurrent uploads which share layers worked correctly as of #18353,
but unfortunately #18785 caused a regression. This PR removed the logic
that shares digests between different push sessions. This overlooked the
case where one session was waiting for another session to upload a
layer.

This commit adds back the ability to propagate this digest information,
using the distribution.Descriptor type because this is what is received
from stats and uploads, and also what is ultimately needed for building
the manifest.

Surprisingly, there was no test covering this case. This commit adds
one. It fails without the fix.

See recent comments on #9132.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
(cherry picked from commit 5c99eebe81)
2016-03-07 16:30:52 -05:00
Mike Dougherty
4b2e7f0562 Use multiple keyservers in install script
This improves on an earlier change by adding another keyserver and using a for loop instead of duplicating the command

Signed-off-by: Mike Dougherty <mike.dougherty@docker.com>
(cherry picked from commit adac575dd3)
2016-03-07 16:25:54 -05:00
David Calavera
a483ccc5df Make stdcopy.stdWriter goroutine safe.
Stop using global variables as prefixes to inject the writer header.
That can cause issues when two writers set the length of the buffer in
the same header concurrently.

Stop Writing to the internal buffer twice for each write. This could
mess up with the ordering information is written.

Signed-off-by: David Calavera <david.calavera@gmail.com>
(cherry picked from commit 443a5c2021)
2016-03-07 16:25:54 -05:00
Anusha Ragunathan
97e7e233b6 Always create apt-ftparchive.conf.
The Releases file(s) and other bits for EOL-ed distros such as Ubuntu
Vivid should remain untouched when we are releasing debs.

However, few files in https://apt.dockerproject.org/repo/dists/ubuntu-vivid/
were being updated for the docker 1.10 release including the Release files.
This is due to apt-ftparchive generating index files for vivid as well,
due to the stale apt-ftparchive.conf

This change always creates config using suites in contrib/reprepro/suites.sh.

Signed-off-by: Anusha Ragunathan <anusha@docker.com>
(cherry picked from commit 204c7808f9)
2016-03-07 16:25:54 -05:00
Antonio Murdaca
11a8469e49 pkg: idtools: fix subid files parsing
Since Docker is already skipping newlines in /etc/sub{uid,gid},
this patch skips commented out lines - otherwise Docker fails to start.
Add unit test also.

Signed-off-by: Antonio Murdaca <runcom@redhat.com>
(cherry picked from commit bf04d68db2)
2016-03-07 16:25:54 -05:00
Phil Estes
54ab6ff79e Add synchronization and closure to IO pipes in userns path
The execdriver pipes setup uses OS pipes with fds so that they can be
chown'ed to the remapped root user for proper access. Recent flakiness
in certain short-lived tests (usually via the "exec" path) reveals that
the copy routines are not completing before exit/tear-down.

This fix adds synchronization and proper closure such that these
routines exit successfully.

Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)

(cherry picked from commit 995386735c)
2016-03-07 16:25:54 -05:00
Brian Goff
d0165c4085 Fix panic when plugin responds with null volume
In cases where the a plugin responds with both a null or empty volume
and a null or empty Err, the daemon would panic.
This is because we assumed the idiom if `err` is nil, then `v` must not
be but in reality the plugin may return whatever it wants and we want to
make sure it doesn't harm the daemon.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit 96c79a1934)
2016-03-07 14:49:37 -05:00
Phil Estes
4899a04a2a Filter auto-created device list if user namespaces enabled
Because devices will be bind-mounted instead of using `mknod`, we need
to make sure the source exists and filter the list by only those whose
source is a valid path/current device entry.

Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)

(cherry picked from commit 9a554e8c37)
2016-03-07 14:46:59 -05:00
Brian Goff
ba797dd6a2 Close resp body on plugin call error
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit 93ad9c31fc)
2016-03-07 14:46:54 -05:00
Lei Jitang
3772dad6e9 Fix exec start api with detach and AttachStdin at same time. fixes #20638
Signed-off-by: Lei Jitang <leijitang@huawei.com>
(cherry picked from commit fb0ac1afd9)
2016-03-07 14:46:48 -05:00
Maxim Ivanov
84596366c2 Fix libdevmapper deferred removal detection
When linking, position of `-l` flags is important since
they muse come _after_ any object files which uses symbols
from a specified library, that is due to --as-needed binutils
ld flag enabled by default

Signed-off-by: Maxim Ivanov <ivanov.maxim@gmail.com>
(cherry picked from commit 24152a4231)
2016-03-07 14:46:30 -05:00
Tibor Vass
9a633164c0 Bump version to 1.10.3
Signed-off-by: Tibor Vass <tibor@docker.com>
2016-03-07 14:37:21 -05:00
Tibor Vass
c3959b140f Merge pull request #20526 from tiborvass/1.10.2-cherrypicks
1.10.2 cherrypicks
2016-02-19 22:45:26 -05:00
Tibor Vass
7613ee933c Update CHANGELOG for 1.10.2
Signed-off-by: Tibor Vass <tibor@docker.com>
2016-02-19 20:03:51 -05:00
David Calavera
1882f96fac Avoid setting default truthy values from flags that are not set.
When the value for a configuration option in the file is `false`,
and the default value for a flag is `true`, we should not
take the value from the later as final value for the option,
because the user explicitly set `false`.

This change overrides the default value in the flagSet with
the value in the configuration file so we get the correct
result when we merge the two configurations together.

Signed-off-by: David Calavera <david.calavera@gmail.com>
(cherry picked from commit 31cb96dcfa)
2016-02-19 20:02:47 -05:00
Tibor Vass
e87914a61f Merge pull request #20522 from LK4D4/do_not_close_chan
filenotify: don't close channels to avoid panic
2016-02-19 19:56:27 -05:00
Phil Estes
b756d5922c Fix copy chown settings to not default to real root
This corrects `docker cp` behavior when user namespaces are enabled.
Instead of chown'ing copied-in files to real root (0,0), the code
queries for the remapped root uid & gid and sets the chown option
properly.

Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)

(cherry picked from commit 40be5dba47)
2016-02-19 19:46:56 -05:00
Tibor Vass
1bfaf317a9 Merge pull request #20523 from cyli/vendor-notary-version-for-docker-1.10.2
Bump the notary version to one that fixes a bug with delegation path traversal
2016-02-19 19:36:29 -05:00
Tibor Vass
7e8b645077 Merge pull request #20518 from crosbymichael/bump-libcontainer-feb19
Bump libcontainer to 27dd48f6919a9bf8c25b41e97ca12
2016-02-19 19:35:52 -05:00
cyli
97b66d5b97 Bump the notary version to one that fixes a bug with delegation path traversal
Signed-off-by: cyli <cyli@twistedmatrix.com>
2016-02-19 15:09:56 -08:00
Alexander Morozov
2251e5db3f filenotify: don't close channels to avoid panic
Signed-off-by: Alexander Morozov <lk4d4@docker.com>
2016-02-19 14:37:33 -08:00
Tonis Tiigi
9d2cd50708 Fix releasing reference on deletion error
Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 64530c8e47)
2016-02-19 17:04:05 -05:00
Michael Crosby
9ef2e9d05c Bump libcontainer to 27dd48f6919a9bf8c25b41e97ca12
This includes the fix for moving the process out of the name=systemd
cgroup so that systemd does not delete the container's cgroups when its
configuration is reloaded.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2016-02-19 13:28:46 -08:00
Jess Frazelle
664c2f6639 Merge pull request #20510 from sanimej/102
Vendoring libnetwork v0.6.2-rc.1 to v1.10.2 branch
2016-02-19 13:39:33 -07:00
Aaron Lehmann
9032ad50c6 Close tarsplit gzip writer when creating tar-split.json.gz files during layer migration
There is a missing call to Close on the gzip.Writer that is used to
compress newly created tar-split files during layer migration. This can
result in corrupt tar-split files that later cause docker push and
docker save to fail. The Close call is necessary to flush buffered data
to the stream.

Fixes: #20104

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
(cherry picked from commit 1c05c65f6f)
2016-02-19 15:06:44 -05:00
Zhang Wei
4112eeb2cd Fix docs
Fix wrong descriptions in docs

Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
(cherry picked from commit 899335022f)
2016-02-19 15:06:26 -05:00
Brian Goff
7ad7f263d7 Fix issue with multiple volume refs with same name
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit 0fe31306d1)
2016-02-19 15:06:09 -05:00
Tonis Tiigi
77f94fd3c5 Fix migration diffid atomic write
Fixes #20267

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 056013f97b)
2016-02-19 15:06:01 -05:00
Tonis Tiigi
64368c438a Fix docker import on compressed data
Fixes #20296

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit e1c2eb0d35)
2016-02-19 15:05:49 -05:00
Dan Walsh
f844fa64e6 /dev/mqueue should never be mounted readonly
If user specifies --read-only flag it should not effect /dev/mqueue.
This is causing SELinux issues in docker-1.10.  --read-only blows up
on SELinux enabled machines.  Mounting /dev/mqueue read/only would also
blow up any tool that was going to use /dev/mqueue.

Signed-off-by: Dan Walsh <dwalsh@redhat.com>
(cherry picked from commit adb2e3fedc)
2016-02-19 15:05:26 -05:00
Tibor Vass
89e4ea0cd2 Bump version to 1.10.2
Signed-off-by: Tibor Vass <tibor@docker.com>
2016-02-19 10:57:14 -05:00
Santhosh Manohar
512b0b7e6d Vendoring libnetwork v0.6.2-rc.1 to v1.10.2 branch
Signed-off-by: Santhosh Manohar <santhosh@docker.com>
2016-02-17 00:51:36 -08:00
Santhosh Manohar
ba00d454e4 IT case for sending invalid query to embedded DNS server
Signed-off-by: Santhosh Manohar <santhosh@docker.com>
2016-02-17 00:47:21 -08:00
Tibor Vass
9e83765d0f Merge pull request #20238 from tiborvass/fix-1.10.1-changelog
Correct 1.10.1 CHANGELOG
2016-02-11 13:45:56 -05:00
Tibor Vass
b71c4680b3 Merge pull request #20235 from mavenugo/v1.10.1
vendor libnetwork v0.6.1-rc3
2016-02-11 13:33:38 -05:00
Madhu Venugopal
484b451a3d vendor libnetwork v0.6.1-rc3
- fixes https://github.com/docker/docker/issues/20140

Signed-off-by: Madhu Venugopal <madhu@docker.com>
2016-02-11 10:31:08 -08:00
Tibor Vass
ce4f13f604 Correct 1.10.1 CHANGELOG
Signed-off-by: Tibor Vass <tibor@docker.com>
2016-02-11 13:27:22 -05:00
Arnaud Porterie
6ab0256048 Merge pull request #20195 from tiborvass/1.10.1-cherrypicks
1.10.1 cherrypicks
2016-02-10 11:36:28 -08:00
Tibor Vass
f1cd0cabba Update CHANGELOG for 1.10.1
Signed-off-by: Tibor Vass <tibor@docker.com>
2016-02-10 13:05:41 -05:00
Madhu Venugopal
8f78ba9e06 Vendor libnetwork v0.6.1-rc2
- Fixes #20132 #20140 #20019

Signed-off-by: Madhu Venugopal <madhu@docker.com>
(cherry picked from commit 84705f15d9)

From PR #20181
2016-02-10 13:05:41 -05:00
Jessica Frazelle
14c2baad6e remove tasksmax, people on newer kernels can add it themselves
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
(cherry picked from commit 6241250824)

From PR #20167
2016-02-10 13:05:41 -05:00
Vincent Demeester
bba374fae5 Fix the since and before filter behavior
Filters should not include stopped container if `-a` is not specified.
Right now, before and since filter are acting as --before and --since
deprecated flags. This commit is fixing that.

Signed-off-by: Vincent Demeester <vincent@sbr.pm>
(cherry picked from commit b41dba58a0)

From PR #20135
2016-02-10 13:05:41 -05:00
Tibor Vass
d6e7dc791f Add runSleepingContainer in integration-cli
Signed-off-by: Tibor Vass <tibor@docker.com>
2016-02-10 13:05:40 -05:00
Kenfe-Mickael Laventure
85dba4980e Disable TestRunMountshmmqueuefromhost when using userns
Since we now automatically mount the mqueue device inside the
container (instead of bind mounting the one from the host), when
trying to start a container with --ipc=host, the mount will fail with
EPERM.

Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
(cherry picked from commit dba5a7f243)

From PR #20133
2016-02-10 12:58:27 -05:00
Kenfe-Mickael Laventure
b4963c87b2 Prevent mqueue from implicitely becoming a bind mount with --ipc=host
Currently, when running a container with --ipc=host, if /dev/mqueue is
a standard directory on the hos the daemon will bind mount it allowing
the container to create/modify files on the host.

This commit forces /dev/mqueue to always be of type mqueue except when
the user explicitely requested something to be bind mounted to
/dev/mqueue.

Signed-off-by: Kenfe-Mickael Laventure <mickael.laventure@gmail.com>
(cherry picked from commit f7d4abdc00)

From PR #20133
2016-02-10 12:58:27 -05:00
Liron Levin
f875caf6bf Fix 19575: Docker events doesn't work with authorization plugin
To support the requirement of blocking the request after the daemon
responded the authorization plugin use a `response recorder` that replay
the response after the flow ends.

This commit adds support for commands that hijack the connection and
flushes data via the http.Flusher interface. This resolves the error
with the event endpoint.

Signed-off-by: Liron Levin <liron@twistlock.com>
(cherry picked from commit 5ffc810df2)

From PR #20002
2016-02-10 12:58:27 -05:00
David Calavera
6234588d72 Fix channel closing race in event tests.
Divide event matching into two functions, a matcher and
a processor. That way, the error handling doesn't call
the channel closing logic at all.

Signed-off-by: David Calavera <david.calavera@gmail.com>
(cherry picked from commit 27b060492c)

From PR #19519
2016-02-10 12:58:22 -05:00
Stephen Rust
0bc432802d Fix volume driver API compatibility mode (a little)
Signed-off-by: Stephen Rust <srust@blockbridge.com>
(cherry picked from commit c3985bdf79)

From PR #19983
2016-02-10 11:30:07 -05:00
Dan Walsh
1e64264697 Make mqueue container specific
mqueue can not be mounted on the host os and then shared into the container.
There is only one mqueue per mount namespace, so current code ends up leaking
the /dev/mqueue from the host into ALL containers.  Since SELinux changes the
label of the mqueue, only the last container is able to use the mqueue, all
other containers will get a permission denied.  If you don't have SELinux protections
sharing of the /dev/mqueue allows one container to interact in potentially hostile
ways with other containers.

Signed-off-by: Dan Walsh <dwalsh@redhat.com>
(cherry picked from commit ba38d58659)

From PR #19876
2016-02-10 11:29:58 -05:00
David Lawrence
d650d8ccde adding note about go version 1.5 requirement for hardware signing
Signed-off-by: David Lawrence <david.lawrence@docker.com> (github: endophage)

(cherry picked from commit 1cc950b52e)

From PR #20112
2016-02-10 11:29:36 -05:00
Sebastiaan van Stijn
c634306b01 Fix 'tcp+tls' protocol not being accepted
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
(cherry picked from commit 878a0dc85c)

From PR #20109
2016-02-10 11:29:28 -05:00
Madhu Venugopal
0fdc67fb6b Vendor libnetwork v0.6.1-rc1
- Fixes #20026. Programming iptables in container use native API.

Signed-off-by: Madhu Venugopal <madhu@docker.com>
(cherry picked from commit 2da61086ea)

From PR #20060
2016-02-10 11:29:17 -05:00
Phil Estes
e24d5623a5 Fix ZFS permissions bug with user namespaces
Fix root directory of the mountpoint being owned by real root. This is
unique to ZFS because of the way file mountpoints are created using the
ZFS tooling, and the remapping that happens at layer unpack doesn't
impact this root (already created) holding directory for the layer.

Docker-DCO-1.1-Signed-off-by: Phil Estes <estesp@linux.vnet.ibm.com> (github: estesp)

(cherry picked from commit aef0995b02)

From PR #20045
2016-02-10 11:29:01 -05:00
Stefan Staudenmeyer
33a8948b3b Use grep -qE instead of egrep which is deprecated.
Signed-off-by: Stefan Staudenmeyer <doerte@instana.com>
(cherry picked from commit b3d66ff010)

From PR #20038
2016-02-10 11:28:50 -05:00
Stefan Staudenmeyer
5484d63e86 Grep for installed AND held packages.
Signed-off-by: Stefan Staudenmeyer <doerte@instana.com>
(cherry picked from commit 996ca75413)

From PR #20038
2016-02-10 11:28:37 -05:00
Tonis Tiigi
99ae25a0be Clear old parent reference on resetting image parent
On migration 2 different images can end up with same
content addressable ID, meaning `SetParent` will be called
multiple times. Previous version did not clear the old
in-memory reference.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
(cherry picked from commit 4852932494)

From PR #20058
2016-02-10 11:28:22 -05:00
Tom X. Tobin
1a53174680 Fix typo in config-json man page
In the NAME section: "confg.json" -> "config.json"

Signed-off-by: Tom X. Tobin <tomxtobin@tomxtobin.com>
(cherry picked from commit c75581c855)

From PR #20028
2016-02-10 11:28:14 -05:00
Tianon Gravi
5fa2c8f1e9 Add some basic bash completion for seccomp values
Signed-off-by: Andrew "Tianon" Page <admwiggin@gmail.com>
(cherry picked from commit 75aa7dbe4f)

From PR #19982
2016-02-10 11:27:23 -05:00
Brian Goff
53a9b1c77b Merge pull request #20175 from aaronlehmann/upper-case-hostnames-1.10
Allow uppercase characters in image reference hostname
2016-02-10 10:32:24 -05:00
Tibor Vass
c4756a0c36 Merge pull request #20164 from tonistiigi/verify-tarsteam-on-creation
Verify layer tarstream
2016-02-09 21:07:41 -05:00
Aaron Lehmann
f38610df1f Allow uppercase characters in image reference hostname
This PR makes restores the pre-Docker 1.10 behavior of allowing
uppercase characters in registry hostnames.

Note that this only applies to hostnames, not remote image names.
Previous versions also prohibited uppercase letters after the hostname,
but Docker 1.10 extended this to the hostname itself.

- Vendor updated distribution docker/1.10 branch.

- Add a check to "normalize" that rejects remote names with uppercase
  letters.

- Add test cases to TestTagValidPrefixedRepo and
  TestTagInvalidUnprefixedRepo

Fixes: #20056

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-02-09 17:18:33 -08:00
Tonis Tiigi
e29e580f7f Verify layer tarstream
This adds verification for getting layer data out
of layerstore. These failures should only be possible
if layer metadata files have been manually changed
of if something is wrong with tar-split algorithm.

Failing early makes sure we don’t upload invalid data
to the registries where it would fail after someone
tries to pull it.


Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2016-02-09 14:45:46 -08:00
Brian Goff
3fd1f6fa8b Merge pull request #20156 from tonistiigi/migration-remove-hard-failure
Don’t stop daemon on migration hard failure
2016-02-09 17:33:45 -05:00
Tonis Tiigi
2798d7a6a6 Don’t stop daemon on migration hard failure
Also changes missing storage layer for container
RWLayer to a soft failure.

Fixes #20147

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2016-02-09 13:09:07 -08:00
Tibor Vass
5f8164d587 Bump version to v1.10.1
Signed-off-by: Tibor Vass <tibor@docker.com>
2016-02-08 15:13:41 -05:00
Jess Frazelle
f154b9246f Merge pull request #19370 from tiborvass/bump_v1.10.0
Bump version to v1.10.0
2016-02-04 12:31:54 -08:00
Tibor Vass
590d5108bb Bump version to v1.10.0
Signed-off-by: Tibor Vass <tibor@docker.com>
2016-02-04 12:17:31 -05:00
Sebastiaan van Stijn
f094d39ad3 dont try to install journald driver on wheezy
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
2016-02-04 12:08:36 -05:00
Jessica Frazelle
58410c2d77 fix opensuse rpm
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
2016-02-03 17:31:25 -05:00
Arnaud Porterie
e7efe99042 Remove unnecessary call to /info
Avoid using the `/info` endpoint in the `login` and `logout` workflows
when the Registry endpoint is overriden by the user through the command
line.

Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
2016-02-03 17:31:25 -05:00
Aaron Lehmann
0438c9bd3a Introduce a client-side version of resolveAuthConfig
This is similar to the version in the registry package, but uses the
daemon's default index (as opposed to the default for the client's
platform) if using the "official index".

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-02-03 17:31:24 -05:00
Arnaud Porterie
08fc87ab80 Enable cross-platforms logout from Registry
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
2016-02-03 17:31:24 -05:00
Aaron Lehmann
6708e2305c Revert "Set idle timeouts for HTTP reads and writes in communications with the registry"
This reverts commit 84b2162c1a.

The intent of this commit was to set an idle timeout on a HTTP
connection. If a read took more than 60 seconds to complete, or a write
took more than 60 seconds to complete, the connection would be
considered dead.

This doesn't work properly, because the HTTP internals apparently read
from the connection concurrently while writing. An upload that doesn't
complete in 60 seconds leads to a timeout.

Fixes #19967

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-02-03 17:31:24 -05:00
Florian Maier
fbd96e09c3 Fix formatting in breaking changes doc
Signed-off-by: Florian Maier <contact@marsmenschen.com>
2016-02-03 17:31:24 -05:00
Lei Jitang
6f72190b7d Check nil before set resource.OomKillDisable
Signed-off-by: Lei Jitang <leijitang@huawei.com>
2016-02-03 17:31:24 -05:00
Alessandro Boch
fa0856e0e4 Store endpoint config on network connect to a stopped container
Signed-off-by: Alessandro Boch <aboch@docker.com>
2016-02-03 17:31:24 -05:00
Ben Firshman
a315a5acec Add 1.10 migration docs
Originally from https://blog.docker.com/2016/01/docker-1-10-rc/

Signed-off-by: Ben Firshman <ben@firshman.co.uk>
2016-02-03 16:27:49 -05:00
Victor Vieux
c7725242b9 fix error message on version too low
Signed-off-by: Victor Vieux <vieux@docker.com>
2016-02-03 16:27:49 -05:00
David Calavera
4a6436223e Make sure flat options are not parsed as config structures.
Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-02-02 15:37:14 -05:00
Arnaud Porterie
4750819a79 Delegation is not experimental
Change wording that described user delegation as an experimental
feature.

Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
2016-02-02 15:17:44 -05:00
Mary Anthony
72bf64601d Changing menu label from Engine > Docker Engine
Signed-off-by: Mary Anthony <mary@docker.com>
2016-02-02 13:46:16 -05:00
Sebastiaan van Stijn
c040d956d3 Add note about legacy links
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2016-02-02 13:46:15 -05:00
Arnaud Porterie
534d69d38a Add doc page for breaking changes
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
2016-02-02 13:46:15 -05:00
Madhu Venugopal
7a6536c546 Docs cleanup for networking features added in v1.10
Signed-off-by: Madhu Venugopal <madhu@docker.com>
2016-02-02 13:46:15 -05:00
Sebastiaan van Stijn
1f6c3c72b4 Fix memory-swap description in older API versions
A value of -1 disables the *limit* so enables unlimited swap

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2016-02-02 13:46:15 -05:00
Qiang Huang
8051540de9 Fix comment about swap limit of docker update
The description "set `-1` to disable swap" is wrong, `build`,
`create` and `run` already fixed, we need to fix `update` as well.

Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
2016-02-02 13:46:15 -05:00
Arnaud Porterie
220adb320b Enable cross-platforms login to Registry
Use a daemon-defined Registry URL for `docker login`. This allows a
Windows client interacting with a Linux daemon to properly use the
default Registry endpoint instead of the Windows specific one.

Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
2016-02-02 13:46:14 -05:00
Kai Qiang Wu(Kennan)
9750ba3494 Correct old virtual size
In new content addressable model, image no longer
have virtual size column, it is now 'size'. So we
need to update related docs about them.

Signed-off-by: Kai Qiang Wu(Kennan) <wkqwu@cn.ibm.com>
2016-02-02 13:46:14 -05:00
Tibor Vass
6da35a288f Skip Close()-ing stdin on Darwin. The Return.
This was accidentally removed in https://github.com/docker/docker/pull/16289
Now adding it back.

Signed-off-by: Tibor Vass <tibor@docker.com>
2016-02-02 13:46:14 -05:00
Alessandro Boch
b2c04e941b Vendoring libnetwork 0.6.0-rc7
Signed-off-by: Alessandro Boch <aboch@docker.com>
2016-02-02 13:46:14 -05:00
Brian Goff
cd9879744f handle debug mode for clients
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-02-02 13:46:14 -05:00
Joel Wurtz
b3307d9e84 Update docker-php library from stage1
Signed-off-by: Joel Wurtz <joel.wurtz@gmail.com>
2016-02-02 13:46:14 -05:00
Aditi Rajagopal
b03c57a726 Update Instructions for Docker Remote API access
Update the location of cert.pem and key.pem to use within the
~/.docker folder
Resolves: #18778

Signed-off-by: Aditi Rajagopal <arajagopal@us.ibm.com>
2016-02-02 13:46:13 -05:00
Alessandro Boch
9c0c32f701 Vendoring libnetwork 0.6.0-rc6
Signed-off-by: Alessandro Boch <aboch@docker.com>
2016-02-02 13:46:13 -05:00
Weiyang Zhu
5d8585fc4b Fix upgrade command
Signed-off-by: Weiyang Zhu <cnresonant@gmail.com>
2016-02-02 13:46:13 -05:00
Aaron Lehmann
a0861479dc Fix panic on network timeout during push
`Upload` already closes the reader returned by `compress` and the
progressreader passed into it, before returning. But even so, the
io.Copy inside compress' goroutine needs to attempt a read from the
progressreader to notice that it's closed, and this read has a side
effect of outputting a progress message. If this happens after `Upload`
returns, it can result in a write to a closed channel. Change `compress`
to return a channel that allows the caller to wait for its goroutine to
finish before freeing any resources connected to the reader that was
passed to it.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-02-02 13:46:13 -05:00
Vincent Demeester
70326ef54a Add docker-volume-ipfs plugin to the list.
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
2016-02-02 13:46:13 -05:00
Felix Hupfeld
797a92d0b2 Added link to Quobyte's volume plugin.
Signed-off-by: Felix Hupfeld <felix@quobyte.com>
2016-02-02 13:46:13 -05:00
qg
a22c9f551b change 'host:port' to host:port
Signed-off-by: Gang Qiao <qiaohai8866@gmail.com>
2016-02-02 13:46:12 -05:00
Wen Cheng Ma
72eb04e7b2 Change container name to id as actual results
Signed-off-by: Wen Cheng Ma <wenchma@cn.ibm.com>
2016-02-02 13:46:12 -05:00
Prayag Verma
d38ed8e5ac Fix typo
Signed-off-by: Prayag Verma <prayag.verma@gmail.com>
2016-02-02 13:46:12 -05:00
Nigel
c7436a4ff8 Updating for CAS changes and new select a driver section
Adding changes requested by @jamtur01 and wrapping to 80 chars
Adding typo fixes and replacing tabs with 4xspaces
Closes and fixes #19240
Updating with content addressable storage model changes

Signed-off-by: Nigel <nigelpoulton@hotmail.com>
2016-02-02 13:46:12 -05:00
Joffrey F
8230753ebf Update example request for container update in docs.
Signed-off-by: Joffrey F <joffrey@docker.com>
2016-02-02 13:46:12 -05:00
Nishant Totla
c2119a9c00 Adding SystemStatus field for /info endpoint
Signed-off-by: Nishant Totla <nishanttotla@gmail.com>
2016-02-02 13:46:11 -05:00
Tibor Vass
192011e178 vendor engine-api 0.2.3 to add SystemStatus in Info type
Signed-off-by: Tibor Vass <tibor@docker.com>
2016-02-02 13:46:11 -05:00
Jessica Frazelle
0d875a262b update bash completions for push and pull
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
2016-02-02 12:20:13 -05:00
John Howard
b6d406fe19 Improvements to ANSI emulation in conemu
Signed-off-by: John Howard <jhoward@microsoft.com>
2016-02-02 12:20:13 -05:00
David Calavera
d37f5ad62e Always prompt for a password when asking for credentials.
There is a weird behavior where we don't ask for a password
when the user you type in the prompt is the same you have configured
in the config file.

This is the source of many frustrations and also a bug.
If the authentication with a registry fails because the password
is incorrect, we won't ask for the password again with the current logic.

With this change, we also stop calling `CmdLogin` directly when
authentication fails. We don't need to parse flags from the cli or
setting up input destriptiors again, like the current behavior is doing.

Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-02-02 12:20:13 -05:00
David Calavera
dc2f5d0f4b Respond with 401 when there is an unauthorized error from the registry.
Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-02-02 12:20:13 -05:00
Wen Cheng Ma
79f0588009 docs: document options for default network driver
Fixes issue #18410

Signed-off-by: Wen Cheng Ma <wenchma@cn.ibm.com>
2016-02-02 12:20:12 -05:00
cyli
16ba075162 Include a new version of notary with less verbose INFO+ logging
Signed-off-by: cyli <cyli@twistedmatrix.com>
2016-02-02 12:20:12 -05:00
cyli
a8bf0dad6f Update integration tests with new error messages, and to use different repos per test.
This way we won't encounter any problems with one test using cached data from a different
test.

Signed-off-by: cyli <cyli@twistedmatrix.com>
2016-02-02 12:20:12 -05:00
cyli
63e57bcc22 Re-vendor notary, as well as change jfrazelle/go to docker/go.
Signed-off-by: cyli <cyli@twistedmatrix.com>
2016-02-02 12:20:12 -05:00
Sebastiaan van Stijn
fe8647bc06 Update notary to 1.10-3 in all Dockerfiles
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2016-02-02 12:20:12 -05:00
Jessica Frazelle
66afedbbce way better apparmor docs
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
2016-02-02 12:20:11 -05:00
Bryan Boreham
cffaf6725b Improve wording about re-assigning IP addresses
Signed-off-by: Bryan Boreham <bjboreham@gmail.com>
2016-02-02 12:20:11 -05:00
Tomasz Kopczynski
1974ccd122 FAQ: add docker daemon unavailable note
Signed-off-by: Tomasz Kopczynski <tomek@kopczynski.net.pl>
2016-02-02 12:20:11 -05:00
Aaron Lehmann
556314ad14 Set idle timeouts for HTTP reads and writes in communications with the registry
Otherwise, some operations can get stuck indefinitely when the remote
side is unresponsive.

Fixes #12823

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-01-27 10:29:57 -08:00
Harald Albers
dc41fad580 bash completion for docker ps --filter status=dead
Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-27 10:29:56 -08:00
Zhang Wei
ec60923688 Forbid exec a restarting container
Currently if we exec a restarting container, client will fail silently,
and daemon will print error that container can't be found which is not a
very meaningful prompt to user.

This commit will stop user from exec a restarting container and gives
more explicit error message.

Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
2016-01-27 10:29:56 -08:00
Pei Su
5dd0e5acb0 fix dead lock in volume store dereference
Signed-off-by: Pei Su <sillyousu@gmail.com>
2016-01-27 10:29:56 -08:00
Harald Albers
b6ea29fad3 Improve bash completion for docker volume ls -f dangling
Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-27 10:29:56 -08:00
David Calavera
0f90db8c33 Fix bash completion for docker volume ls --dangling=false.
Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-01-27 10:29:56 -08:00
David Calavera
823d7ce150 Make volume dangling filter return only used volumes with dangling=false.
Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-01-27 10:29:56 -08:00
Kai Qiang Wu(Kennan)
0cd60bcf47 Fix volume filter validation
Fixes: #18890
This fix add same filter validation logic as images. We should
add such check to make sure filters work make sense to end-users

Right now, we keep old use 1 as filter, but in long term, it should
be have same interface checking as images, it could be improved in
other patches.

Signed-off-by: Kai Qiang Wu(Kennan) <wkqwu@cn.ibm.com>
2016-01-27 10:29:55 -08:00
Sebastiaan van Stijn
c9417fac95 Fix docs for tmpfs (pr 19688)
Underlying files are no longer copied to the tmpfs.

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2016-01-27 10:29:55 -08:00
Michael Crosby
7d749fbd48 Update libcontainer to 3d8a20bb772defc28c355534d83
Fixes #14203

This bump fixes the issue of having the container's pipes connection
reset by peer because of using the json.Encoder and having a \n added to
the output.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2016-01-27 10:29:55 -08:00
David Calavera
745158f033 Remove cluster storage advertise from reload.
Because libnetwork won't really send container information to the new
storage anyways.

Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-01-27 10:29:55 -08:00
Michael Crosby
cd5c2575c1 Move tar copy-up for tmpfs mounts
We cannot rely on the tar command for this type of operation because tar
versions, flags, and functionality can very from distro to distro.
Since this is in the container execution path it is not safe to have
this as a dependency from dockers POV where the user cannot change the
fact that docker is adding these pre and post mount commands.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2016-01-27 10:29:55 -08:00
Mary Anthony
828c8ba83d Creating Engine specific menu
Fixing the links
Updating with Seb's comments
Adding weight
Fixing the engine aliases
Updating after Arun pushed
Removing empty file

Signed-off-by: Mary Anthony <mary@docker.com>
2016-01-27 10:29:54 -08:00
Sebastiaan van Stijn
794b2bcc89 Fix remove API order in menu
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
2016-01-27 10:29:54 -08:00
Mike Dougherty
7dc109e727 Adjust version string processing for RPM build
This will only trim off the last '-' separated token to be checked for
RC status. This allows including a 'cs#' token in the version string.

Signed-off-by: Mike Dougherty <mike.dougherty@docker.com>
2016-01-27 10:29:54 -08:00
Kai Qiang Wu(Kennan)
dd7b0abc01 Refine the volume mount example
The path here should be absolute, else it would
deem it as volume name.

Also link to release page to contain static binary,
the old link not work, because it is just used to
install docker in os distro, it can not be used
as static binary directly.

Signed-off-by: Kai Qiang Wu(Kennan) <wkqwu@cn.ibm.com>
2016-01-27 10:29:54 -08:00
Kai Qiang Wu(Kennan)
a145ec47e0 Fix the typo in ps
Signed-off-by: Kai Qiang Wu(Kennan) <wkqwu@cn.ibm.com>
2016-01-27 10:29:54 -08:00
Morton Fox
8934612d69 cgroups documentation moved
Signed-off-by: Morton Fox <github@qslw.com>
2016-01-27 10:29:54 -08:00
Kai Qiang Wu(Kennan)
f01ff1db7f Fix commit wrong repository example
The old name is invalid in new repository name spec.
So we need to fix them.

Signed-off-by: Kai Qiang Wu(Kennan) <wkqwu@cn.ibm.com>
2016-01-27 10:29:53 -08:00
Dave Barboza
36809b4726 Fix minor doc grammar issues
Signed-off-by: Dave Barboza <dxbarboza@gmail.com>
2016-01-27 10:29:53 -08:00
Kai Qiang Wu(Kennan)
517628120c Fix the privileged example
Signed-off-by: Kai Qiang Wu(Kennan) <wkqwu@cn.ibm.com>
2016-01-27 10:29:53 -08:00
Kai Qiang Wu(Kennan)
ea4ee1e4ea Fix ulimit command form
The ulimit is builtin, so we need shell form to execute it.

Signed-off-by: Kai Qiang Wu(Kennan) <wkqwu@cn.ibm.com>
2016-01-27 10:29:53 -08:00
Tianon Gravi
fdaa6d0c7e Change the way we install from backports in the deb builder (to force deps too)
Also, add "libsystemd-journal-dev" to the explicit list (which is what prompted the change in how we install).

Signed-off-by: Andrew "Tianon" Page <admwiggin@gmail.com>
2016-01-27 10:29:53 -08:00
Jana Radhakrishnan
d4497e74f5 Vendoring libnetwork v0.6.0-rc5
- Cleanup stale overlay sandboxes

Fixes #19694

Signed-off-by: Jana Radhakrishnan <mrjana@docker.com>
2016-01-27 10:29:53 -08:00
Victor Costan
debe687d55 Add missing words in selectadriver.md
Signed-off-by: Victor Costan <costan@gmail.com>
2016-01-27 10:29:52 -08:00
Brian Goff
fcad2d9384 Use imageStore.Children instead of whole the Map
daemon cache was getting the whole image map and then iterating through
it to find children. This information is already stored in the image
store.

Prior to this change building the docker repo with a full cache took 30
seconds.
After it takes between 15 seconds or less (As low as 9 seconds).
This is an improvement on docker 1.9.1 which hovered around 17 seconds.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-01-27 10:29:52 -08:00
Brian Goff
b04d424bf8 Add note about mount propagation on systemd
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-01-27 10:29:52 -08:00
Aidan Hobson Sayers
364967e39e Permit OPTIONS request against any url, fixes #19398
Signed-off-by: Aidan Hobson Sayers <aidanhs@cantab.net>
2016-01-27 10:29:52 -08:00
Harald Albers
4632701fe2 bash completion for docker daemon --userns-remap
Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-27 10:29:52 -08:00
Madhu Venugopal
59915f15bd Move port-mapping ownership closer to Sandbox (from Endpoint)
https://github.com/docker/libnetwork/pull/810 provides the more complete
solution for moving the Port-mapping ownership away from endpoint and
into Sandbox. But, this PR makes the best use of existing libnetwork
design and get a step closer to the gaol.

Signed-off-by: Madhu Venugopal <madhu@docker.com>
2016-01-26 12:59:00 -08:00
Madhu Venugopal
3b2cbc2325 Vendor libnetwork v0.6.0-rc4
- Add Endpoints() API to Sandbox interface
- Fixes #19677

Signed-off-by: Madhu Venugopal <madhu@docker.com>
2016-01-26 12:59:00 -08:00
Qiang Huang
6934594ae0 Verify cgroup-parent name for systemd cgroup
Fixes: #17126

Signed-off-by: Qiang Huang <h.huangqiang@huawei.com>
2016-01-26 12:59:00 -08:00
Aaron Lehmann
a5fc987d2e Remove temporary layer download file on error
Currently, the temporary file storing downloaded layer data is only
removed after a successful download or a digest verification error. A
transport-level error does not cause it to be removed. This is a
regression from 1.9 that could cause disk usage to grow until the Docker
daemon is restarted.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-01-26 12:59:00 -08:00
David Calavera
c446fd2099 Allow network configuration via daemon config file.
Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-01-26 12:59:00 -08:00
Tianon Gravi
949255c010 Add a note to /etc/default/docker noting that it does not apply to systemd
Signed-off-by: Andrew "Tianon" Page <admwiggin@gmail.com>
2016-01-26 12:58:59 -08:00
Brian Goff
be311fba7b On container rm, don't remove named mountpoints
This makes it so when calling `docker run --rm`, or `docker rm -v`, only
volumes specified without a name, e.g. `docker run -v /foo` instead of
`docker run -v awesome:/foo` are removed.

Note that all volumes are named, some are named by the user, some get a
generated name. This is specifically about how the volume was specified
on `run`, assuming that if the user specified it with a name they expect
it to persist after the container is cleaned up.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-01-26 12:58:59 -08:00
Alessandro Boch
61943d54aa Save endpoint config only if endpoint creation succeeds
- Currently it is being save upfront...

Signed-off-by: Alessandro Boch <aboch@docker.com>
2016-01-26 12:58:59 -08:00
Brian Goff
08ca18b59d Fix removing mountpoints on container rm fail
Ensure that the the container's mountpoints are cleaned up if the
container is force removed.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-01-26 12:58:59 -08:00
Madhu Venugopal
46ea20fb18 Vendor libnetwork v0.6.0-rc3
- Fixes docker/docker#19576
- Fixed embedded DNS to listen in TCP as well
- Fixed a race-condition in IPAM to choose non-overlapping subnet for concurrent requests

Signed-off-by: Madhu Venugopal <madhu@docker.com>
2016-01-26 12:58:59 -08:00
Arun Gupta
fe82e7fb2f adding docs for Dockerizing Couchbase service
cleaning up instructions, removing redundant output

Signed-off-by: Arun Gupta <arun.gupta@gmail.com>

adding the latest feedback

Signed-off-by: Arun Gupta <arun.gupta@gmail.com>
2016-01-26 12:58:59 -08:00
Aaron Lehmann
1fd7b0881e Fix watching a released transfer
Things could go wrong if Watch was called after the last existing
watcher was released. The call to Watch would succeed even though it was
not really adding a watcher, and the corresponding call to Release would
close hasWatchers a second time.

The fix for this is twofold:

1. We allow transfers to gain new watchers after the watcher count has
touched zero. This means that the channel returned by Released should
not be closed until all watchers have been released AND the transfer is
no longer tracked by the transfer manager, meaning it won't be possible
for additional calls to Watch to race with closing the channel returned
by Released.

The Transfer interface has a new method called Close so the transfer can
know when the transfer manager no longer references it.

Remove the Cancel method. It's not used and should not be exported.

2. Even though (1) makes it possible to add watchers after all the
previous watchers have been released, we want to avoid doing this in
practice. A transfer that has had all its watchers released is in the
process of being cancelled, and attaching to one of these will never be
the correct behavior. Add a check if a watcher is attaching to a
cancelled transfer.  In this case, wait for the transfer to be removed
from the map and try again. This will ensure correct behavior when a
watcher tries to attach during the race window.

Either (1) or (2) should be sufficient to fix the race involved here,
but the combination is the most correct approach. (1) fixes the
low-level plumbing to be resilient to the race condition, and (2) avoids
using it in a racy way.

Fixes #19606

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-01-26 12:58:58 -08:00
Alessandro Boch
36efc47844 Reject multiple networks on container creation
Signed-off-by: Alessandro Boch <aboch@docker.com>
2016-01-26 12:58:58 -08:00
Tonis Tiigi
5bb832e024 Fix error message in container creation
Error message was different if image was specified with the full ID.

Fixes #19652

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2016-01-26 12:58:58 -08:00
Brian Goff
fb6eda91c2 Add back compat for volume drivers Get and Ls
Use a back-compat struct to handle listing volumes for volumes we know
about (because, presumably, they are being used by a container) for
volume drivers which don't yet support `List`.

Adds a fall-back for the volume driver `Get` call, which will use
`Create` when the driver returns a `404` for `Get`. The old behavior was
to always use `Create` to get a volume reference.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-01-26 12:58:58 -08:00
Mary Anthony
3fbb69073f Fixing missing certs article; consolidating security material
Entering comments from reviewers
Updating with Derek's comments
Fixing bad links reported by build

Signed-off-by: Mary Anthony <mary@docker.com>
2016-01-26 12:58:58 -08:00
Steve Durrheimer
41c6bf4fdd Add zsh completion for 'docker cp -L --follow-link'
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2016-01-26 12:58:57 -08:00
Steve Durrheimer
66e6eff020 Add zsh completion for new 'docker daemon --log-opt syslog-tls-ca-cert syslog-tls-cert syslog-tls-key syslog-tls-skip-verify' options
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2016-01-26 12:58:57 -08:00
Steve Durrheimer
abfe273447 Add zsh completion for new 'docker daemon --cluster-store-opt discovery.heartbeat discovery.ttl kv.path' options
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2016-01-26 12:58:57 -08:00
Harald Albers
e68d32f1e7 fix minor bash completion issue on OSX (compopt)
Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-26 12:58:57 -08:00
scaleoutsean
29423cb6e9 Add GPFS
Signed-off-by: Sean Lee <seanlee@tw.ibm.com>
2016-01-26 12:58:57 -08:00
Harald Albers
a22b9c5bdf bash completion for syslog over TLS log driver
Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-26 12:58:57 -08:00
Harald Albers
f2fb744453 remove zsh completion for docker tag -f
Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-26 12:58:56 -08:00
Harald Albers
88d4ce135b bash completion for --cluster-store-opt kv.path discovery.{heartbeat,ttl}
Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-26 12:58:56 -08:00
Harald Albers
f292f12f00 bash completion for docker cp --follow-link
Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-26 12:58:56 -08:00
Harald Albers
5dc40351af bash completion for docker images -f dangling=false
Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-26 12:58:56 -08:00
Jasmine Hegman
e778dc919b Correcting overlay -> bridge driver in run.md
Correcting `overlay` -> `bridge` driver in run.md to match the preceding paragraph.

Signed-off-by: Jasmine Hegman <jasmine@jhegman.com>
2016-01-26 12:58:56 -08:00
Tianon Gravi
7138dedf6a Add pkg-config to our Debian build environment
This is used in `hack/make.sh` for detecting various dependencies such as `libsystemd-journal` -- without this, our packages don't support pulling logs back out of journald. 😢

Signed-off-by: Andrew "Tianon" Page <admwiggin@gmail.com>
2016-01-26 12:58:56 -08:00
Doug Davis
09ff96bace Add some helper text for magical ADD
Closes: #15777

Signed-off-by: Doug Davis <dug@us.ibm.com>
2016-01-26 12:58:55 -08:00
Avi Miller
789a10de60 Updated Oracle Linux install documentation to be more accurate.
Signed-off-by: Avi Miller <avi.miller@oracle.com>
2016-01-26 12:58:55 -08:00
Nalin Dahyabhai
3a9ebcb7f7 Add pkg-config to our RPM build environment
While hack/make.sh checks for systemd headers using pkg-config, we
forgot to ensure that they were there in the images that we use for
building binaries for RPM-based distributions.  Add the right packages
to the generate.sh that we use for them, and update the copies of the
generated files that we carry in the source tree.

Notes: Fedora, CentOS, and Oracle Linux put the pkg-config command in
the "pkgconfig" package, while OpenSUSE calls the package "pkg-config".
The systemd-devel package, like systemd, is not in Oracle Linux 6.

Signed-off-by: Nalin Dahyabhai <nalin@redhat.com>
2016-01-26 12:58:55 -08:00
Aleksa Sarai
2bc762e6c8 integration-cli: add bad --cgroup-parent tests
To ensure we don't regress on bad --cgroup-parent paths, add some
integration tests that check that the host hasn't toppled (or suddently
started to create files in the host).

Signed-off-by: Aleksa Sarai <asarai@suse.com>
2016-01-26 12:58:55 -08:00
Aleksa Sarai
7fa92c23d5 vendor: *: update libcontainer
This fixes a security vulnerability in Docker, which can cause a DoS
under certain circumstances. This is from the hotfix branch, so the
vendored commit is actually bf899fef451956be4abd63de6d6141d9f9096a02 in
runc master.

Signed-off-by: Aleksa Sarai <asarai@suse.com>
2016-01-26 12:58:55 -08:00
Michael Crosby
187a9a154c Update libcontainer to 47e3f834d73e76bc2a6a585b48d
This adds a fix for the resource struct in the cgroups type and seccomp
IsEnabled function

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2016-01-26 12:58:55 -08:00
Aaron Lehmann
6649716949 Vendor updated distribution package
Another day, another revendor.

This revision of distribution is more tolerant of incorrect Content-Type
headers when fetching manifests.

Fixes #19526

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-01-26 12:58:54 -08:00
Santhosh Manohar
5e36b8cf81 IT for service/network name with '.', corrected libnetwork flag for DNS
Signed-off-by: Santhosh Manohar <santhosh@docker.com>
2016-01-26 12:58:54 -08:00
Santhosh Manohar
fc7f291b9b Vendor in libnetwork v0.6.0-rc2
Signed-off-by: Santhosh Manohar <santhosh@docker.com>
2016-01-26 12:58:54 -08:00
David Calavera
c62c9636c5 Extract container store from the daemon.
- Generalize in an interface.
- Stop abusing of List for everything.

Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-01-26 12:58:54 -08:00
Alessandro Boch
56a982afb0 Move ErrUnsupportedNetwork* checks to updateNetworkConfig() func
Signed-off-by: Alessandro Boch <aboch@docker.com>
2016-01-26 12:58:53 -08:00
Stephen Rust
e91c8a9aa0 Allow external volume drivers to host anonymous volumes and copy existing data from image.
Signed-off-by: Stephen Rust <srust@blockbridge.com>
2016-01-26 12:58:53 -08:00
David Calavera
f999cd3d4e Make TLSOptions and LogConfig embedded structs.
That way the configuration file becomes flag, without extra keys.

Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-01-26 12:58:53 -08:00
David Calavera
231eeca2b0 Verify that the configuration keys in the file are valid.
- Return an error if any of the keys don't match valid flags.
- Fix an issue ignoring merged values as named values.
- Fix tlsverify configuration key.
- Fix bug in mflag to avoid panics when one of the flag set doesn't have any flag.

Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-01-26 12:58:53 -08:00
David Calavera
ba01d9f9d6 Fix post config verification without flags.
- Set the daemon log level to what's set in the configuration.
- Enable TLS when TLSVerify is enabled.

Signed-off-by: David Calavera <david.calavera@gmail.com>
2016-01-26 12:58:53 -08:00
Brian Bland
97d84623cf Fixes layer MediaTypes in manifests created from a cross-repository push
Signed-off-by: Brian Bland <brian.bland@docker.com>
2016-01-26 12:58:53 -08:00
Brian Goff
aad22c7801 Bump plugin API version
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-01-26 12:58:52 -08:00
Anton Polonskiy
233cc865b5 fixed typo
Signed-off-by: Anton Polonskiy <anton.polonskiy@gmail.com>
2016-01-26 12:58:52 -08:00
Aaron Lehmann
d550cf0bee Clarify error message when a .cert file is missing a corresponding key
The daemon uses two similar filename extensions to identify different
kinds of certificates. ".crt" files are interpreted as CA certificates,
and ".cert" files are interprted as client certificates. If a CA
certificate is accidentally given the extension ".cert", it will lead to
the following error message:

    Missing key ca.key for certificate ca.cert

To make this slightly less confusing, clarify the error message with a
note that CA certificates should use the extension ".crt".

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-01-26 12:58:52 -08:00
Kareem Khazem
5a65aac15c Added dead to docs for docker ps -f status=...
It is possible to invoke `docker ps -f status=dead`, but the
documentation for docker-ps does not mention `dead` as a valid option.
This commit fixes that.

Signed-off-by: Kareem Khazem <karkhaz@karkhaz.com>
2016-01-26 12:58:52 -08:00
Aaron Lehmann
2d678f5120 Don't retry downloads when disk is full
There was already a check that prevented protocol-level fallback in this
situation, but retries within a specific protocol will still happen.
This makes it take a long time for the pull to finally error out.

This fixes slowness in TestDaemonNoSpaceleftOnDeviceError, which used to
take a long time due to the backoff between retry attempts:

PASS: docker_cli_daemon_test.go:1868: DockerDaemonSuite.TestDaemonNoSpaceleftOnDeviceError	5.882s

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-01-26 12:58:52 -08:00
Derek McGowan
e08cf4fd80 Unwrap URL errors on retry
When authorization errors are returned by the token process the error will be wrapped in url.Error.
In order to check the underlying error for retry this error message should be unwrapped.
Unwrapping this error allows failure to push due to an unauthorized response to keep from retrying, possibly resulting in later 429 responses.

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2016-01-26 12:58:52 -08:00
Tonis Tiigi
084a60e8e1 Revert "Copy aufs hardlinks to top layer"
This reverts commit ef05b83417.

Signed-off-by: Tonis Tiigi <tonistiigi@gmail.com>
2016-01-26 12:58:51 -08:00
Jessica Frazelle
43267aa225 add warning if upgrading via script to migrate
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
2016-01-26 12:58:51 -08:00
Harald Albers
1fe410e173 Refactor handling of key specific subcompletions
The currently used idiom for handling key specific subcompletions
did not work here: behind `docker event -f type=network `, the completion
of networks triggered. The expected behaviour is not to complete
anything here.

In order to limit the scope of the corresponding PR, the new idiom is
currently only used in `docker events --filter`.

Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-26 12:58:51 -08:00
Harald Albers
821b40d1ef Support new events in bash completion
Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-26 12:58:51 -08:00
Jessica Frazelle
4d331573ff disable install of docker-engine for 1.10, try to get ready for 1.11
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
2016-01-26 12:58:51 -08:00
Azat Khuyiyakhmetov
3aa4d3e936 Fixed typo in "/etc/subUid"
Signed-off-by: Azat Khuziyakhmetov <shadow_uz@mail.ru>
2016-01-26 12:58:51 -08:00
Aaron Lehmann
6514690023 Vendor updated distribution
The only changes are https://github.com/docker/distribution/pull/1379
and https://github.com/docker/distribution/pull/1380.

Fixes #19476

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-01-26 12:58:50 -08:00
Brian Goff
d1043f654c Use fine-grained locks for plugin loading.
This helps ensure that only one thing is trying to intialize a plugin at
once while also keeping the global lock free during initialization.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-01-26 12:58:50 -08:00
Brian Goff
360d59662f Fix loading of containerized plugins
During daemon startup, all containers are registered before any are
started.
During container registration it was calling out to initialize volumes.
If the volume uses a plugin that is running in a container, this will
cause the restart of that container to fail since the plugin is not yet
running.
This also slowed down daemon startup since volume initialization was
happening sequentially, which can be slow (and is flat out slow since
initialization would fail but take 8 seconds for each volume to do it).

This fix holds off on volume initialization until after containers are
restarted and does the initialization in parallel.

The containers that are restarted will have thier volumes initialized
because they are being started. If any of these containers are using a
plugin they will just keep retrying to reach the plugin (up to the
timeout, which is 8seconds) until the container with the plugin is up
and running.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-01-26 12:58:50 -08:00
Lei Jitang
326de12d8f Fix #19477, clean up the ports when release network
Signed-off-by: Lei Jitang <leijitang@huawei.com>
2016-01-26 12:58:50 -08:00
Koichi Shiraishi
528ebe6ed1 Add ARG instruction syntax for vim
Signed-off-by: Koichi Shiraishi <k@zchee.io>
2016-01-26 12:58:50 -08:00
Steve Durrheimer
6820877d65 Add zsh completion for 'docker network connect --link'
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2016-01-26 12:58:50 -08:00
Steve Durrheimer
bea0dca3d4 Add zsh completion for 'docker {network connect, create, run} --ip --ip6'
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2016-01-26 12:58:49 -08:00
Steve Durrheimer
57833e5fb6 Add zsh completion for 'docker network connect --alias' and 'docker {create, run} --net-alias'
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2016-01-26 12:58:49 -08:00
Aaron Lehmann
d37f25f0d7 Revert reporting of multiple pull errors
Revert the portions of #17617 that report all errors when a pull
falls back, and go back to just reporting the last error. This was nice
to have, but causes some UX issues because nonexistent images show
additional "unauthorized" errors.

Keep the part of the PR that handled ENOSPC, as this appears to work
even without tracking multiple errors.

Fixes #19419

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-01-26 12:58:49 -08:00
Brian Goff
77e92cfb13 Don't error out when link name in use.
This preserves old behavior from sqlite links/names.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-01-26 12:58:49 -08:00
Michael Crosby
3b5b116d43 Move tty set and restore to caller
Fixes #19506

This fixes the issue of errors on create and the tty not being able to
be restored to its previous state because of a race where it was
in the hijack goroutine.

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
2016-01-26 12:58:49 -08:00
Pei Su
ac382473d9 Fix race condition in execCommandGC
`daemon.execCommandGC`
The daemon object (grep execCommandGC) iterate over a map
(grep execCommands.Commands) in a goroutine.
Lock can't protect concurrency access in this case.
Exec command storage object should return a copy of commands instead.

Signed-off-by: Pei Su <sillyousu@gmail.com>
2016-01-26 12:58:49 -08:00
Wenyu You
64c6593a36 fix a spelling error of 'dnsmasq'
Signed-off-by: Wenyu You <21551128@zju.edu.cn>
2016-01-26 12:58:48 -08:00
Steve Durrheimer
37a51e452a Add zsh completion for 'docker {attach,exec,run,start} --detach-keys'
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2016-01-26 12:58:48 -08:00
Steve Durrheimer
78ece35f2b Add zsh completion for 'docker network create --ipam-opt' + Reordering for better maintainability
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2016-01-26 12:58:48 -08:00
Madhu Venugopal
c2443596bf IT for remote network driver & ungraceful restart
Signed-off-by: Madhu Venugopal <madhu@docker.com>
2016-01-26 12:58:48 -08:00
Madhu Venugopal
c9b16010a6 Vendor libnetwork v0.6.0-rc1
- Fixes docker/docker#19404
- Fixes ungraceful daemon restart issue in systemd with remote
  network plugin (https://github.com/docker/libnetwork/issues/813)

Signed-off-by: Madhu Venugopal <madhu@docker.com>
2016-01-26 12:58:48 -08:00
Aaron Lehmann
98ccb46f3d Vendor updated docker/distribution package
Fixes #19400

Note that this introduces an incompatibility with Docker 1.10-rc1,
because the media type used for schema1 manifests has been corrected in
the upstream distribution code. Docker 1.10-rc1 won't be able to pull
old manifests from Registry 2.3-rc0 and up, but because of this vendor
update, Docker 1.10-rc2 won't have this problem.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
2016-01-26 12:58:48 -08:00
Derek McGowan
c51c1caab7 Add more robust error handling on layer store creation
Add continue when layer fails on store creation
Trim whitespace from layerstore files to keep trailing space from failing a layer load

Fixes #19449

Signed-off-by: Derek McGowan <derek@mcgstyle.net> (github: dmcgowan)
2016-01-26 12:58:47 -08:00
Antonio Murdaca
aa8641d504 api: client: build: do not fall through if git isn't installed
Signed-off-by: Antonio Murdaca <runcom@redhat.com>
2016-01-26 12:58:47 -08:00
Jessica Frazelle
e75305e5f3 add send, recv, and x32 so we can install i386 pkgs on amd64
Signed-off-by: Jessica Frazelle <acidburn@docker.com>
2016-01-26 12:58:47 -08:00
Santhosh Manohar
3e54117f4a Vendoring miekg/dns @ 75e6e86cc601825c5dbcd4e0c209eab180997cd7
- Fixes the issue of Shutdown() not working, resulting in hung
  goroutines

Signed-off-by: Santhosh Manohar <santhosh@docker.com>
2016-01-26 12:58:47 -08:00
Kai Qiang Wu(Kennan)
ebc02ee93b Fix add host device example
The example is not right in parameter, and also
one command is same as first one, it should be typo
before, we should use 'rw' as example for that.

Signed-off-by: Kai Qiang Wu(Kennan) <wkqwu@cn.ibm.com>
2016-01-26 12:58:47 -08:00
Madhu Venugopal
f175dc5fb4 nil ptr check for endpointsettings when used with older clients
Signed-off-by: Madhu Venugopal <madhu@docker.com>
2016-01-26 12:58:47 -08:00
Zhang Wei
d9217acb11 bugfix: prevent creating network 'default'
Default is predefined network and is reserved, so we should stop user
from creating network with name `default`

Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
2016-01-26 12:58:46 -08:00
Christy Perez
35ca3304ff Move closeNotify to fix panic with newer golang
This is happening now due to improvements in net/http:
99fb19194c

To test, change the go version in the Dockerfile:
-ENV GO_VERSION 1.5.3
+ENV GO_VERSION 1.6beta2

More info here: https://github.com/golang/go/issues/14001

Signed-off-by: Christy Perez <christy@linux.vnet.ibm.com>
2016-01-26 12:58:46 -08:00
Daniel Dao
bfa80edf4b only close LogDriver after LogCopier is done
this prevents the copier from sending messages in the buffer to the closed
driver. If the copied took longer than the timeout to drain the buffer, this
aborts the copier read loop and return back so we can cleanup resources
properly.

Signed-off-by: Daniel Dao <dqminh@cloudflare.com>
2016-01-26 12:58:46 -08:00
Candid Dauth
2af5574795 Set TasksMax in addition to LimitNPROC in systemd service files
systemd sets an additional limit on processes and threads that defaults to 512 when run under Linux >= 4.3.
See more information here: http://unix.stackexchange.com/a/255603/59955

Signed-off-by: Candid Dauth <cdauth@cdauth.eu>
2016-01-26 12:58:46 -08:00
Harald Albers
c78eb02bb1 bash completion for docker network create --internal, --ipam-opt
Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-26 12:58:46 -08:00
Harald Albers
91ddf04563 bash completion for container linking and aliasing
Signed-off-by: Harald Albers <github@albersweb.de>
2016-01-26 12:58:46 -08:00
Avi Miller
2bffeb8a70 Add missing ? to specfile variable.
Signed-off-by: Avi Miller <avi.miller@oracle.com>
2016-01-26 12:58:45 -08:00
Avi Miller
245b1facb8 Restoring the RPM build process for Oracle Linux 6 and updating the docker-engine.spec
file to require the Unbreakable Enterprise Kernel Release 4 on both Oracle Linux 6
and Oracle Linux 7.

The UEK R4 provides the required kernel functionality for VxLAN support
required by Docker 1.9 and user namespace support required for 1.10+.

The build of Docker on Oracle Linux 6 requires some manipulation of the build
environment so that the CGO compiler uses the UEK R4 headers instead of the old
default kernel headers.

Signed-off-by: Avi Miller <avi.miller@oracle.com>
2016-01-26 12:58:45 -08:00
Steve Durrheimer
0e7fbdd62f Modify zsh completion for connecting/disconnecting non-running containers to networks
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2016-01-26 12:58:45 -08:00
Steve Durrheimer
0b8eafefd5 Add zsh completion for 'docker network create --internal'
Signed-off-by: Steve Durrheimer <s.durrheimer@gmail.com>
2016-01-26 12:58:45 -08:00
Brian Goff
81cd580d68 Fix panic on starting exec more than once
Issue was caused when exec is tarted, exits, then stated again.
In this case, `Close` is called twice, which closes a channel twice.

Changes execConfig.ExitCode to a pointer so we can test if the it has
been set or not.
This allows us to return early when the exec has already been run.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
2016-01-26 12:58:45 -08:00
437 changed files with 8551 additions and 3729 deletions

View File

@@ -5,6 +5,235 @@ information on the list of deprecated flags and APIs please have a look at
https://docs.docker.com/misc/deprecated/ where target removal dates can also
be found.
## 1.10.3 (2016-03-10)
### Runtime
- Fix Docker client exiting with an "Unrecognized input header" error [#20706](https://github.com/docker/docker/pull/20706)
- Fix Docker exiting if Exec is started with both `AttachStdin` and `Detach` [#20647](https://github.com/docker/docker/pull/20647)
### Distribution
- Fix a crash when pushing multiple images sharing the same layers to the same repository in parallel [#20831](https://github.com/docker/docker/pull/20831)
- Fix a panic when pushing images to a registry which uses a misconfigured token service [#21030](https://github.com/docker/docker/pull/21030)
### Plugin system
- Fix issue preventing volume plugins to start when SELinux is enabled [#20834](https://github.com/docker/docker/pull/20834)
- Prevent Docker from exiting if a volume plugin returns a null response for Get requests [#20682](https://github.com/docker/docker/pull/20682)
- Fix plugin system leaking file descriptors if a plugin has an error [#20680](https://github.com/docker/docker/pull/20680)
### Security
- Fix linux32 emulation to fail during docker build [#20672](https://github.com/docker/docker/pull/20672)
It was due to the `personality` syscall being blocked by the default seccomp profile.
- Fix Oracle XE 10g failing to start in a container [#20981](https://github.com/docker/docker/pull/20981)
It was due to the `ipc` syscall being blocked by the default seccomp profile.
- Fix user namespaces not working on Linux From Scratch [#20685](https://github.com/docker/docker/pull/20685)
- Fix issue preventing daemon to start if userns is enabled and the `subuid` or `subgid` files contain comments [#20725](https://github.com/docker/docker/pull/20725)
## 1.10.2 (2016-02-22)
### Runtime
- Prevent systemd from deleting containers' cgroups when its configuration is reloaded [#20518](https://github.com/docker/docker/pull/20518)
- Fix SELinux issues by disregarding `--read-only` when mounting `/dev/mqueue` [#20333](https://github.com/docker/docker/pull/20333)
- Fix chown permissions used during `docker cp` when userns is used [#20446](https://github.com/docker/docker/pull/20446)
- Fix configuration loading issue with all booleans defaulting to `true` [#20471](https://github.com/docker/docker/pull/20471)
- Fix occasional panic with `docker logs -f` [#20522](https://github.com/docker/docker/pull/20522)
### Distribution
- Keep layer reference if deletion failed to avoid a badly inconsistent state [#20513](https://github.com/docker/docker/pull/20513)
- Handle gracefully a corner case when canceling migration [#20372](https://github.com/docker/docker/pull/20372)
- Fix docker import on compressed data [#20367](https://github.com/docker/docker/pull/20367)
- Fix tar-split files corruption during migration that later cause docker push and docker save to fail [#20458](https://github.com/docker/docker/pull/20458)
### Networking
- Fix daemon crash if embedded DNS is sent garbage [#20510](https://github.com/docker/docker/pull/20510)
### Volumes
- Fix issue with multiple volume references with same name [#20381](https://github.com/docker/docker/pull/20381)
### Security
- Fix potential cache corruption and delegation conflict issues [#20523](https://github.com/docker/docker/pull/20523)
## 1.10.1 (2016-02-11)
### Runtime
* Do not stop daemon on migration hard failure [#20156](https://github.com/docker/docker/pull/20156)
- Fix various issues with migration to content-addressable images [#20058](https://github.com/docker/docker/pull/20058)
- Fix ZFS permission bug with user namespaces [#20045](https://github.com/docker/docker/pull/20045)
- Do not leak /dev/mqueue from the host to all containers, keep it container-specific [#19876](https://github.com/docker/docker/pull/19876) [#20133](https://github.com/docker/docker/pull/20133)
- Fix `docker ps --filter before=...` to not show stopped containers without providing `-a` flag [#20135](https://github.com/docker/docker/pull/20135)
### Security
- Fix issue preventing docker events to work properly with authorization plugin [#20002](https://github.com/docker/docker/pull/20002)
### Distribution
* Add additional verifications and prevent from uploading invalid data to registries [#20164](https://github.com/docker/docker/pull/20164)
- Fix regression preventing uppercase characters in image reference hostname [#20175](https://github.com/docker/docker/pull/20175)
### Networking
- Fix embedded DNS for user-defined networks in the presence of firewalld [#20060](https://github.com/docker/docker/pull/20060)
- Fix issue where removing a network during shutdown left Docker inoperable [#20181](https://github.com/docker/docker/issues/20181) [#20235](https://github.com/docker/docker/issues/20235)
- Embedded DNS is now able to return compressed results [#20181](https://github.com/docker/docker/issues/20181)
- Fix port-mapping issue with `userland-proxy=false` [#20181](https://github.com/docker/docker/issues/20181)
### Logging
- Fix bug where tcp+tls protocol would be rejected [#20109](https://github.com/docker/docker/pull/20109)
### Volumes
- Fix issue whereby older volume drivers would not receive volume options [#19983](https://github.com/docker/docker/pull/19983)
### Misc
- Remove TasksMax from Docker systemd service [#20167](https://github.com/docker/docker/pull/20167)
## 1.10.0 (2016-02-04)
**IMPORTANT**: Docker 1.10 uses a new content-addressable storage for images and layers.
A migration is performed the first time docker is run, and can take a significant amount of time depending on the number of images present.
Refer to this page on the wiki for more information: https://github.com/docker/docker/wiki/Engine-v1.10.0-content-addressability-migration
We also released a cool migration utility that enables you to perform the migration before updating to reduce downtime.
Engine 1.10 migrator can be found on Docker Hub: https://hub.docker.com/r/docker/v1.10-migrator/
### Runtime
+ New `docker update` command that allows updating resource constraints on running containers [#15078](https://github.com/docker/docker/pull/15078)
+ Add `--tmpfs` flag to `docker run` to create a tmpfs mount in a container [#13587](https://github.com/docker/docker/pull/13587)
+ Add `--format` flag to `docker images` command [#17692](https://github.com/docker/docker/pull/17692)
+ Allow to set daemon configuration in a file and hot-reload it with the `SIGHUP` signal [#18587](https://github.com/docker/docker/pull/18587)
+ Updated docker events to include more meta-data and event types [#18888](https://github.com/docker/docker/pull/18888)
This change is backward compatible in the API, but not on the CLI.
+ Add `--blkio-weight-device` flag to `docker run` [#13959](https://github.com/docker/docker/pull/13959)
+ Add `--device-read-bps` and `--device-write-bps` flags to `docker run` [#14466](https://github.com/docker/docker/pull/14466)
+ Add `--device-read-iops` and `--device-write-iops` flags to `docker run` [#15879](https://github.com/docker/docker/pull/15879)
+ Add `--oom-score-adj` flag to `docker run` [#16277](https://github.com/docker/docker/pull/16277)
+ Add `--detach-keys` flag to `attach`, `run`, `start` and `exec` commands to override the default key sequence that detaches from a container [#15666](https://github.com/docker/docker/pull/15666)
+ Add `--shm-size` flag to `run`, `create` and `build` to set the size of `/dev/shm` [#16168](https://github.com/docker/docker/pull/16168)
+ Show the number of running, stopped, and paused containers in `docker info` [#19249](https://github.com/docker/docker/pull/19249)
+ Show the `OSType` and `Architecture` in `docker info` [#17478](https://github.com/docker/docker/pull/17478)
+ Add `--cgroup-parent` flag on `daemon` to set cgroup parent for all containers [#19062](https://github.com/docker/docker/pull/19062)
+ Add `-L` flag to docker cp to follow symlinks [#16613](https://github.com/docker/docker/pull/16613)
+ New `status=dead` filter for `docker ps` [#17908](https://github.com/docker/docker/pull/17908)
* Change `docker run` exit codes to distinguish between runtime and application errors [#14012](https://github.com/docker/docker/pull/14012)
* Enhance `docker events --since` and `--until` to support nanoseconds and timezones [#17495](https://github.com/docker/docker/pull/17495)
* Add `--all`/`-a` flag to `stats` to include both running and stopped containers [#16742](https://github.com/docker/docker/pull/16742)
* Change the default cgroup-driver to `cgroupfs` [#17704](https://github.com/docker/docker/pull/17704)
* Emit a "tag" event when tagging an image with `build -t` [#17115](https://github.com/docker/docker/pull/17115)
* Best effort for linked containers' start order when starting the daemon [#18208](https://github.com/docker/docker/pull/18208)
* Add ability to add multiple tags on `build` [#15780](https://github.com/docker/docker/pull/15780)
* Permit `OPTIONS` request against any url, thus fixing issue with CORS [#19569](https://github.com/docker/docker/pull/19569)
- Fix the `--quiet` flag on `docker build` to actually be quiet [#17428](https://github.com/docker/docker/pull/17428)
- Fix `docker images --filter dangling=false` to now show all non-dangling images [#19326](https://github.com/docker/docker/pull/19326)
- Fix race condition causing autorestart turning off on restart [#17629](https://github.com/docker/docker/pull/17629)
- Recognize GPFS filesystems [#19216](https://github.com/docker/docker/pull/19216)
- Fix obscure bug preventing to start containers [#19751](https://github.com/docker/docker/pull/19751)
- Forbid `exec` during container restart [#19722](https://github.com/docker/docker/pull/19722)
- devicemapper: Increasing `--storage-opt dm.basesize` will now increase the base device size on daemon restart [#19123](https://github.com/docker/docker/pull/19123)
### Security
+ Add `--userns-remap` flag to `daemon` to support user namespaces (previously in experimental) [#19187](https://github.com/docker/docker/pull/19187)
+ Add support for custom seccomp profiles in `--security-opt` [#17989](https://github.com/docker/docker/pull/17989)
+ Add default seccomp profile [#18780](https://github.com/docker/docker/pull/18780)
+ Add `--authorization-plugin` flag to `daemon` to customize ACLs [#15365](https://github.com/docker/docker/pull/15365)
+ Docker Content Trust now supports the ability to read and write user delegations [#18887](https://github.com/docker/docker/pull/18887)
This is an optional, opt-in feature that requires the explicit use of the Notary command-line utility in order to be enabled.
Enabling delegation support in a specific repository will break the ability of Docker 1.9 and 1.8 to pull from that repository, if content trust is enabled.
* Allow SELinux to run in a container when using the BTRFS storage driver [#16452](https://github.com/docker/docker/pull/16452)
### Distribution
* Use content-addressable storage for images and layers [#17924](https://github.com/docker/docker/pull/17924)
Note that a migration is performed the first time docker is run; it can take a significant amount of time depending on the number of images and containers present.
Images no longer depend on the parent chain but contain a list of layer references.
`docker load`/`docker save` tarballs now also contain content-addressable image configurations.
For more information: https://github.com/docker/docker/wiki/Engine-v1.10.0-content-addressability-migration
* Add support for the new [manifest format ("schema2")](https://github.com/docker/distribution/blob/master/docs/spec/manifest-v2-2.md) [#18785](https://github.com/docker/docker/pull/18785)
* Lots of improvements for push and pull: performance++, retries on failed downloads, cancelling on client disconnect [#18353](https://github.com/docker/docker/pull/18353), [#18418](https://github.com/docker/docker/pull/18418), [#19109](https://github.com/docker/docker/pull/19109), [#18353](https://github.com/docker/docker/pull/18353)
* Limit v1 protocol fallbacks [#18590](https://github.com/docker/docker/pull/18590)
- Fix issue where docker could hang indefinitely waiting for a nonexistent process to pull an image [#19743](https://github.com/docker/docker/pull/19743)
### Networking
+ Use DNS-based discovery instead of `/etc/hosts` [#19198](https://github.com/docker/docker/pull/19198)
+ Support for network-scoped alias using `--net-alias` on `run` and `--alias` on `network connect` [#19242](https://github.com/docker/docker/pull/19242)
+ Add `--ip` and `--ip6` on `run` and `network connect` to support custom IP addresses for a container in a network [#19001](https://github.com/docker/docker/pull/19001)
+ Add `--ipam-opt` to `network create` for passing custom IPAM options [#17316](https://github.com/docker/docker/pull/17316)
+ Add `--internal` flag to `network create` to restrict external access to and from the network [#19276](https://github.com/docker/docker/pull/19276)
+ Add `kv.path` option to `--cluster-store-opt` [#19167](https://github.com/docker/docker/pull/19167)
+ Add `discovery.heartbeat` and `discovery.ttl` options to `--cluster-store-opt` to configure discovery TTL and heartbeat timer [#18204](https://github.com/docker/docker/pull/18204)
+ Add `--format` flag to `network inspect` [#17481](https://github.com/docker/docker/pull/17481)
+ Add `--link` to `network connect` to provide a container-local alias [#19229](https://github.com/docker/docker/pull/19229)
+ Support for Capability exchange with remote IPAM plugins [#18775](https://github.com/docker/docker/pull/18775)
+ Add `--force` to `network disconnect` to force container to be disconnected from network [#19317](https://github.com/docker/docker/pull/19317)
* Support for multi-host networking using built-in overlay driver for all engine supported kernels: 3.10+ [#18775](https://github.com/docker/docker/pull/18775)
* `--link` is now supported on `docker run` for containers in user-defined network [#19229](https://github.com/docker/docker/pull/19229)
* Enhance `docker network rm` to allow removing multiple networks [#17489](https://github.com/docker/docker/pull/17489)
* Include container names in `network inspect` [#17615](https://github.com/docker/docker/pull/17615)
* Include auto-generated subnets for user-defined networks in `network inspect` [#17316](https://github.com/docker/docker/pull/17316)
* Add `--filter` flag to `network ls` to hide predefined networks [#17782](https://github.com/docker/docker/pull/17782)
* Add support for network connect/disconnect to stopped containers [#18906](https://github.com/docker/docker/pull/18906)
* Add network ID to container inspect [#19323](https://github.com/docker/docker/pull/19323)
- Fix MTU issue where Docker would not start with two or more default routes [#18108](https://github.com/docker/docker/pull/18108)
- Fix duplicate IP address for containers [#18106](https://github.com/docker/docker/pull/18106)
- Fix issue preventing sometimes docker from creating the bridge network [#19338](https://github.com/docker/docker/pull/19338)
- Do not substitute 127.0.0.1 name server when using `--net=host` [#19573](https://github.com/docker/docker/pull/19573)
### Logging
+ New logging driver for Splunk [#16488](https://github.com/docker/docker/pull/16488)
+ Add support for syslog over TCP+TLS [#18998](https://github.com/docker/docker/pull/18998)
* Enhance `docker logs --since` and `--until` to support nanoseconds and time [#17495](https://github.com/docker/docker/pull/17495)
* Enhance AWS logs to auto-detect region [#16640](https://github.com/docker/docker/pull/16640)
### Volumes
+ Add support to set the mount propagation mode for a volume [#17034](https://github.com/docker/docker/pull/17034)
* Add `ls` and `inspect` endpoints to volume plugin API [#16534](https://github.com/docker/docker/pull/16534)
Existing plugins need to make use of these new APIs to satisfy users' expectation
For that, please use the new MIME type `application/vnd.docker.plugins.v1.2+json` [#19549](https://github.com/docker/docker/pull/19549)
- Fix data not being copied to named volumes [#19175](https://github.com/docker/docker/pull/19175)
- Fix issues preventing volume drivers from being containerized [#19500](https://github.com/docker/docker/pull/19500)
- Fix `docker volumes ls --dangling=false` to now show all non-dangling volumes [#19671](https://github.com/docker/docker/pull/19671)
- Do not remove named volumes on container removal [#19568](https://github.com/docker/docker/pull/19568)
- Allow external volume drivers to host anonymous volumes [#19190](https://github.com/docker/docker/pull/19190)
### Builder
+ Add support for `**` in `.dockerignore` to wildcard multiple levels of directories [#17090](https://github.com/docker/docker/pull/17090)
- Fix handling of UTF-8 characters in Dockerfiles [#17055](https://github.com/docker/docker/pull/17055)
- Fix permissions problem when reading from STDIN [#19283](https://github.com/docker/docker/pull/19283)
### Client
+ Add support for overriding the API version to use via an `DOCKER_API_VERSION` environment-variable [#15964](https://github.com/docker/docker/pull/15964)
- Fix a bug preventing Windows clients to log in to Docker Hub [#19891](https://github.com/docker/docker/pull/19891)
### Misc
* systemd: Set TasksMax in addition to LimitNPROC in systemd service file [#19391](https://github.com/docker/docker/pull/19391)
### Deprecations
* Remove LXC support. The LXC driver was deprecated in Docker 1.8, and has now been removed [#17700](https://github.com/docker/docker/pull/17700)
* Remove `--exec-driver` daemon flag, because it is no longer in use [#17700](https://github.com/docker/docker/pull/17700)
* Remove old deprecated single-dashed long CLI flags (such as `-rm`; use `--rm` instead) [#17724](https://github.com/docker/docker/pull/17724)
* Deprecate HostConfig at API container start [#17799](https://github.com/docker/docker/pull/17799)
* Deprecate docker packages for newly EOL'd Linux distributions: Fedora 21 and Ubuntu 15.04 (Vivid) [#18794](https://github.com/docker/docker/pull/18794), [#18809](https://github.com/docker/docker/pull/18809)
* Deprecate `-f` flag for docker tag [#18350](https://github.com/docker/docker/pull/18350)
## 1.9.1 (2015-11-21)
### Runtime

View File

@@ -88,7 +88,7 @@ RUN cd /usr/local/lvm2 \
# Install Go
# IMPORTANT: If the version of Go is updated, the Windows to Linux CI machines
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
# will need updating, to avoid errors. Ping #docker-maintainers on IRC
# with a heads-up.
ENV GO_VERSION 1.5.3
RUN curl -fsSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" \
@@ -155,7 +155,7 @@ RUN set -x \
# both. This allows integration-cli tests to cover push/pull with both schema1
# and schema2 manifests.
ENV REGISTRY_COMMIT_SCHEMA1 ec87e9b6971d831f0eff752ddb54fb64693e51cd
ENV REGISTRY_COMMIT cb08de17d74bef86ce6c5abe8b240e282f5750be
ENV REGISTRY_COMMIT 47a064d4195a9b56133891bbb13620c3ac83a827
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/distribution.git "$GOPATH/src/github.com/docker/distribution" \
@@ -168,7 +168,7 @@ RUN set -x \
&& rm -rf "$GOPATH"
# Install notary server
ENV NOTARY_VERSION docker-v1.10-3
ENV NOTARY_VERSION docker-v1.10.2-1
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \

View File

@@ -145,7 +145,7 @@ RUN set -x \
&& rm -rf "$GOPATH"
# Install notary server
ENV NOTARY_VERSION docker-v1.10-2
ENV NOTARY_VERSION docker-v1.10.2-1
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \

View File

@@ -116,14 +116,14 @@ RUN set -x \
&& rm -rf "$GOPATH"
# Install notary server
ENV NOTARY_COMMIT 8e8122eb5528f621afcd4e2854c47302f17392f7
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_COMMIT") \
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
&& rm -rf "$GOPATH"
#ENV NOTARY_VERSION docker-v1.10.2-1
#RUN set -x \
# && export GOPATH="$(mktemp -d)" \
# && git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
# && (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
# && GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
# go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
# && rm -rf "$GOPATH"
# Get the "docker-py" source so we can run their integration tests
ENV DOCKER_PY_COMMIT e2878cbcc3a7eef99917adc1be252800b0e41ece

View File

@@ -116,11 +116,11 @@ RUN set -x \
&& rm -rf "$GOPATH"
# Install notary server
ENV NOTARY_COMMIT 8e8122eb5528f621afcd4e2854c47302f17392f7
ENV NOTARY_VERSION docker-v1.10.2-1
RUN set -x \
&& export GOPATH="$(mktemp -d)" \
&& git clone https://github.com/docker/notary.git "$GOPATH/src/github.com/docker/notary" \
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_COMMIT") \
&& (cd "$GOPATH/src/github.com/docker/notary" && git checkout -q "$NOTARY_VERSION") \
&& GOPATH="$GOPATH/src/github.com/docker/notary/Godeps/_workspace:$GOPATH" \
go build -o /usr/local/bin/notary-server github.com/docker/notary/cmd/notary-server \
&& rm -rf "$GOPATH"

View File

@@ -167,7 +167,7 @@ Under the hood
Under the hood, Docker is built on the following components:
* The
[cgroups](https://www.kernel.org/doc/Documentation/cgroups/cgroups.txt)
[cgroups](https://www.kernel.org/doc/Documentation/cgroup-v1/cgroups.txt)
and
[namespaces](http://man7.org/linux/man-pages/man7/namespaces.7.html)
capabilities of the Linux kernel

View File

@@ -1 +1 @@
1.10.0-dev
1.10.3-rc2

View File

@@ -75,6 +75,12 @@ func (cli *DockerCli) CmdAttach(args ...string) error {
return err
}
defer resp.Close()
if in != nil && c.Config.Tty {
if err := cli.setRawTerminal(); err != nil {
return err
}
defer cli.restoreTerminal(in)
}
if err := cli.holdHijackedConnection(c.Config.Tty, in, cli.out, cli.err, resp); err != nil {
return err

View File

@@ -82,9 +82,6 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
err error
)
_, err = exec.LookPath("git")
hasGit := err == nil
specifiedContext := cmd.Arg(0)
var (
@@ -105,7 +102,7 @@ func (cli *DockerCli) CmdBuild(args ...string) error {
switch {
case specifiedContext == "-":
context, relDockerfile, err = getContextFromReader(cli.in, *dockerfileName)
case urlutil.IsGitURL(specifiedContext) && hasGit:
case urlutil.IsGitURL(specifiedContext):
tempDir, relDockerfile, err = getContextFromGitURL(specifiedContext, *dockerfileName)
case urlutil.IsURL(specifiedContext):
context, relDockerfile, err = getContextFromURL(progBuff, specifiedContext, *dockerfileName)
@@ -510,6 +507,9 @@ func getContextFromReader(r io.ReadCloser, dockerfileName string) (out io.ReadCl
// path of the dockerfile in that context directory, and a non-nil error on
// success.
func getContextFromGitURL(gitURL, dockerfileName string) (absContextDir, relDockerfile string, err error) {
if _, err := exec.LookPath("git"); err != nil {
return "", "", fmt.Errorf("unable to find 'git': %v", err)
}
if absContextDir, err = gitutils.Clone(gitURL); err != nil {
return "", "", fmt.Errorf("unable to 'git clone' to temporary context directory: %v", err)
}

View File

@@ -44,6 +44,8 @@ type DockerCli struct {
isTerminalOut bool
// client is the http client that performs all API operations
client client.APIClient
// state holds the terminal state
state *term.State
}
// Initialize calls the init function that will setup the configuration for the client
@@ -79,6 +81,31 @@ func (cli *DockerCli) ImagesFormat() string {
return cli.configFile.ImagesFormat
}
func (cli *DockerCli) setRawTerminal() error {
if cli.isTerminalIn && os.Getenv("NORAW") == "" {
state, err := term.SetRawTerminal(cli.inFd)
if err != nil {
return err
}
cli.state = state
}
return nil
}
func (cli *DockerCli) restoreTerminal(in io.Closer) error {
if cli.state != nil {
term.RestoreTerminal(cli.inFd, cli.state)
}
// WARNING: DO NOT REMOVE THE OS CHECK !!!
// For some reason this Close call blocks on darwin..
// As the client exists right after, simply discard the close
// until we find a better solution.
if in != nil && runtime.GOOS != "darwin" {
return in.Close()
}
return nil
}
// NewDockerCli returns a DockerCli instance with IO output and error streams set by in, out and err.
// The key file, protocol (i.e. unix) and address are passed in as strings, along with the tls.Config. If the tls.Config
// is set the client scheme will be set to https.

View File

@@ -40,8 +40,8 @@ func (cli *DockerCli) pullImageCustomOut(image string, out io.Writer) error {
return err
}
// Resolve the Auth config relevant for this server
encodedAuth, err := cli.encodeRegistryAuth(repoInfo.Index)
authConfig := cli.resolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index)
encodedAuth, err := encodeAuthToBase64(authConfig)
if err != nil {
return err
}

View File

@@ -87,6 +87,12 @@ func (cli *DockerCli) CmdExec(args ...string) error {
return err
}
defer resp.Close()
if in != nil && execConfig.Tty {
if err := cli.setRawTerminal(); err != nil {
return err
}
defer cli.restoreTerminal(in)
}
errCh = promise.Go(func() error {
return cli.holdHijackedConnection(execConfig.Tty, in, out, stderr, resp)
})

View File

@@ -2,41 +2,19 @@ package client
import (
"io"
"os"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/stdcopy"
"github.com/docker/docker/pkg/term"
"github.com/docker/engine-api/types"
)
func (cli *DockerCli) holdHijackedConnection(setRawTerminal bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error {
var (
err error
oldState *term.State
)
if inputStream != nil && setRawTerminal && cli.isTerminalIn && os.Getenv("NORAW") == "" {
oldState, err = term.SetRawTerminal(cli.inFd)
if err != nil {
return err
}
defer term.RestoreTerminal(cli.inFd, oldState)
}
func (cli *DockerCli) holdHijackedConnection(tty bool, inputStream io.ReadCloser, outputStream, errorStream io.Writer, resp types.HijackedResponse) error {
var err error
receiveStdout := make(chan error, 1)
if outputStream != nil || errorStream != nil {
go func() {
defer func() {
if inputStream != nil {
if setRawTerminal && cli.isTerminalIn {
term.RestoreTerminal(cli.inFd, oldState)
}
inputStream.Close()
}
}()
// When TTY is ON, use regular copy
if setRawTerminal && outputStream != nil {
if tty && outputStream != nil {
_, err = io.Copy(outputStream, resp.Reader)
} else {
_, err = stdcopy.StdCopy(outputStream, errorStream, resp.Reader)

View File

@@ -42,6 +42,11 @@ func (cli *DockerCli) CmdInfo(args ...string) error {
}
}
if info.SystemStatus != nil {
for _, pair := range info.SystemStatus {
fmt.Fprintf(cli.out, "%s: %s\n", pair[0], pair[1])
}
}
ioutils.FprintfIfNotEmpty(cli.out, "Execution Driver: %s\n", info.ExecutionDriver)
ioutils.FprintfIfNotEmpty(cli.out, "Logging Driver: %s\n", info.LoggingDriver)

View File

@@ -11,7 +11,6 @@ import (
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/pkg/term"
"github.com/docker/docker/registry"
"github.com/docker/engine-api/client"
"github.com/docker/engine-api/types"
)
@@ -22,14 +21,12 @@ import (
//
// Usage: docker login SERVER
func (cli *DockerCli) CmdLogin(args ...string) error {
cmd := Cli.Subcmd("login", []string{"[SERVER]"}, Cli.DockerCommands["login"].Description+".\nIf no server is specified \""+registry.IndexServer+"\" is the default.", true)
cmd := Cli.Subcmd("login", []string{"[SERVER]"}, Cli.DockerCommands["login"].Description+".\nIf no server is specified, the default is defined by the daemon.", true)
cmd.Require(flag.Max, 1)
var username, password, email string
cmd.StringVar(&username, []string{"u", "-username"}, "", "Username")
cmd.StringVar(&password, []string{"p", "-password"}, "", "Password")
cmd.StringVar(&email, []string{"e", "-email"}, "", "Email")
flUser := cmd.String([]string{"u", "-username"}, "", "Username")
flPassword := cmd.String([]string{"p", "-password"}, "", "Password")
flEmail := cmd.String([]string{"e", "-email"}, "", "Email")
cmd.ParseFlags(args, true)
@@ -38,89 +35,19 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
cli.in = os.Stdin
}
serverAddress := registry.IndexServer
var serverAddress string
if len(cmd.Args()) > 0 {
serverAddress = cmd.Arg(0)
}
promptDefault := func(prompt string, configDefault string) {
if configDefault == "" {
fmt.Fprintf(cli.out, "%s: ", prompt)
} else {
fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
}
}
readInput := func(in io.Reader, out io.Writer) string {
reader := bufio.NewReader(in)
line, _, err := reader.ReadLine()
if err != nil {
fmt.Fprintln(out, err.Error())
os.Exit(1)
}
return string(line)
}
authconfig, ok := cli.configFile.AuthConfigs[serverAddress]
if !ok {
authconfig = types.AuthConfig{}
}
if username == "" {
promptDefault("Username", authconfig.Username)
username = readInput(cli.in, cli.out)
username = strings.TrimSpace(username)
if username == "" {
username = authconfig.Username
}
}
// Assume that a different username means they may not want to use
// the password or email from the config file, so prompt them
if username != authconfig.Username {
if password == "" {
oldState, err := term.SaveState(cli.inFd)
if err != nil {
return err
}
fmt.Fprintf(cli.out, "Password: ")
term.DisableEcho(cli.inFd, oldState)
password = readInput(cli.in, cli.out)
fmt.Fprint(cli.out, "\n")
term.RestoreTerminal(cli.inFd, oldState)
if password == "" {
return fmt.Errorf("Error : Password Required")
}
}
if email == "" {
promptDefault("Email", authconfig.Email)
email = readInput(cli.in, cli.out)
if email == "" {
email = authconfig.Email
}
}
} else {
// However, if they don't override the username use the
// password or email from the cmd line if specified. IOW, allow
// then to change/override them. And if not specified, just
// use what's in the config file
if password == "" {
password = authconfig.Password
}
if email == "" {
email = authconfig.Email
}
serverAddress = cli.electAuthServer()
}
authconfig.Username = username
authconfig.Password = password
authconfig.Email = email
authconfig.ServerAddress = serverAddress
cli.configFile.AuthConfigs[serverAddress] = authconfig
auth := cli.configFile.AuthConfigs[serverAddress]
response, err := cli.client.RegistryLogin(auth)
authConfig, err := cli.configureAuth(*flUser, *flPassword, *flEmail, serverAddress)
if err != nil {
return err
}
response, err := cli.client.RegistryLogin(authConfig)
if err != nil {
if client.IsErrUnauthorized(err) {
delete(cli.configFile.AuthConfigs, serverAddress)
@@ -141,3 +68,80 @@ func (cli *DockerCli) CmdLogin(args ...string) error {
}
return nil
}
func (cli *DockerCli) promptWithDefault(prompt string, configDefault string) {
if configDefault == "" {
fmt.Fprintf(cli.out, "%s: ", prompt)
} else {
fmt.Fprintf(cli.out, "%s (%s): ", prompt, configDefault)
}
}
func (cli *DockerCli) configureAuth(flUser, flPassword, flEmail, serverAddress string) (types.AuthConfig, error) {
authconfig, ok := cli.configFile.AuthConfigs[serverAddress]
if !ok {
authconfig = types.AuthConfig{}
}
if flUser == "" {
cli.promptWithDefault("Username", authconfig.Username)
flUser = readInput(cli.in, cli.out)
flUser = strings.TrimSpace(flUser)
if flUser == "" {
flUser = authconfig.Username
}
}
if flPassword == "" {
oldState, err := term.SaveState(cli.inFd)
if err != nil {
return authconfig, err
}
fmt.Fprintf(cli.out, "Password: ")
term.DisableEcho(cli.inFd, oldState)
flPassword = readInput(cli.in, cli.out)
fmt.Fprint(cli.out, "\n")
term.RestoreTerminal(cli.inFd, oldState)
if flPassword == "" {
return authconfig, fmt.Errorf("Error : Password Required")
}
}
// Assume that a different username means they may not want to use
// the email from the config file, so prompt it
if flUser != authconfig.Username {
if flEmail == "" {
cli.promptWithDefault("Email", authconfig.Email)
flEmail = readInput(cli.in, cli.out)
if flEmail == "" {
flEmail = authconfig.Email
}
}
} else {
// However, if they don't override the username use the
// email from the cmd line if specified. IOW, allow
// then to change/override them. And if not specified, just
// use what's in the config file
if flEmail == "" {
flEmail = authconfig.Email
}
}
authconfig.Username = flUser
authconfig.Password = flPassword
authconfig.Email = flEmail
authconfig.ServerAddress = serverAddress
cli.configFile.AuthConfigs[serverAddress] = authconfig
return authconfig, nil
}
func readInput(in io.Reader, out io.Writer) string {
reader := bufio.NewReader(in)
line, _, err := reader.ReadLine()
if err != nil {
fmt.Fprintln(out, err.Error())
os.Exit(1)
}
return string(line)
}

View File

@@ -5,7 +5,6 @@ import (
Cli "github.com/docker/docker/cli"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/registry"
)
// CmdLogout logs a user out from a Docker registry.
@@ -14,14 +13,16 @@ import (
//
// Usage: docker logout [SERVER]
func (cli *DockerCli) CmdLogout(args ...string) error {
cmd := Cli.Subcmd("logout", []string{"[SERVER]"}, Cli.DockerCommands["logout"].Description+".\nIf no server is specified \""+registry.IndexServer+"\" is the default.", true)
cmd := Cli.Subcmd("logout", []string{"[SERVER]"}, Cli.DockerCommands["logout"].Description+".\nIf no server is specified, the default is defined by the daemon.", true)
cmd.Require(flag.Max, 1)
cmd.ParseFlags(args, true)
serverAddress := registry.IndexServer
var serverAddress string
if len(cmd.Args()) > 0 {
serverAddress = cmd.Arg(0)
} else {
serverAddress = cli.electAuthServer()
}
if _, ok := cli.configFile.AuthConfigs[serverAddress]; !ok {

View File

@@ -54,7 +54,7 @@ func (cli *DockerCli) CmdPull(args ...string) error {
return err
}
authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index)
authConfig := cli.resolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index)
requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "pull")
if isTrusted() && !ref.HasDigest() {

View File

@@ -42,7 +42,7 @@ func (cli *DockerCli) CmdPush(args ...string) error {
return err
}
// Resolve the Auth config relevant for this server
authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index)
authConfig := cli.resolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index)
requestPrivilege := cli.registryAuthenticationPrivilegedFunc(repoInfo.Index, "push")
if isTrusted() {

View File

@@ -207,6 +207,12 @@ func (cli *DockerCli) CmdRun(args ...string) error {
if err != nil {
return err
}
if in != nil && config.Tty {
if err := cli.setRawTerminal(); err != nil {
return err
}
defer cli.restoreTerminal(in)
}
errCh = promise.Go(func() error {
return cli.holdHijackedConnection(config.Tty, in, out, stderr, resp)
})

View File

@@ -36,7 +36,7 @@ func (cli *DockerCli) CmdSearch(args ...string) error {
return err
}
authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, indexInfo)
authConfig := cli.resolveAuthConfig(cli.configFile.AuthConfigs, indexInfo)
requestPrivilege := cli.registryAuthenticationPrivilegedFunc(indexInfo, "search")
encodedAuth, err := encodeAuthToBase64(authConfig)

View File

@@ -96,6 +96,12 @@ func (cli *DockerCli) CmdStart(args ...string) error {
return err
}
defer resp.Close()
if in != nil && c.Config.Tty {
if err := cli.setRawTerminal(); err != nil {
return err
}
defer cli.restoreTerminal(in)
}
cErr := promise.Go(func() error {
return cli.holdHijackedConnection(c.Config.Tty, in, cli.out, cli.err, resp)

View File

@@ -234,7 +234,7 @@ func (cli *DockerCli) trustedReference(ref reference.NamedTagged) (reference.Can
}
// Resolve the Auth config relevant for this server
authConfig := registry.ResolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index)
authConfig := cli.resolveAuthConfig(cli.configFile.AuthConfigs, repoInfo.Index)
notaryRepo, err := cli.getNotaryRepository(repoInfo, authConfig)
if err != nil {

View File

@@ -23,7 +23,7 @@ func (cli *DockerCli) CmdUpdate(args ...string) error {
flCPUShares := cmd.Int64([]string{"#c", "-cpu-shares"}, 0, "CPU shares (relative weight)")
flMemoryString := cmd.String([]string{"m", "-memory"}, "", "Memory limit")
flMemoryReservation := cmd.String([]string{"-memory-reservation"}, "", "Memory soft limit")
flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Total memory (memory + swap), '-1' to disable swap")
flMemorySwap := cmd.String([]string{"-memory-swap"}, "", "Swap limit equal to memory plus swap: '-1' to enable unlimited swap")
flKernelMemory := cmd.String([]string{"-kernel-memory"}, "", "Kernel memory limit")
cmd.Require(flag.Min, 1)

View File

@@ -7,6 +7,7 @@ import (
"os"
gosignal "os/signal"
"runtime"
"strings"
"time"
"github.com/Sirupsen/logrus"
@@ -18,6 +19,20 @@ import (
registrytypes "github.com/docker/engine-api/types/registry"
)
func (cli *DockerCli) electAuthServer() string {
// The daemon `/info` endpoint informs us of the default registry being
// used. This is essential in cross-platforms environment, where for
// example a Linux client might be interacting with a Windows daemon, hence
// the default registry URL might be Windows specific.
serverAddress := registry.IndexServer
if info, err := cli.client.Info(); err != nil {
fmt.Fprintf(cli.out, "Warning: failed to get default registry endpoint from daemon (%v). Using system default: %s\n", err, serverAddress)
} else {
serverAddress = info.IndexServerAddress
}
return serverAddress
}
// encodeAuthToBase64 serializes the auth configuration as JSON base64 payload
func encodeAuthToBase64(authConfig types.AuthConfig) (string, error) {
buf, err := json.Marshal(authConfig)
@@ -35,10 +50,12 @@ func (cli *DockerCli) encodeRegistryAuth(index *registrytypes.IndexInfo) (string
func (cli *DockerCli) registryAuthenticationPrivilegedFunc(index *registrytypes.IndexInfo, cmdName string) client.RequestPrivilegeFunc {
return func() (string, error) {
fmt.Fprintf(cli.out, "\nPlease login prior to %s:\n", cmdName)
if err := cli.CmdLogin(registry.GetAuthConfigKey(index)); err != nil {
indexServer := registry.GetAuthConfigKey(index)
authConfig, err := cli.configureAuth("", "", "", indexServer)
if err != nil {
return "", err
}
return cli.encodeRegistryAuth(index)
return encodeAuthToBase64(authConfig)
}
}
@@ -138,3 +155,42 @@ func (cli *DockerCli) getTtySize() (int, int) {
}
return int(ws.Height), int(ws.Width)
}
// resolveAuthConfig is like registry.ResolveAuthConfig, but if using the
// default index, it uses the default index name for the daemon's platform,
// not the client's platform.
func (cli *DockerCli) resolveAuthConfig(authConfigs map[string]types.AuthConfig, index *registrytypes.IndexInfo) types.AuthConfig {
configKey := index.Name
if index.Official {
configKey = cli.electAuthServer()
}
// First try the happy case
if c, found := authConfigs[configKey]; found || index.Official {
return c
}
convertToHostname := func(url string) string {
stripped := url
if strings.HasPrefix(url, "http://") {
stripped = strings.Replace(url, "http://", "", 1)
} else if strings.HasPrefix(url, "https://") {
stripped = strings.Replace(url, "https://", "", 1)
}
nameParts := strings.SplitN(stripped, "/", 2)
return nameParts[0]
}
// Maybe they have a legacy config file, we will iterate the keys converting
// them to the new format and testing
for registry, ac := range authConfigs {
if configKey == convertToHostname(registry) {
return ac
}
}
// When all else fails, return an empty auth config
return types.AuthConfig{}
}

View File

@@ -147,7 +147,7 @@ func versionMiddleware(handler httputils.APIFunc) httputils.APIFunc {
return errors.ErrorCodeNewerClientVersion.WithArgs(apiVersion, api.DefaultVersion)
}
if apiVersion.LessThan(api.MinVersion) {
return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, api.DefaultVersion)
return errors.ErrorCodeOldClientVersion.WithArgs(apiVersion, api.MinVersion)
}
w.Header().Set("Server", "Docker/"+dockerversion.Version+" ("+runtime.GOOS+")")

View File

@@ -241,10 +241,11 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
if closeNotifier, ok := w.(http.CloseNotifier); ok {
finished := make(chan struct{})
defer close(finished)
clientGone := closeNotifier.CloseNotify()
go func() {
select {
case <-finished:
case <-closeNotifier.CloseNotify():
case <-clientGone:
logrus.Infof("Client disconnected, cancelling job: build")
b.Cancel()
}

View File

@@ -7,9 +7,11 @@ import (
"fmt"
"io"
"net/http"
"net/url"
"strings"
"github.com/docker/distribution/digest"
"github.com/docker/distribution/registry/api/errcode"
"github.com/docker/docker/api/server/httputils"
"github.com/docker/docker/builder/dockerfile"
derr "github.com/docker/docker/errors"
@@ -137,6 +139,12 @@ func (s *router) postImagesCreate(ctx context.Context, w http.ResponseWriter, r
err = s.daemon.PullImage(ref, metaHeaders, authConfig, output)
}
}
// Check the error from pulling an image to make sure the request
// was authorized. Modify the status if the request was
// unauthorized to respond with 401 rather than 500.
if err != nil && isAuthorizedError(err) {
err = errcode.ErrorCodeUnauthorized.WithMessage(fmt.Sprintf("Authentication is required: %s", err))
}
} else { //import
var newRef reference.Named
if repo != "" {
@@ -373,3 +381,16 @@ func (s *router) getImagesSearch(ctx context.Context, w http.ResponseWriter, r *
}
return httputils.WriteJSON(w, http.StatusOK, query.Results)
}
func isAuthorizedError(err error) bool {
if urlError, ok := err.(*url.Error); ok {
err = urlError.Err
}
if dError, ok := err.(errcode.Error); ok {
if dError.ErrorCode() == errcode.ErrorCodeUnauthorized {
return true
}
}
return false
}

View File

@@ -20,7 +20,7 @@ func NewRouter(b Backend) router.Router {
}
r.routes = []router.Route{
local.NewOptionsRoute("/", optionsHandler),
local.NewOptionsRoute("/{anyroute:.*}", optionsHandler),
local.NewGetRoute("/_ping", pingHandler),
local.NewGetRoute("/events", r.getEvents),
local.NewGetRoute("/info", r.getInfo),

View File

@@ -21,7 +21,7 @@ import (
runconfigopts "github.com/docker/docker/runconfig/opts"
"github.com/docker/docker/utils"
"github.com/docker/docker/volume"
"github.com/docker/engine-api/types/container"
containertypes "github.com/docker/engine-api/types/container"
"github.com/docker/engine-api/types/network"
"github.com/docker/go-connections/nat"
"github.com/docker/libnetwork"
@@ -44,7 +44,6 @@ type Container struct {
HostnamePath string
HostsPath string
ShmPath string
MqueuePath string
ResolvConfPath string
SeccompProfile string
}
@@ -129,18 +128,26 @@ func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
return derr.ErrorCodeEmptyNetwork
}
if len(networkSettings.Ports) == 0 {
pm, err := getEndpointPortMapInfo(ep)
if err != nil {
return err
}
networkSettings.Ports = pm
}
return nil
}
func getEndpointPortMapInfo(ep libnetwork.Endpoint) (nat.PortMap, error) {
pm := nat.PortMap{}
driverInfo, err := ep.DriverInfo()
if err != nil {
return err
return pm, err
}
if driverInfo == nil {
// It is not an error for epInfo to be nil
return nil
}
if networkSettings.Ports == nil {
networkSettings.Ports = nat.PortMap{}
return pm, nil
}
if expData, ok := driverInfo[netlabel.ExposedPorts]; ok {
@@ -148,30 +155,45 @@ func (container *Container) buildPortMapInfo(ep libnetwork.Endpoint) error {
for _, tp := range exposedPorts {
natPort, err := nat.NewPort(tp.Proto.String(), strconv.Itoa(int(tp.Port)))
if err != nil {
return derr.ErrorCodeParsingPort.WithArgs(tp.Port, err)
return pm, derr.ErrorCodeParsingPort.WithArgs(tp.Port, err)
}
networkSettings.Ports[natPort] = nil
pm[natPort] = nil
}
}
}
mapData, ok := driverInfo[netlabel.PortMap]
if !ok {
return nil
return pm, nil
}
if portMapping, ok := mapData.([]types.PortBinding); ok {
for _, pp := range portMapping {
natPort, err := nat.NewPort(pp.Proto.String(), strconv.Itoa(int(pp.Port)))
if err != nil {
return err
return pm, err
}
natBndg := nat.PortBinding{HostIP: pp.HostIP.String(), HostPort: strconv.Itoa(int(pp.HostPort))}
networkSettings.Ports[natPort] = append(networkSettings.Ports[natPort], natBndg)
pm[natPort] = append(pm[natPort], natBndg)
}
}
return nil
return pm, nil
}
func getSandboxPortMapInfo(sb libnetwork.Sandbox) nat.PortMap {
pm := nat.PortMap{}
if sb == nil {
return pm
}
for _, ep := range sb.Endpoints() {
pm, _ = getEndpointPortMapInfo(ep)
if len(pm) > 0 {
break
}
}
return pm
}
// BuildEndpointInfo sets endpoint-related fields on container.NetworkSettings based on the provided network and endpoint.
@@ -265,7 +287,7 @@ func (container *Container) BuildJoinOptions(n libnetwork.Network) ([]libnetwork
}
// BuildCreateEndpointOptions builds endpoint options from a given network.
func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network) ([]libnetwork.EndpointOption, error) {
func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network, epConfig *network.EndpointSettings, sb libnetwork.Sandbox) ([]libnetwork.EndpointOption, error) {
var (
portSpecs = make(nat.PortSet)
bindings = make(nat.PortMap)
@@ -278,7 +300,7 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network) ([]
createOptions = append(createOptions, libnetwork.CreateOptionAnonymous())
}
if epConfig, ok := container.NetworkSettings.Networks[n.Name()]; ok {
if epConfig != nil {
ipam := epConfig.IPAMConfig
if ipam != nil && (ipam.IPv4Address != "" || ipam.IPv6Address != "") {
createOptions = append(createOptions,
@@ -290,14 +312,33 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network) ([]
}
}
if !container.HostConfig.NetworkMode.IsUserDefined() {
if !containertypes.NetworkMode(n.Name()).IsUserDefined() {
createOptions = append(createOptions, libnetwork.CreateOptionDisableResolution())
}
// Other configs are applicable only for the endpoint in the network
// configs that are applicable only for the endpoint in the network
// to which container was connected to on docker run.
if n.Name() != container.HostConfig.NetworkMode.NetworkName() &&
!(n.Name() == "bridge" && container.HostConfig.NetworkMode.IsDefault()) {
// Ideally all these network-specific endpoint configurations must be moved under
// container.NetworkSettings.Networks[n.Name()]
if n.Name() == container.HostConfig.NetworkMode.NetworkName() ||
(n.Name() == "bridge" && container.HostConfig.NetworkMode.IsDefault()) {
if container.Config.MacAddress != "" {
mac, err := net.ParseMAC(container.Config.MacAddress)
if err != nil {
return nil, err
}
genericOption := options.Generic{
netlabel.MacAddress: mac,
}
createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
}
}
// Port-mapping rules belong to the container & applicable only to non-internal networks
portmaps := getSandboxPortMapInfo(sb)
if n.Info().Internal() || len(portmaps) > 0 {
return createOptions, nil
}
@@ -357,19 +398,6 @@ func (container *Container) BuildCreateEndpointOptions(n libnetwork.Network) ([]
libnetwork.CreateOptionPortMapping(pbList),
libnetwork.CreateOptionExposedPorts(exposeList))
if container.Config.MacAddress != "" {
mac, err := net.ParseMAC(container.Config.MacAddress)
if err != nil {
return nil, err
}
genericOption := options.Generic{
netlabel.MacAddress: mac,
}
createOptions = append(createOptions, libnetwork.EndpointOptionGeneric(genericOption))
}
return createOptions, nil
}
@@ -534,18 +562,6 @@ func (container *Container) UnmountIpcMounts(unmount func(pth string) error) {
}
}
if !container.HasMountFor("/dev/mqueue") {
mqueuePath, err := container.MqueueResourcePath()
if err != nil {
logrus.Error(err)
warnings = append(warnings, err.Error())
} else if mqueuePath != "" {
if err := unmount(mqueuePath); err != nil {
warnings = append(warnings, fmt.Sprintf("failed to umount %s: %v", mqueuePath, err))
}
}
}
if len(warnings) > 0 {
logrus.Warnf("failed to cleanup ipc mounts:\n%v", strings.Join(warnings, "\n"))
}
@@ -564,20 +580,10 @@ func (container *Container) IpcMounts() []execdriver.Mount {
Propagation: volume.DefaultPropagationMode,
})
}
if !container.HasMountFor("/dev/mqueue") {
label.SetFileLabel(container.MqueuePath, container.MountLabel)
mounts = append(mounts, execdriver.Mount{
Source: container.MqueuePath,
Destination: "/dev/mqueue",
Writable: true,
Propagation: volume.DefaultPropagationMode,
})
}
return mounts
}
func updateCommand(c *execdriver.Command, resources container.Resources) {
func updateCommand(c *execdriver.Command, resources containertypes.Resources) {
c.Resources.BlkioWeight = resources.BlkioWeight
c.Resources.CPUShares = resources.CPUShares
c.Resources.CPUPeriod = resources.CPUPeriod
@@ -591,7 +597,7 @@ func updateCommand(c *execdriver.Command, resources container.Resources) {
}
// UpdateContainer updates resources of a container.
func (container *Container) UpdateContainer(hostConfig *container.HostConfig) error {
func (container *Container) UpdateContainer(hostConfig *containertypes.HostConfig) error {
container.Lock()
resources := hostConfig.Resources

View File

@@ -1,34 +1,35 @@
package daemon
package container
import (
"sort"
"github.com/docker/docker/container"
)
import "sort"
// History is a convenience type for storing a list of containers,
// ordered by creation date.
type History []*container.Container
// sorted by creation date in descendant order.
type History []*Container
// Len returns the number of containers in the history.
func (history *History) Len() int {
return len(*history)
}
// Less compares two containers and returns true if the second one
// was created before the first one.
func (history *History) Less(i, j int) bool {
containers := *history
return containers[j].Created.Before(containers[i].Created)
}
// Swap switches containers i and j positions in the history.
func (history *History) Swap(i, j int) {
containers := *history
containers[i], containers[j] = containers[j], containers[i]
}
// Add the given container to history.
func (history *History) Add(container *container.Container) {
func (history *History) Add(container *Container) {
*history = append(*history, container)
}
// sort orders the history by creation date in descendant order.
func (history *History) sort() {
sort.Sort(history)
}

91
container/memory_store.go Normal file
View File

@@ -0,0 +1,91 @@
package container
import "sync"
// memoryStore implements a Store in memory.
type memoryStore struct {
s map[string]*Container
sync.Mutex
}
// NewMemoryStore initializes a new memory store.
func NewMemoryStore() Store {
return &memoryStore{
s: make(map[string]*Container),
}
}
// Add appends a new container to the memory store.
// It overrides the id if it existed before.
func (c *memoryStore) Add(id string, cont *Container) {
c.Lock()
c.s[id] = cont
c.Unlock()
}
// Get returns a container from the store by id.
func (c *memoryStore) Get(id string) *Container {
c.Lock()
res := c.s[id]
c.Unlock()
return res
}
// Delete removes a container from the store by id.
func (c *memoryStore) Delete(id string) {
c.Lock()
delete(c.s, id)
c.Unlock()
}
// List returns a sorted list of containers from the store.
// The containers are ordered by creation date.
func (c *memoryStore) List() []*Container {
containers := new(History)
c.Lock()
for _, cont := range c.s {
containers.Add(cont)
}
c.Unlock()
containers.sort()
return *containers
}
// Size returns the number of containers in the store.
func (c *memoryStore) Size() int {
c.Lock()
defer c.Unlock()
return len(c.s)
}
// First returns the first container found in the store by a given filter.
func (c *memoryStore) First(filter StoreFilter) *Container {
c.Lock()
defer c.Unlock()
for _, cont := range c.s {
if filter(cont) {
return cont
}
}
return nil
}
// ApplyAll calls the reducer function with every container in the store.
// This operation is asyncronous in the memory store.
func (c *memoryStore) ApplyAll(apply StoreReducer) {
c.Lock()
defer c.Unlock()
wg := new(sync.WaitGroup)
for _, cont := range c.s {
wg.Add(1)
go func(container *Container) {
apply(container)
wg.Done()
}(cont)
}
wg.Wait()
}
var _ Store = &memoryStore{}

View File

@@ -0,0 +1,106 @@
package container
import (
"testing"
"time"
)
func TestNewMemoryStore(t *testing.T) {
s := NewMemoryStore()
m, ok := s.(*memoryStore)
if !ok {
t.Fatalf("store is not a memory store %v", s)
}
if m.s == nil {
t.Fatal("expected store map to not be nil")
}
}
func TestAddContainers(t *testing.T) {
s := NewMemoryStore()
s.Add("id", NewBaseContainer("id", "root"))
if s.Size() != 1 {
t.Fatalf("expected store size 1, got %v", s.Size())
}
}
func TestGetContainer(t *testing.T) {
s := NewMemoryStore()
s.Add("id", NewBaseContainer("id", "root"))
c := s.Get("id")
if c == nil {
t.Fatal("expected container to not be nil")
}
}
func TestDeleteContainer(t *testing.T) {
s := NewMemoryStore()
s.Add("id", NewBaseContainer("id", "root"))
s.Delete("id")
if c := s.Get("id"); c != nil {
t.Fatalf("expected container to be nil after removal, got %v", c)
}
if s.Size() != 0 {
t.Fatalf("expected store size to be 0, got %v", s.Size())
}
}
func TestListContainers(t *testing.T) {
s := NewMemoryStore()
cont := NewBaseContainer("id", "root")
cont.Created = time.Now()
cont2 := NewBaseContainer("id2", "root")
cont2.Created = time.Now().Add(24 * time.Hour)
s.Add("id", cont)
s.Add("id2", cont2)
list := s.List()
if len(list) != 2 {
t.Fatalf("expected list size 2, got %v", len(list))
}
if list[0].ID != "id2" {
t.Fatalf("expected older container to be first, got %v", list[0].ID)
}
}
func TestFirstContainer(t *testing.T) {
s := NewMemoryStore()
s.Add("id", NewBaseContainer("id", "root"))
s.Add("id2", NewBaseContainer("id2", "root"))
first := s.First(func(cont *Container) bool {
return cont.ID == "id2"
})
if first == nil {
t.Fatal("expected container to not be nil")
}
if first.ID != "id2" {
t.Fatalf("expected id2, got %v", first)
}
}
func TestApplyAllContainer(t *testing.T) {
s := NewMemoryStore()
s.Add("id", NewBaseContainer("id", "root"))
s.Add("id2", NewBaseContainer("id2", "root"))
s.ApplyAll(func(cont *Container) {
if cont.ID == "id2" {
cont.ID = "newID"
}
})
cont := s.Get("id2")
if cont == nil {
t.Fatal("expected container to not be nil")
}
if cont.ID != "newID" {
t.Fatalf("expected newID, got %v", cont)
}
}

View File

@@ -369,6 +369,9 @@ func (m *containerMonitor) resetContainer(lock bool) {
select {
case <-time.After(loggerCloseTimeout):
logrus.Warnf("Logger didn't exit in time: logs may be truncated")
container.LogCopier.Close()
// always waits for the LogCopier to finished before closing
<-exit
case <-exit:
}
}

View File

@@ -247,6 +247,14 @@ func (s *State) IsPaused() bool {
return res
}
// IsRestarting returns whether the container is restarting or not.
func (s *State) IsRestarting() bool {
s.Lock()
res := s.Restarting
s.Unlock()
return res
}
// SetRemovalInProgress sets the container state as being removed.
func (s *State) SetRemovalInProgress() error {
s.Lock()

28
container/store.go Normal file
View File

@@ -0,0 +1,28 @@
package container
// StoreFilter defines a function to filter
// container in the store.
type StoreFilter func(*Container) bool
// StoreReducer defines a function to
// manipulate containers in the store
type StoreReducer func(*Container)
// Store defines an interface that
// any container store must implement.
type Store interface {
// Add appends a new container to the store.
Add(string, *Container)
// Get returns a container from the store by the identifier it was stored with.
Get(string) *Container
// Delete removes a container from the store by the identifier it was stored with.
Delete(string)
// List returns a list of containers from the store.
List() []*Container
// Size returns the number of containers in the store.
Size() int
// First returns the first container found in the store by a given filter.
First(StoreFilter) *Container
// ApplyAll calls the reducer function with every container in the store.
ApplyAll(StoreReducer)
}

View File

@@ -4,7 +4,7 @@
FROM debian:jessie
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libsqlite3-dev libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libsqlite3-dev pkg-config libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.5.3
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local

View File

@@ -4,7 +4,7 @@
FROM debian:stretch
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libsqlite3-dev libseccomp-dev libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libseccomp-dev libsqlite3-dev pkg-config libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.5.3
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local

View File

@@ -4,7 +4,8 @@
FROM debian:wheezy-backports
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools/wheezy-backports build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libsqlite3-dev libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y -t wheezy-backports btrfs-tools --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y apparmor bash-completion build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libsqlite3-dev pkg-config --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.5.3
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local

View File

@@ -57,12 +57,13 @@ for version in "${versions[@]}"; do
libapparmor-dev # for "sys/apparmor.h"
libdevmapper-dev # for "libdevmapper.h"
libltdl-dev # for pkcs11 "ltdl.h"
libsqlite3-dev # for "sqlite3.h"
libseccomp-dev # for "seccomp.h" & "libseccomp.so"
libsqlite3-dev # for "sqlite3.h"
pkg-config # for detecting things like libsystemd-journal dynamically
)
# packaging for "sd-journal.h" and libraries varies
case "$suite" in
precise) ;;
precise|wheezy) ;;
sid|stretch|wily) packages+=( libsystemd-dev );;
*) packages+=( libsystemd-journal-dev );;
esac
@@ -96,9 +97,13 @@ for version in "${versions[@]}"; do
fi
if [ "$suite" = 'wheezy' ]; then
# pull btrfs-toold from backports
backports="/$suite-backports"
packages=( "${packages[@]/btrfs-tools/btrfs-tools$backports}" )
# pull a couple packages from backports explicitly
# (build failures otherwise)
backportsPackages=( btrfs-tools libsystemd-journal-dev )
for pkg in "${backportsPackages[@]}"; do
packages=( "${packages[@]/$pkg}" )
done
echo "RUN apt-get update && apt-get install -y -t $suite-backports ${backportsPackages[*]} --no-install-recommends && rm -rf /var/lib/apt/lists/*" >> "$version/Dockerfile"
fi
echo "RUN apt-get update && apt-get install -y ${packages[*]} --no-install-recommends && rm -rf /var/lib/apt/lists/*" >> "$version/Dockerfile"

View File

@@ -4,7 +4,7 @@
FROM ubuntu:precise
RUN apt-get update && apt-get install -y apparmor bash-completion build-essential curl ca-certificates debhelper dh-apparmor git libapparmor-dev libltdl-dev libsqlite3-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y apparmor bash-completion build-essential curl ca-certificates debhelper dh-apparmor git libapparmor-dev libltdl-dev libsqlite3-dev pkg-config --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.5.3
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local

View File

@@ -4,7 +4,7 @@
FROM ubuntu:trusty
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libsqlite3-dev libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libsqlite3-dev pkg-config libsystemd-journal-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.5.3
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local

View File

@@ -4,7 +4,7 @@
FROM ubuntu:wily
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libsqlite3-dev libseccomp-dev libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
RUN apt-get update && apt-get install -y apparmor bash-completion btrfs-tools build-essential curl ca-certificates debhelper dh-apparmor dh-systemd git libapparmor-dev libdevmapper-dev libltdl-dev libseccomp-dev libsqlite3-dev pkg-config libsystemd-dev --no-install-recommends && rm -rf /var/lib/apt/lists/*
ENV GO_VERSION 1.5.3
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local

View File

@@ -6,7 +6,7 @@ FROM centos:7
RUN yum groupinstall -y "Development Tools"
RUN yum -y swap -- remove systemd-container systemd-container-libs -- install systemd systemd-libs
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel libtool-ltdl-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel sqlite-devel systemd-devel tar
ENV GO_VERSION 1.5.3
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
@@ -15,3 +15,4 @@ ENV PATH $PATH:/usr/local/go/bin
ENV AUTO_GOPATH 1
ENV DOCKER_BUILDTAGS selinux

View File

@@ -5,7 +5,7 @@
FROM fedora:22
RUN dnf install -y @development-tools fedora-packager
RUN dnf install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN dnf install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel sqlite-devel systemd-devel tar
ENV SECCOMP_VERSION v2.2.3
RUN buildDeps=' \
@@ -35,3 +35,4 @@ ENV PATH $PATH:/usr/local/go/bin
ENV AUTO_GOPATH 1
ENV DOCKER_BUILDTAGS seccomp selinux

View File

@@ -5,7 +5,7 @@
FROM fedora:23
RUN dnf install -y @development-tools fedora-packager
RUN dnf install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN dnf install -y btrfs-progs-devel device-mapper-devel glibc-static libseccomp-devel libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel sqlite-devel systemd-devel tar
ENV SECCOMP_VERSION v2.2.3
RUN buildDeps=' \
@@ -35,3 +35,4 @@ ENV PATH $PATH:/usr/local/go/bin
ENV AUTO_GOPATH 1
ENV DOCKER_BUILDTAGS seccomp selinux

View File

@@ -51,6 +51,7 @@ for version in "${versions[@]}"; do
;;
oraclelinux:*)
# get "Development Tools" packages and dependencies
# we also need yum-utils for yum-config-manager to pull the latest repo file
echo 'RUN yum groupinstall -y "Development Tools"' >> "$version/Dockerfile"
;;
opensuse:*)
@@ -70,9 +71,11 @@ for version in "${versions[@]}"; do
libseccomp-devel # for "seccomp.h" & "libseccomp.so"
libselinux-devel # for "libselinux.so"
libtool-ltdl-devel # for pkcs11 "ltdl.h"
pkgconfig # for the pkg-config command
selinux-policy
selinux-policy-devel
sqlite-devel # for "sqlite3.h"
systemd-devel # for "sd-journal.h" and libraries
tar # older versions of dev-tools do not have tar
)
@@ -83,6 +86,13 @@ for version in "${versions[@]}"; do
;;
esac
case "$from" in
oraclelinux:6)
# doesn't use systemd, doesn't have a devel package for it
packages=( "${packages[@]/systemd-devel}" )
;;
esac
# opensuse & oraclelinx:6 do not have the right libseccomp libs
# centos:7 and oraclelinux:7 have a libseccomp < 2.2.1 :(
case "$from" in
@@ -97,6 +107,11 @@ for version in "${versions[@]}"; do
case "$from" in
opensuse:*)
packages=( "${packages[@]/btrfs-progs-devel/libbtrfs-devel}" )
packages=( "${packages[@]/pkgconfig/pkg-config}" )
if [[ "$from" == "opensuse:13."* ]]; then
packages+=( systemd-rpm-macros )
fi
# use zypper
echo "RUN zypper --non-interactive install ${packages[*]}" >> "$version/Dockerfile"
;;
@@ -140,6 +155,18 @@ for version in "${versions[@]}"; do
*) ;;
esac
case "$from" in
oraclelinux:6)
# We need a known version of the kernel-uek-devel headers to set CGO_CPPFLAGS, so grab the UEKR4 GA version
# This requires using yum-config-manager from yum-utils to enable the UEKR4 yum repo
echo "RUN yum install -y yum-utils && curl -o /etc/yum.repos.d/public-yum-ol6.repo http://yum.oracle.com/public-yum-ol6.repo && yum-config-manager -q --enable ol6_UEKR4" >> "$version/Dockerfile"
echo "RUN yum install -y kernel-uek-devel-4.1.12-32.el6uek" >> "$version/Dockerfile"
echo >> "$version/Dockerfile"
;;
*) ;;
esac
awk '$1 == "ENV" && $2 == "GO_VERSION" { print; exit }' ../../../Dockerfile >> "$version/Dockerfile"
echo 'RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local' >> "$version/Dockerfile"
echo 'ENV PATH $PATH:/usr/local/go/bin' >> "$version/Dockerfile"
@@ -154,4 +181,22 @@ for version in "${versions[@]}"; do
buildTags=$( echo "selinux $extraBuildTags" | xargs -n1 | sort -n | tr '\n' ' ' | sed -e 's/[[:space:]]*$//' )
echo "ENV DOCKER_BUILDTAGS $buildTags" >> "$version/Dockerfile"
echo >> "$version/Dockerfile"
case "$from" in
oraclelinux:6)
# We need to set the CGO_CPPFLAGS environment to use the updated UEKR4 headers with all the userns stuff.
# The ordering is very important and should not be changed.
echo 'ENV CGO_CPPFLAGS -D__EXPORTED_HEADERS__ \' >> "$version/Dockerfile"
echo ' -I/usr/src/kernels/4.1.12-32.el6uek.x86_64/arch/x86/include/generated/uapi \' >> "$version/Dockerfile"
echo ' -I/usr/src/kernels/4.1.12-32.el6uek.x86_64/arch/x86/include/uapi \' >> "$version/Dockerfile"
echo ' -I/usr/src/kernels/4.1.12-32.el6uek.x86_64/include/generated/uapi \' >> "$version/Dockerfile"
echo ' -I/usr/src/kernels/4.1.12-32.el6uek.x86_64/include/uapi \' >> "$version/Dockerfile"
echo ' -I/usr/src/kernels/4.1.12-32.el6uek.x86_64/include' >> "$version/Dockerfile"
echo >> "$version/Dockerfile"
;;
*) ;;
esac
done

View File

@@ -5,7 +5,7 @@
FROM opensuse:13.2
RUN zypper --non-interactive install ca-certificates* curl gzip rpm-build
RUN zypper --non-interactive install libbtrfs-devel device-mapper-devel glibc-static libselinux-devel libtool-ltdl-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN zypper --non-interactive install libbtrfs-devel device-mapper-devel glibc-static libselinux-devel libtool-ltdl-devel pkg-config selinux-policy selinux-policy-devel sqlite-devel systemd-devel tar systemd-rpm-macros
ENV GO_VERSION 1.5.3
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
@@ -14,3 +14,4 @@ ENV PATH $PATH:/usr/local/go/bin
ENV AUTO_GOPATH 1
ENV DOCKER_BUILDTAGS selinux

View File

@@ -0,0 +1,27 @@
#
# THIS FILE IS AUTOGENERATED; SEE "contrib/builder/rpm/amd64/generate.sh"!
#
FROM oraclelinux:6
RUN yum groupinstall -y "Development Tools"
RUN yum install -y btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y yum-utils && curl -o /etc/yum.repos.d/public-yum-ol6.repo http://yum.oracle.com/public-yum-ol6.repo && yum-config-manager -q --enable ol6_UEKR4
RUN yum install -y kernel-uek-devel-4.1.12-32.el6uek
ENV GO_VERSION 1.5.3
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
ENV PATH $PATH:/usr/local/go/bin
ENV AUTO_GOPATH 1
ENV DOCKER_BUILDTAGS selinux
ENV CGO_CPPFLAGS -D__EXPORTED_HEADERS__ \
-I/usr/src/kernels/4.1.12-32.el6uek.x86_64/arch/x86/include/generated/uapi \
-I/usr/src/kernels/4.1.12-32.el6uek.x86_64/arch/x86/include/uapi \
-I/usr/src/kernels/4.1.12-32.el6uek.x86_64/include/generated/uapi \
-I/usr/src/kernels/4.1.12-32.el6uek.x86_64/include/uapi \
-I/usr/src/kernels/4.1.12-32.el6uek.x86_64/include

View File

@@ -5,7 +5,7 @@
FROM oraclelinux:7
RUN yum groupinstall -y "Development Tools"
RUN yum install -y --enablerepo=ol7_optional_latest btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel libtool-ltdl-devel selinux-policy selinux-policy-devel sqlite-devel tar
RUN yum install -y --enablerepo=ol7_optional_latest btrfs-progs-devel device-mapper-devel glibc-static libselinux-devel libtool-ltdl-devel pkgconfig selinux-policy selinux-policy-devel sqlite-devel systemd-devel tar
ENV GO_VERSION 1.5.3
RUN curl -fSL "https://storage.googleapis.com/golang/go${GO_VERSION}.linux-amd64.tar.gz" | tar xzC /usr/local
@@ -14,3 +14,4 @@ ENV PATH $PATH:/usr/local/go/bin
ENV AUTO_GOPATH 1
ENV DOCKER_BUILDTAGS selinux

View File

@@ -220,6 +220,32 @@ __docker_pos_first_nonflag() {
echo $counter
}
# If we are currently completing the value of a map option (key=value)
# which matches the extglob given as an argument, returns key.
# This function is needed for key-specific completions.
# TODO use this in all "${words[$cword-2]}$prev=" occurrences
__docker_map_key_of_current_option() {
local glob="$1"
local key glob_pos
if [ "$cur" = "=" ] ; then # key= case
key="$prev"
glob_pos=$((cword - 2))
elif [[ $cur == *=* ]] ; then # key=value case (OSX)
key=${cur%=*}
glob_pos=$((cword - 1))
elif [ "$prev" = "=" ] ; then
key=${words[$cword - 2]} # key=value case
glob_pos=$((cword - 3))
else
return
fi
[ "${words[$glob_pos]}" = "=" ] && ((glob_pos--)) # --option=key=value syntax
[[ ${words[$glob_pos]} == @($glob) ]] && echo "$key"
}
# Returns the value of the first option matching option_glob.
# Valid values for option_glob are option names like '--log-level' and
# globs like '--log-level|-l'
@@ -383,7 +409,7 @@ __docker_complete_log_options() {
local gelf_options="env gelf-address labels tag"
local journald_options="env labels"
local json_file_options="env labels max-file max-size"
local syslog_options="syslog-address syslog-facility tag"
local syslog_options="syslog-address syslog-tls-ca-cert syslog-tls-cert syslog-tls-key syslog-tls-skip-verify syslog-facility tag"
local splunk_options="env labels splunk-caname splunk-capath splunk-index splunk-insecureskipverify splunk-source splunk-sourcetype splunk-token splunk-url tag"
local all_options="$fluentd_options $gelf_options $journald_options $json_file_options $syslog_options $splunk_options"
@@ -431,8 +457,9 @@ __docker_complete_log_driver_options() {
return
;;
*syslog-address=*)
COMPREPLY=( $( compgen -W "tcp udp unix" -S "://" -- "${cur#=}" ) )
COMPREPLY=( $( compgen -W "tcp:// tcp+tls:// udp:// unix://" -- "${cur#=}" ) )
__docker_nospace
__ltrim_colon_completions "${cur}"
return
;;
*syslog-facility=*)
@@ -460,15 +487,23 @@ __docker_complete_log_driver_options() {
" -- "${cur#=}" ) )
return
;;
*syslog-tls-@(ca-cert|cert|key)=*)
_filedir
return
;;
*syslog-tls-skip-verify=*)
COMPREPLY=( $( compgen -W "true" -- "${cur#=}" ) )
return
;;
*splunk-url=*)
COMPREPLY=( $( compgen -W "http:// https://" -- "${cur#=}" ) )
compopt -o nospace
__docker_nospace
__ltrim_colon_completions "${cur}"
return
;;
*splunk-insecureskipverify=*)
COMPREPLY=( $( compgen -W "true false" -- "${cur#=}" ) )
compopt -o nospace
__docker_nospace
return
;;
esac
@@ -644,7 +679,7 @@ _docker_commit() {
_docker_cp() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--follow-link -L --help" -- "$cur" ) )
;;
*)
local counter=$(__docker_pos_first_nonflag)
@@ -735,6 +770,7 @@ _docker_daemon() {
--registry-mirror
--storage-driver -s
--storage-opt
--userns-remap
"
case "$prev" in
@@ -748,7 +784,7 @@ _docker_daemon() {
return
;;
--cluster-store-opt)
COMPREPLY=( $( compgen -W "kv.cacertfile kv.certfile kv.keyfile" -S = -- "$cur" ) )
COMPREPLY=( $( compgen -W "discovery.heartbeat discovery.ttl kv.cacertfile kv.certfile kv.keyfile kv.path" -S = -- "$cur" ) )
__docker_nospace
return
;;
@@ -810,6 +846,15 @@ _docker_daemon() {
__docker_complete_log_options
return
;;
--userns-remap)
if [[ $cur == *:* ]] ; then
COMPREPLY=( $(compgen -g -- "${cur#*:}") )
else
COMPREPLY=( $(compgen -u -S : -- "$cur") )
__docker_nospace
fi
return
;;
$(__docker_to_extglob "$options_with_args") )
return
;;
@@ -860,37 +905,30 @@ _docker_diff() {
}
_docker_events() {
case "$prev" in
--filter|-f)
COMPREPLY=( $( compgen -S = -W "container event image" -- "$cur" ) )
__docker_nospace
return
;;
--since|--until)
return
;;
esac
case "${words[$cword-2]}$prev=" in
*container=*)
cur="${cur#=}"
local filter=$(__docker_map_key_of_current_option '-f|--filter')
case "$filter" in
container)
cur="${cur##*=}"
__docker_complete_containers_all
return
;;
*event=*)
event)
COMPREPLY=( $( compgen -W "
attach
commit
connect
copy
create
delete
destroy
die
disconnect
exec_create
exec_start
export
import
kill
mount
oom
pause
pull
@@ -902,16 +940,43 @@ _docker_events() {
stop
tag
top
unmount
unpause
untag
" -- "${cur#=}" ) )
update
" -- "${cur##*=}" ) )
return
;;
*image=*)
cur="${cur#=}"
image)
cur="${cur##*=}"
__docker_complete_images
return
;;
network)
cur="${cur##*=}"
__docker_complete_networks
return
;;
type)
COMPREPLY=( $( compgen -W "container image network volume" -- "${cur##*=}" ) )
return
;;
volume)
cur="${cur##*=}"
__docker_complete_volumes
return
;;
esac
case "$prev" in
--filter|-f)
COMPREPLY=( $( compgen -S = -W "container event image label network type volume" -- "$cur" ) )
__docker_nospace
return
;;
--since|--until)
return
;;
esac
case "$cur" in
@@ -978,10 +1043,8 @@ _docker_history() {
_docker_images() {
case "$prev" in
--filter|-f)
COMPREPLY=( $( compgen -W "dangling=true label=" -- "$cur" ) )
if [ "$COMPREPLY" = "label=" ]; then
__docker_nospace
fi
COMPREPLY=( $( compgen -S = -W "dangling label" -- "$cur" ) )
__docker_nospace
return
;;
--format)
@@ -1153,12 +1216,41 @@ _docker_logs() {
}
_docker_network_connect() {
local options_with_args="
--alias
--ip
--ip6
--link
"
local boolean_options="
--help
"
case "$prev" in
--link)
case "$cur" in
*:*)
;;
*)
__docker_complete_containers_running
COMPREPLY=( $( compgen -W "${COMPREPLY[*]}" -S ':' ) )
__docker_nospace
;;
esac
return
;;
$(__docker_to_extglob "$options_with_args") )
return
;;
esac
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
COMPREPLY=( $( compgen -W "$boolean_options $options_with_args" -- "$cur" ) )
;;
*)
local counter=$(__docker_pos_first_nonflag)
local counter=$( __docker_pos_first_nonflag $( __docker_to_alternatives "$options_with_args" ) )
if [ $cword -eq $counter ]; then
__docker_complete_networks
elif [ $cword -eq $(($counter + 1)) ]; then
@@ -1170,7 +1262,7 @@ _docker_network_connect() {
_docker_network_create() {
case "$prev" in
--aux-address|--gateway|--ip-range|--opt|-o|--subnet)
--aux-address|--gateway|--ip-range|--ipam-opt|--opt|-o|--subnet)
return
;;
--ipam-driver)
@@ -1189,7 +1281,7 @@ _docker_network_create() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--aux-address --driver -d --gateway --help --ip-range --ipam-driver --opt -o --subnet" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--aux-address --driver -d --gateway --help --internal --ip-range --ipam-driver --ipam-opt --opt -o --subnet" -- "$cur" ) )
;;
esac
}
@@ -1350,7 +1442,7 @@ _docker_ps() {
return
;;
*status=*)
COMPREPLY=( $( compgen -W "exited paused restarting running" -- "${cur#=}" ) )
COMPREPLY=( $( compgen -W "created dead exited paused restarting running" -- "${cur#=}" ) )
return
;;
esac
@@ -1365,7 +1457,7 @@ _docker_ps() {
_docker_pull() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--all-tags -a --help" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--all-tags -a --disable-content-trust=false --help" -- "$cur" ) )
;;
*)
local counter=$(__docker_pos_first_nonflag)
@@ -1387,7 +1479,7 @@ _docker_pull() {
_docker_push() {
case "$cur" in
-*)
COMPREPLY=( $( compgen -W "--help" -- "$cur" ) )
COMPREPLY=( $( compgen -W "--disable-content-trust=false --help" -- "$cur" ) )
;;
*)
local counter=$(__docker_pos_first_nonflag)
@@ -1488,6 +1580,8 @@ _docker_run() {
--expose
--group-add
--hostname -h
--ip
--ip6
--ipc
--isolation
--kernel-memory
@@ -1503,6 +1597,7 @@ _docker_run() {
--memory-reservation
--name
--net
--net-alias
--oom-score-adj
--pid
--publish -p
@@ -1663,6 +1758,11 @@ _docker_run() {
__docker_nospace
fi
;;
seccomp:*)
local cur=${cur##*:}
_filedir
COMPREPLY+=( $( compgen -W "unconfined" -- "$cur" ) )
;;
*)
COMPREPLY=( $( compgen -W "label apparmor seccomp" -S ":" -- "$cur") )
__docker_nospace
@@ -1903,7 +2003,15 @@ _docker_volume_inspect() {
_docker_volume_ls() {
case "$prev" in
--filter|-f)
COMPREPLY=( $( compgen -W "dangling=true" -- "$cur" ) )
COMPREPLY=( $( compgen -S = -W "dangling" -- "$cur" ) )
__docker_nospace
return
;;
esac
case "${words[$cword-2]}$prev=" in
*dangling=*)
COMPREPLY=( $( compgen -W "true false" -- "${cur#=}" ) )
return
;;
esac

View File

@@ -204,7 +204,7 @@ __docker_get_log_options() {
gelf_options=("env" "gelf-address" "labels" "tag")
journald_options=("env" "labels")
json_file_options=("env" "labels" "max-file" "max-size")
syslog_options=("syslog-address" "syslog-facility" "tag")
syslog_options=("syslog-address" "syslog-tls-ca-cert" "syslog-tls-cert" "syslog-tls-key" "syslog-tls-skip-verify" "syslog-facility" "tag")
splunk_options=("env" "labels" "splunk-caname" "splunk-capath" "splunk-index" "splunk-insecureskipverify" "splunk-source" "splunk-sourcetype" "splunk-token" "splunk-url" "tag")
[[ $log_driver = (awslogs|all) ]] && _describe -t awslogs-options "awslogs options" awslogs_options "$@" && ret=0
@@ -231,6 +231,17 @@ __docker_log_options() {
return ret
}
__docker_complete_detach_keys() {
[[ $PREFIX = -* ]] && return 1
integer ret=1
compset -P "*,"
keys=(${:-{a-z}})
ctrl_keys=(${:-ctrl-{{a-z},{@,'[','\\','^',']',_}}})
_describe -t detach_keys "[a-z]" keys -qS "," && ret=0
_describe -t detach_keys-ctrl "'ctrl-' + 'a-z @ [ \\\\ ] ^ _'" ctrl_keys -qS "," && ret=0
}
__docker_networks() {
[[ $PREFIX = -* ]] && return 1
integer ret=1
@@ -291,24 +302,46 @@ __docker_network_subcommand() {
opts_help=("(: -)--help[Print usage]")
case "$words[1]" in
(connect|disconnect)
(connect)
_arguments $(__docker_arguments) \
$opts_help \
"($help)*--alias=[Add network-scoped alias for the container]:alias: " \
"($help)--ip=[Container IPv4 address]:IPv4: " \
"($help)--ip6=[Container IPv6 address]:IPv6: " \
"($help)*--link=[Add a link to another container]:link:->link" \
"($help -)1:network:__docker_networks" \
"($help -)2:containers:__docker_runningcontainers" && ret=0
"($help -)2:containers:__docker_containers" && ret=0
case $state in
(link)
if compset -P "*:"; then
_wanted alias expl "Alias" compadd -E "" && ret=0
else
__docker_runningcontainers -qS ":" && ret=0
fi
;;
esac
;;
(create)
_arguments $(__docker_arguments) -A '-*' \
$opts_help \
"($help -d --driver)"{-d=,--driver=}"[Driver to manage the Network]:driver:(null host bridge overlay)" \
"($help)--ipam-driver=[IP Address Management Driver]:driver:(default)" \
"($help)*--subnet=[Subnet in CIDR format that represents a network segment]:IP/mask: " \
"($help)*--ip-range=[Allocate container ip from a sub-range]:IP/mask: " \
"($help)*--gateway=[ipv4 or ipv6 Gateway for the master subnet]:IP: " \
"($help)*--aux-address[Auxiliary ipv4 or ipv6 addresses used by network driver]:key=IP: " \
"($help)*"{-o=,--opt=}"[Set driver specific options]:key=value: " \
"($help -d --driver)"{-d=,--driver=}"[Driver to manage the Network]:driver:(null host bridge overlay)" \
"($help)*--gateway=[ipv4 or ipv6 Gateway for the master subnet]:IP: " \
"($help)--internal[Restricts external access to the network]" \
"($help)*--ip-range=[Allocate container ip from a sub-range]:IP/mask: " \
"($help)--ipam-driver=[IP Address Management Driver]:driver:(default)" \
"($help)*--ipam-opt=[Set custom IPAM plugin options]:opt=value: " \
"($help)*"{-o=,--opt=}"[Set driver specific options]:opt=value: " \
"($help)*--subnet=[Subnet in CIDR format that represents a network segment]:IP/mask: " \
"($help -)1:Network Name: " && ret=0
;;
(disconnect)
_arguments $(__docker_arguments) \
$opts_help \
"($help -)1:network:__docker_networks" \
"($help -)2:containers:__docker_containers" && ret=0
;;
(inspect)
_arguments $(__docker_arguments) \
$opts_help \
@@ -485,6 +518,8 @@ __docker_subcommand() {
"($help)*--group-add=[Add additional groups to run as]:group:_groups"
"($help -h --hostname)"{-h=,--hostname=}"[Container host name]:hostname:_hosts"
"($help -i --interactive)"{-i,--interactive}"[Keep stdin open even if not attached]"
"($help)--ip=[Container IPv4 address]:IPv4: "
"($help)--ip6=[Container IPv6 address]:IPv6: "
"($help)--ipc=[IPC namespace to use]:IPC namespace: "
"($help)*--link=[Add link to another container]:link:->link"
"($help)*"{-l=,--label=}"[Set meta data on a container]:label: "
@@ -493,6 +528,7 @@ __docker_subcommand() {
"($help)--mac-address=[Container MAC address]:MAC address: "
"($help)--name=[Container name]:name: "
"($help)--net=[Connect a container to a network]:network mode:(bridge none container host)"
"($help)*--net-alias=[Add network-scoped alias for the container]:alias: "
"($help)--oom-kill-disable[Disable OOM Killer]"
"($help)--oom-score-adj[Tune the host's OOM preferences for containers (accepts -1000 to 1000)]"
"($help -P --publish-all)"{-P,--publish-all}"[Publish all exposed ports]"
@@ -515,11 +551,15 @@ __docker_subcommand() {
"($help)--kernel-memory=[Kernel memory limit in bytes.]:Memory limit: "
"($help)--memory-reservation=[Memory soft limit]:Memory limit: "
)
opts_attach_exec_run_start=(
"($help)--detach-keys=[Specify the escape key sequence used to detach a container]:sequence:__docker_complete_detach_keys"
)
case "$words[1]" in
(attach)
_arguments $(__docker_arguments) \
$opts_help \
$opts_attach_exec_run_start \
"($help)--no-stdin[Do not attach stdin]" \
"($help)--sig-proxy[Proxy all received signals to the process (non-TTY mode only)]" \
"($help -):containers:__docker_runningcontainers" && ret=0
@@ -552,6 +592,7 @@ __docker_subcommand() {
(cp)
_arguments $(__docker_arguments) \
$opts_help \
"($help -L --follow-link)"{-L,--follow-link}"[Always follow symbol link in SRC_PATH]" \
"($help -)1:container:->container" \
"($help -)2:hostpath:_files" && ret=0
case $state in
@@ -650,7 +691,7 @@ __docker_subcommand() {
if compset -P '*='; then
_files && ret=0
else
opts=('kv.cacertfile' 'kv.certfile' 'kv.keyfile')
opts=('discovery.heartbeat' 'discovery.ttl' 'kv.cacertfile' 'kv.certfile' 'kv.keyfile' 'kv.path')
_describe -t cluster-store-opts "Cluster Store Options" opts -qS "=" && ret=0
fi
;;
@@ -680,6 +721,7 @@ __docker_subcommand() {
local state
_arguments $(__docker_arguments) \
$opts_help \
$opts_attach_exec_run_start \
"($help -d --detach)"{-d,--detach}"[Detached mode: leave the container running in the background]" \
"($help -i --interactive)"{-i,--interactive}"[Keep stdin open even if not attached]" \
"($help)--privileged[Give extended Linux capabilities to the command]" \
@@ -874,6 +916,7 @@ __docker_subcommand() {
$opts_build_create_run_update \
$opts_create_run \
$opts_create_run_update \
$opts_attach_exec_run_start \
"($help -d --detach)"{-d,--detach}"[Detached mode: leave the container running in the background]" \
"($help)--rm[Remove intermediate containers when it exits]" \
"($help)--sig-proxy[Proxy all received signals to the process (non-TTY mode only)]" \
@@ -910,6 +953,7 @@ __docker_subcommand() {
(start)
_arguments $(__docker_arguments) \
$opts_help \
$opts_attach_exec_run_start \
"($help -a --attach)"{-a,--attach}"[Attach container's stdout/stderr and forward all signals]" \
"($help -i --interactive)"{-i,--interactive}"[Attach container's stding]" \
"($help -)*:containers:__docker_stoppedcontainers" && ret=0
@@ -924,7 +968,6 @@ __docker_subcommand() {
(tag)
_arguments $(__docker_arguments) \
$opts_help \
"($help -f --force)"{-f,--force}"[force]"\
"($help -):source:__docker_images"\
"($help -):destination:__docker_repositories_with_tags" && ret=0
;;

View File

@@ -1,5 +1,12 @@
# Docker Upstart and SysVinit configuration file
#
# THIS FILE DOES NOT APPLY TO SYSTEMD
#
# Please see the documentation for "systemd drop-ins":
# https://docs.docker.com/engine/articles/systemd/
#
# Customize location of Docker binary (especially for development testing).
#DOCKER="/usr/local/bin/docker"

View File

@@ -11,7 +11,7 @@ let b:current_syntax = "dockerfile"
syntax case ignore
syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|CMD|ENTRYPOINT|ENV|EXPOSE|FROM|MAINTAINER|RUN|USER|LABEL|VOLUME|WORKDIR|COPY|STOPSIGNAL)\s/
syntax match dockerfileKeyword /\v^\s*(ONBUILD\s+)?(ADD|CMD|ENTRYPOINT|ENV|EXPOSE|FROM|MAINTAINER|RUN|USER|LABEL|VOLUME|WORKDIR|COPY|STOPSIGNAL|ARG)\s/
highlight link dockerfileKeyword Keyword
syntax region dockerfileString start=/\v"/ skip=/\v\\./ end=/\v"/

View File

@@ -248,13 +248,13 @@ func (daemon *Daemon) containerExtractToDir(container *container.Container, path
return ErrRootFSReadOnly
}
uid, gid := daemon.GetRemappedUIDGID()
options := &archive.TarOptions{
ChownOpts: &archive.TarChownOptions{
UID: 0, GID: 0, // TODO: use config.User? Remap to userns root?
},
NoOverwriteDirNonDir: noOverwriteDirNonDir,
ChownOpts: &archive.TarChownOptions{
UID: uid, GID: gid, // TODO: should all ownership be set to root (either real or remapped)?
},
}
if err := chrootarchive.Untar(content, resolvedPath, options); err != nil {
return err
}

View File

@@ -21,6 +21,15 @@ const (
disableNetworkBridge = "none"
)
// flatOptions contains configuration keys
// that MUST NOT be parsed as deep structures.
// Use this to differentiate these options
// with others like the ones in CommonTLSOptions.
var flatOptions = map[string]bool{
"cluster-store-opts": true,
"log-opts": true,
}
// LogConfig represents the default log configuration.
// It includes json tags to deserialize configuration from a file
// using the same names that the flags in the command line uses.
@@ -45,7 +54,6 @@ type CommonTLSOptions struct {
type CommonConfig struct {
AuthorizationPlugins []string `json:"authorization-plugins,omitempty"` // AuthorizationPlugins holds list of authorization plugins
AutoRestart bool `json:"-"`
Bridge bridgeConfig `json:"-"` // Bridge holds bridge network specific configuration.
Context map[string][]string `json:"-"`
DisableBridge bool `json:"-"`
DNS []string `json:"dns,omitempty"`
@@ -56,7 +64,6 @@ type CommonConfig struct {
GraphDriver string `json:"storage-driver,omitempty"`
GraphOptions []string `json:"storage-opts,omitempty"`
Labels []string `json:"labels,omitempty"`
LogConfig LogConfig `json:"log-config,omitempty"`
Mtu int `json:"mtu,omitempty"`
Pidfile string `json:"pidfile,omitempty"`
Root string `json:"graph,omitempty"`
@@ -76,14 +83,20 @@ type CommonConfig struct {
// reachable by other hosts.
ClusterAdvertise string `json:"cluster-advertise,omitempty"`
Debug bool `json:"debug,omitempty"`
Hosts []string `json:"hosts,omitempty"`
LogLevel string `json:"log-level,omitempty"`
TLS bool `json:"tls,omitempty"`
TLSVerify bool `json:"tls-verify,omitempty"`
TLSOptions CommonTLSOptions `json:"tls-opts,omitempty"`
Debug bool `json:"debug,omitempty"`
Hosts []string `json:"hosts,omitempty"`
LogLevel string `json:"log-level,omitempty"`
TLS bool `json:"tls,omitempty"`
TLSVerify bool `json:"tlsverify,omitempty"`
// Embedded structs that allow config
// deserialization without the full struct.
CommonTLSOptions
LogConfig
bridgeConfig // bridgeConfig holds bridge network specific configuration.
reloadLock sync.Mutex
valuesSet map[string]interface{}
}
// InstallCommonFlags adds command-line options to the top-level flag parser for
@@ -112,6 +125,16 @@ func (config *Config) InstallCommonFlags(cmd *flag.FlagSet, usageFn func(string)
cmd.Var(opts.NewNamedMapOpts("cluster-store-opts", config.ClusterOpts, nil), []string{"-cluster-store-opt"}, usageFn("Set cluster store options"))
}
// IsValueSet returns true if a configuration value
// was explicitly set in the configuration file.
func (config *Config) IsValueSet(name string) bool {
if config.valuesSet == nil {
return false
}
_, ok := config.valuesSet[name]
return ok
}
func parseClusterAdvertiseSettings(clusterStore, clusterAdvertise string) (string, error) {
if clusterAdvertise == "" {
return "", errDiscoveryDisabled
@@ -128,14 +151,20 @@ func parseClusterAdvertiseSettings(clusterStore, clusterAdvertise string) (strin
}
// ReloadConfiguration reads the configuration in the host and reloads the daemon and server.
func ReloadConfiguration(configFile string, flags *flag.FlagSet, reload func(*Config)) {
func ReloadConfiguration(configFile string, flags *flag.FlagSet, reload func(*Config)) error {
logrus.Infof("Got signal to reload configuration, reloading from: %s", configFile)
newConfig, err := getConflictFreeConfiguration(configFile, flags)
if err != nil {
logrus.Error(err)
} else {
reload(newConfig)
return err
}
reload(newConfig)
return nil
}
// boolValue is an interface that boolean value flags implement
// to tell the command line how to make -name equivalent to -name=true.
type boolValue interface {
IsBoolFlag() bool
}
// MergeDaemonConfigurations reads a configuration file,
@@ -165,6 +194,7 @@ func getConflictFreeConfiguration(configFile string, flags *flag.FlagSet) (*Conf
return nil, err
}
var config Config
var reader io.Reader
if flags != nil {
var jsonConfig map[string]interface{}
@@ -173,41 +203,110 @@ func getConflictFreeConfiguration(configFile string, flags *flag.FlagSet) (*Conf
return nil, err
}
if err := findConfigurationConflicts(jsonConfig, flags); err != nil {
configSet := configValuesSet(jsonConfig)
if err := findConfigurationConflicts(configSet, flags); err != nil {
return nil, err
}
// Override flag values to make sure the values set in the config file with nullable values, like `false`,
// are not overriden by default truthy values from the flags that were not explicitly set.
// See https://github.com/docker/docker/issues/20289 for an example.
//
// TODO: Rewrite configuration logic to avoid same issue with other nullable values, like numbers.
namedOptions := make(map[string]interface{})
for key, value := range configSet {
f := flags.Lookup("-" + key)
if f == nil { // ignore named flags that don't match
namedOptions[key] = value
continue
}
if _, ok := f.Value.(boolValue); ok {
f.Value.Set(fmt.Sprintf("%v", value))
}
}
if len(namedOptions) > 0 {
// set also default for mergeVal flags that are boolValue at the same time.
flags.VisitAll(func(f *flag.Flag) {
if opt, named := f.Value.(opts.NamedOption); named {
v, set := namedOptions[opt.Name()]
_, boolean := f.Value.(boolValue)
if set && boolean {
f.Value.Set(fmt.Sprintf("%v", v))
}
}
})
}
config.valuesSet = configSet
}
var config Config
reader = bytes.NewReader(b)
err = json.NewDecoder(reader).Decode(&config)
return &config, err
}
// findConfigurationConflicts iterates over the provided flags searching for
// duplicated configurations. It returns an error with all the conflicts if
// it finds any.
func findConfigurationConflicts(config map[string]interface{}, flags *flag.FlagSet) error {
var conflicts []string
// configValuesSet returns the configuration values explicitly set in the file.
func configValuesSet(config map[string]interface{}) map[string]interface{} {
flatten := make(map[string]interface{})
for k, v := range config {
if m, ok := v.(map[string]interface{}); ok {
if m, isMap := v.(map[string]interface{}); isMap && !flatOptions[k] {
for km, vm := range m {
flatten[km] = vm
}
} else {
flatten[k] = v
continue
}
flatten[k] = v
}
return flatten
}
// findConfigurationConflicts iterates over the provided flags searching for
// duplicated configurations and unknown keys. It returns an error with all the conflicts if
// it finds any.
func findConfigurationConflicts(config map[string]interface{}, flags *flag.FlagSet) error {
// 1. Search keys from the file that we don't recognize as flags.
unknownKeys := make(map[string]interface{})
for key, value := range config {
flagName := "-" + key
if flag := flags.Lookup(flagName); flag == nil {
unknownKeys[key] = value
}
}
// 2. Discard values that implement NamedOption.
// Their configuration name differs from their flag name, like `labels` and `label`.
if len(unknownKeys) > 0 {
unknownNamedConflicts := func(f *flag.Flag) {
if namedOption, ok := f.Value.(opts.NamedOption); ok {
if _, valid := unknownKeys[namedOption.Name()]; valid {
delete(unknownKeys, namedOption.Name())
}
}
}
flags.VisitAll(unknownNamedConflicts)
}
if len(unknownKeys) > 0 {
var unknown []string
for key := range unknownKeys {
unknown = append(unknown, key)
}
return fmt.Errorf("the following directives don't match any configuration option: %s", strings.Join(unknown, ", "))
}
var conflicts []string
printConflict := func(name string, flagValue, fileValue interface{}) string {
return fmt.Sprintf("%s: (from flag: %v, from file: %v)", name, flagValue, fileValue)
}
collectConflicts := func(f *flag.Flag) {
// 3. Search keys that are present as a flag and as a file option.
duplicatedConflicts := func(f *flag.Flag) {
// search option name in the json configuration payload if the value is a named option
if namedOption, ok := f.Value.(opts.NamedOption); ok {
if optsValue, ok := flatten[namedOption.Name()]; ok {
if optsValue, ok := config[namedOption.Name()]; ok {
conflicts = append(conflicts, printConflict(namedOption.Name(), f.Value.String(), optsValue))
}
} else {
@@ -215,7 +314,7 @@ func findConfigurationConflicts(config map[string]interface{}, flags *flag.FlagS
for _, name := range f.Names {
name = strings.TrimLeft(name, "-")
if value, ok := flatten[name]; ok {
if value, ok := config[name]; ok {
conflicts = append(conflicts, printConflict(name, f.Value.String(), value))
break
}
@@ -223,7 +322,7 @@ func findConfigurationConflicts(config map[string]interface{}, flags *flag.FlagS
}
}
flags.Visit(collectConflicts)
flags.Visit(duplicatedConflicts)
if len(conflicts) > 0 {
return fmt.Errorf("the following directives are specified both as a flag and in the configuration file: %s", strings.Join(conflicts, ", "))

View File

@@ -89,21 +89,16 @@ func TestFindConfigurationConflicts(t *testing.T) {
config := map[string]interface{}{"authorization-plugins": "foobar"}
flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
flags.String([]string{"-authorization-plugins"}, "", "")
if err := flags.Set("-authorization-plugins", "asdf"); err != nil {
t.Fatal(err)
}
err := findConfigurationConflicts(config, flags)
if err != nil {
t.Fatal(err)
}
flags.String([]string{"authorization-plugins"}, "", "")
if err := flags.Set("authorization-plugins", "asdf"); err != nil {
t.Fatal(err)
}
err = findConfigurationConflicts(config, flags)
if err == nil {
t.Fatal("expected error, got nil")
}
if !strings.Contains(err.Error(), "authorization-plugins") {
if !strings.Contains(err.Error(), "authorization-plugins: (from flag: asdf, from file: foobar)") {
t.Fatalf("expected authorization-plugins conflict, got %v", err)
}
}
@@ -175,3 +170,41 @@ func TestDaemonConfigurationMergeConflictsWithInnerStructs(t *testing.T) {
t.Fatalf("expected tlscacert conflict, got %v", err)
}
}
func TestFindConfigurationConflictsWithUnknownKeys(t *testing.T) {
config := map[string]interface{}{"tls-verify": "true"}
flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
flags.Bool([]string{"-tlsverify"}, false, "")
err := findConfigurationConflicts(config, flags)
if err == nil {
t.Fatal("expected error, got nil")
}
if !strings.Contains(err.Error(), "the following directives don't match any configuration option: tls-verify") {
t.Fatalf("expected tls-verify conflict, got %v", err)
}
}
func TestFindConfigurationConflictsWithMergedValues(t *testing.T) {
var hosts []string
config := map[string]interface{}{"hosts": "tcp://127.0.0.1:2345"}
base := mflag.NewFlagSet("base", mflag.ContinueOnError)
base.Var(opts.NewNamedListOptsRef("hosts", &hosts, nil), []string{"H", "-host"}, "")
flags := mflag.NewFlagSet("test", mflag.ContinueOnError)
mflag.Merge(flags, base)
err := findConfigurationConflicts(config, flags)
if err != nil {
t.Fatal(err)
}
flags.Set("-host", "unix:///var/run/docker.sock")
err = findConfigurationConflicts(config, flags)
if err == nil {
t.Fatal("expected error, got nil")
}
if !strings.Contains(err.Error(), "hosts: (from flag: [unix:///var/run/docker.sock], from file: tcp://127.0.0.1:2345)") {
t.Fatalf("expected hosts conflict, got %v", err)
}
}

View File

@@ -37,19 +37,19 @@ type Config struct {
// bridgeConfig stores all the bridge driver specific
// configuration.
type bridgeConfig struct {
EnableIPv6 bool
EnableIPTables bool
EnableIPForward bool
EnableIPMasq bool
EnableUserlandProxy bool
DefaultIP net.IP
Iface string
IP string
FixedCIDR string
FixedCIDRv6 string
DefaultGatewayIPv4 net.IP
DefaultGatewayIPv6 net.IP
InterContainerCommunication bool
EnableIPv6 bool `json:"ipv6,omitempty"`
EnableIPTables bool `json:"iptables,omitempty"`
EnableIPForward bool `json:"ip-forward,omitempty"`
EnableIPMasq bool `json:"ip-mask,omitempty"`
EnableUserlandProxy bool `json:"userland-proxy,omitempty"`
DefaultIP net.IP `json:"ip,omitempty"`
Iface string `json:"bridge,omitempty"`
IP string `json:"bip,omitempty"`
FixedCIDR string `json:"fixed-cidr,omitempty"`
FixedCIDRv6 string `json:"fixed-cidr-v6,omitempty"`
DefaultGatewayIPv4 net.IP `json:"default-gateway,omitempty"`
DefaultGatewayIPv6 net.IP `json:"default-gateway-v6,omitempty"`
InterContainerCommunication bool `json:"icc,omitempty"`
}
// InstallFlags adds command-line options to the top-level flag parser for
@@ -65,19 +65,19 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin
cmd.StringVar(&config.SocketGroup, []string{"G", "-group"}, "docker", usageFn("Group for the unix socket"))
config.Ulimits = make(map[string]*units.Ulimit)
cmd.Var(runconfigopts.NewUlimitOpt(&config.Ulimits), []string{"-default-ulimit"}, usageFn("Set default ulimits for containers"))
cmd.BoolVar(&config.Bridge.EnableIPTables, []string{"#iptables", "-iptables"}, true, usageFn("Enable addition of iptables rules"))
cmd.BoolVar(&config.Bridge.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, usageFn("Enable net.ipv4.ip_forward"))
cmd.BoolVar(&config.Bridge.EnableIPMasq, []string{"-ip-masq"}, true, usageFn("Enable IP masquerading"))
cmd.BoolVar(&config.Bridge.EnableIPv6, []string{"-ipv6"}, false, usageFn("Enable IPv6 networking"))
cmd.StringVar(&config.Bridge.IP, []string{"#bip", "-bip"}, "", usageFn("Specify network bridge IP"))
cmd.StringVar(&config.Bridge.Iface, []string{"b", "-bridge"}, "", usageFn("Attach containers to a network bridge"))
cmd.StringVar(&config.Bridge.FixedCIDR, []string{"-fixed-cidr"}, "", usageFn("IPv4 subnet for fixed IPs"))
cmd.StringVar(&config.Bridge.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", usageFn("IPv6 subnet for fixed IPs"))
cmd.Var(opts.NewIPOpt(&config.Bridge.DefaultGatewayIPv4, ""), []string{"-default-gateway"}, usageFn("Container default gateway IPv4 address"))
cmd.Var(opts.NewIPOpt(&config.Bridge.DefaultGatewayIPv6, ""), []string{"-default-gateway-v6"}, usageFn("Container default gateway IPv6 address"))
cmd.BoolVar(&config.Bridge.InterContainerCommunication, []string{"#icc", "-icc"}, true, usageFn("Enable inter-container communication"))
cmd.Var(opts.NewIPOpt(&config.Bridge.DefaultIP, "0.0.0.0"), []string{"#ip", "-ip"}, usageFn("Default IP when binding container ports"))
cmd.BoolVar(&config.Bridge.EnableUserlandProxy, []string{"-userland-proxy"}, true, usageFn("Use userland proxy for loopback traffic"))
cmd.BoolVar(&config.bridgeConfig.EnableIPTables, []string{"#iptables", "-iptables"}, true, usageFn("Enable addition of iptables rules"))
cmd.BoolVar(&config.bridgeConfig.EnableIPForward, []string{"#ip-forward", "-ip-forward"}, true, usageFn("Enable net.ipv4.ip_forward"))
cmd.BoolVar(&config.bridgeConfig.EnableIPMasq, []string{"-ip-masq"}, true, usageFn("Enable IP masquerading"))
cmd.BoolVar(&config.bridgeConfig.EnableIPv6, []string{"-ipv6"}, false, usageFn("Enable IPv6 networking"))
cmd.StringVar(&config.bridgeConfig.IP, []string{"#bip", "-bip"}, "", usageFn("Specify network bridge IP"))
cmd.StringVar(&config.bridgeConfig.Iface, []string{"b", "-bridge"}, "", usageFn("Attach containers to a network bridge"))
cmd.StringVar(&config.bridgeConfig.FixedCIDR, []string{"-fixed-cidr"}, "", usageFn("IPv4 subnet for fixed IPs"))
cmd.StringVar(&config.bridgeConfig.FixedCIDRv6, []string{"-fixed-cidr-v6"}, "", usageFn("IPv6 subnet for fixed IPs"))
cmd.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultGatewayIPv4, ""), []string{"-default-gateway"}, usageFn("Container default gateway IPv4 address"))
cmd.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultGatewayIPv6, ""), []string{"-default-gateway-v6"}, usageFn("Container default gateway IPv6 address"))
cmd.BoolVar(&config.bridgeConfig.InterContainerCommunication, []string{"#icc", "-icc"}, true, usageFn("Enable inter-container communication"))
cmd.Var(opts.NewIPOpt(&config.bridgeConfig.DefaultIP, "0.0.0.0"), []string{"#ip", "-ip"}, usageFn("Default IP when binding container ports"))
cmd.BoolVar(&config.bridgeConfig.EnableUserlandProxy, []string{"-userland-proxy"}, true, usageFn("Use userland proxy for loopback traffic"))
cmd.BoolVar(&config.EnableCors, []string{"#api-enable-cors", "#-api-enable-cors"}, false, usageFn("Enable CORS headers in the remote API, this is deprecated by --api-cors-header"))
cmd.StringVar(&config.CorsHeaders, []string{"-api-cors-header"}, "", usageFn("Set CORS headers in the remote API"))
cmd.StringVar(&config.CgroupParent, []string{"-cgroup-parent"}, "", usageFn("Set parent cgroup for all containers"))

View File

@@ -15,7 +15,7 @@ var (
// bridgeConfig stores all the bridge driver specific
// configuration.
type bridgeConfig struct {
VirtualSwitchName string
VirtualSwitchName string `json:"bridge,omitempty"`
}
// Config defines the configuration of a docker daemon.
@@ -37,5 +37,5 @@ func (config *Config) InstallFlags(cmd *flag.FlagSet, usageFn func(string) strin
config.InstallCommonFlags(cmd, usageFn)
// Then platform-specific install flags.
cmd.StringVar(&config.Bridge.VirtualSwitchName, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch")
cmd.StringVar(&config.bridgeConfig.VirtualSwitchName, []string{"b", "-bridge"}, "", "Attach containers to a virtual switch")
}

View File

@@ -21,7 +21,6 @@ import (
"github.com/docker/docker/pkg/fileutils"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/mount"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/runconfig"
containertypes "github.com/docker/engine-api/types/container"
@@ -94,11 +93,6 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
return err
}
c.MqueuePath, err = c.MqueueResourcePath()
if err != nil {
return err
}
if c.HostConfig.IpcMode.IsContainer() {
ic, err := daemon.getIpcContainer(c)
if err != nil {
@@ -106,18 +100,13 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
}
ipc.ContainerID = ic.ID
c.ShmPath = ic.ShmPath
c.MqueuePath = ic.MqueuePath
} else {
ipc.HostIpc = c.HostConfig.IpcMode.IsHost()
if ipc.HostIpc {
if _, err := os.Stat("/dev/shm"); err != nil {
return fmt.Errorf("/dev/shm is not mounted, but must be for --ipc=host")
}
if _, err := os.Stat("/dev/mqueue"); err != nil {
return fmt.Errorf("/dev/mqueue is not mounted, but must be for --ipc=host")
}
c.ShmPath = "/dev/shm"
c.MqueuePath = "/dev/mqueue"
}
}
@@ -209,10 +198,12 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
BlkioThrottleWriteBpsDevice: writeBpsDevice,
BlkioThrottleReadIOpsDevice: readIOpsDevice,
BlkioThrottleWriteIOpsDevice: writeIOpsDevice,
OomKillDisable: *c.HostConfig.OomKillDisable,
MemorySwappiness: -1,
}
if c.HostConfig.OomKillDisable != nil {
resources.OomKillDisable = *c.HostConfig.OomKillDisable
}
if c.HostConfig.MemorySwappiness != nil {
resources.MemorySwappiness = *c.HostConfig.MemorySwappiness
}
@@ -249,16 +240,8 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
defaultCgroupParent := "/docker"
if daemon.configStore.CgroupParent != "" {
defaultCgroupParent = daemon.configStore.CgroupParent
} else {
for _, option := range daemon.configStore.ExecOptions {
key, val, err := parsers.ParseKeyValueOpt(option)
if err != nil || !strings.EqualFold(key, "native.cgroupdriver") {
continue
}
if val == "systemd" {
defaultCgroupParent = "system.slice"
}
}
} else if daemon.usingSystemd() {
defaultCgroupParent = "system.slice"
}
c.Command = &execdriver.Command{
CommonCommand: execdriver.CommonCommand{
@@ -513,7 +496,7 @@ func (daemon *Daemon) updateEndpointNetworkSettings(container *container.Contain
}
if container.HostConfig.NetworkMode == containertypes.NetworkMode("bridge") {
container.NetworkSettings.Bridge = daemon.configStore.Bridge.Iface
container.NetworkSettings.Bridge = daemon.configStore.bridgeConfig.Iface
}
return nil
@@ -658,6 +641,9 @@ func hasUserDefinedIPAddress(epConfig *networktypes.EndpointSettings) bool {
// User specified ip address is acceptable only for networks with user specified subnets.
func validateNetworkingConfig(n libnetwork.Network, epConfig *networktypes.EndpointSettings) error {
if n == nil || epConfig == nil {
return nil
}
if !hasUserDefinedIPAddress(epConfig) {
return nil
}
@@ -704,7 +690,7 @@ func cleanOperationalData(es *networktypes.EndpointSettings) {
es.MacAddress = ""
}
func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrName string, updateSettings bool) (libnetwork.Network, error) {
func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (libnetwork.Network, error) {
if container.HostConfig.NetworkMode.IsContainer() {
return nil, runconfig.ErrConflictSharedNetwork
}
@@ -715,11 +701,24 @@ func (daemon *Daemon) updateNetworkConfig(container *container.Container, idOrNa
return nil, nil
}
if !containertypes.NetworkMode(idOrName).IsUserDefined() {
if hasUserDefinedIPAddress(endpointConfig) {
return nil, runconfig.ErrUnsupportedNetworkAndIP
}
if endpointConfig != nil && len(endpointConfig.Aliases) > 0 {
return nil, runconfig.ErrUnsupportedNetworkAndAlias
}
}
n, err := daemon.FindNetwork(idOrName)
if err != nil {
return nil, err
}
if err := validateNetworkingConfig(n, endpointConfig); err != nil {
return nil, err
}
if updateSettings {
if err := daemon.updateNetworkSettings(container, n); err != nil {
return nil, err
@@ -734,9 +733,12 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName
if container.RemovalInProgress || container.Dead {
return derr.ErrorCodeRemovalContainer.WithArgs(container.ID)
}
if _, err := daemon.updateNetworkConfig(container, idOrName, true); err != nil {
if _, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, true); err != nil {
return err
}
if endpointConfig != nil {
container.NetworkSettings.Networks[idOrName] = endpointConfig
}
} else {
if err := daemon.connectToNetwork(container, idOrName, endpointConfig, true); err != nil {
return err
@@ -749,7 +751,7 @@ func (daemon *Daemon) ConnectToNetwork(container *container.Container, idOrName
}
func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName string, endpointConfig *networktypes.EndpointSettings, updateSettings bool) (err error) {
n, err := daemon.updateNetworkConfig(container, idOrName, updateSettings)
n, err := daemon.updateNetworkConfig(container, idOrName, endpointConfig, updateSettings)
if err != nil {
return err
}
@@ -757,25 +759,10 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
return nil
}
if !containertypes.NetworkMode(idOrName).IsUserDefined() && hasUserDefinedIPAddress(endpointConfig) {
return runconfig.ErrUnsupportedNetworkAndIP
}
if !containertypes.NetworkMode(idOrName).IsUserDefined() && len(endpointConfig.Aliases) > 0 {
return runconfig.ErrUnsupportedNetworkAndAlias
}
controller := daemon.netController
if err := validateNetworkingConfig(n, endpointConfig); err != nil {
return err
}
if endpointConfig != nil {
container.NetworkSettings.Networks[n.Name()] = endpointConfig
}
createOptions, err := container.BuildCreateEndpointOptions(n)
sb := daemon.getNetworkSandbox(container)
createOptions, err := container.BuildCreateEndpointOptions(n, endpointConfig, sb)
if err != nil {
return err
}
@@ -793,11 +780,14 @@ func (daemon *Daemon) connectToNetwork(container *container.Container, idOrName
}
}()
if endpointConfig != nil {
container.NetworkSettings.Networks[n.Name()] = endpointConfig
}
if err := daemon.updateEndpointNetworkSettings(container, n, ep); err != nil {
return err
}
sb := daemon.getNetworkSandbox(container)
if sb == nil {
options, err := daemon.buildSandboxOptions(container, n)
if err != nil {
@@ -1000,6 +990,8 @@ func (daemon *Daemon) releaseNetwork(container *container.Container) {
sid := container.NetworkSettings.SandboxID
settings := container.NetworkSettings.Networks
container.NetworkSettings.Ports = nil
if sid == "" || len(settings) == 0 {
return
}
@@ -1055,21 +1047,6 @@ func (daemon *Daemon) setupIpcDirs(c *container.Container) error {
}
}
if !c.HasMountFor("/dev/mqueue") {
mqueuePath, err := c.MqueueResourcePath()
if err != nil {
return err
}
if err := idtools.MkdirAllAs(mqueuePath, 0700, rootUID, rootGID); err != nil {
return err
}
if err := syscall.Mount("mqueue", mqueuePath, "mqueue", uintptr(syscall.MS_NOEXEC|syscall.MS_NOSUID|syscall.MS_NODEV), ""); err != nil {
return fmt.Errorf("mounting mqueue mqueue : %s", err)
}
}
return nil
}

View File

@@ -54,7 +54,7 @@ func (daemon *Daemon) populateCommand(c *container.Container, env []string) erro
if !c.Config.NetworkDisabled {
en.Interface = &execdriver.NetworkInterface{
MacAddress: c.Config.MacAddress,
Bridge: daemon.configStore.Bridge.VirtualSwitchName,
Bridge: daemon.configStore.bridgeConfig.VirtualSwitchName,
PortBindings: c.HostConfig.PortBindings,
// TODO Windows. Include IPAddress. There already is a

View File

@@ -26,6 +26,11 @@ func (daemon *Daemon) ContainerCreate(params types.ContainerCreateConfig) (types
return types.ContainerCreateResponse{Warnings: warnings}, err
}
err = daemon.verifyNetworkingConfig(params.NetworkingConfig)
if err != nil {
return types.ContainerCreateResponse{}, err
}
if params.HostConfig == nil {
params.HostConfig = &containertypes.HostConfig{}
}
@@ -105,7 +110,7 @@ func (daemon *Daemon) create(params types.ContainerCreateConfig) (retC *containe
}
}()
if err := daemon.createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig, img); err != nil {
if err := daemon.createContainerPlatformSpecificSettings(container, params.Config, params.HostConfig); err != nil {
return nil, err
}

View File

@@ -9,15 +9,13 @@ import (
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
derr "github.com/docker/docker/errors"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/volume"
containertypes "github.com/docker/engine-api/types/container"
"github.com/opencontainers/runc/libcontainer/label"
)
// createContainerPlatformSpecificSettings performs platform specific container create functionality
func (daemon *Daemon) createContainerPlatformSpecificSettings(container *container.Container, config *containertypes.Config, hostConfig *containertypes.HostConfig, img *image.Image) error {
func (daemon *Daemon) createContainerPlatformSpecificSettings(container *container.Container, config *containertypes.Config, hostConfig *containertypes.HostConfig) error {
if err := daemon.Mount(container); err != nil {
return err
}
@@ -46,17 +44,7 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
return derr.ErrorCodeMountOverFile.WithArgs(path)
}
volumeDriver := hostConfig.VolumeDriver
if destination != "" && img != nil {
if _, ok := img.ContainerConfig.Volumes[destination]; ok {
// check for whether bind is not specified and then set to local
if _, ok := container.MountPoints[destination]; !ok {
volumeDriver = volume.DefaultDriverName
}
}
}
v, err := daemon.volumes.CreateWithRef(name, volumeDriver, container.ID, nil)
v, err := daemon.volumes.CreateWithRef(name, hostConfig.VolumeDriver, container.ID, nil)
if err != nil {
return err
}

View File

@@ -4,14 +4,13 @@ import (
"fmt"
"github.com/docker/docker/container"
"github.com/docker/docker/image"
"github.com/docker/docker/pkg/stringid"
"github.com/docker/docker/volume"
containertypes "github.com/docker/engine-api/types/container"
)
// createContainerPlatformSpecificSettings performs platform specific container create functionality
func (daemon *Daemon) createContainerPlatformSpecificSettings(container *container.Container, config *containertypes.Config, hostConfig *containertypes.HostConfig, img *image.Image) error {
func (daemon *Daemon) createContainerPlatformSpecificSettings(container *container.Container, config *containertypes.Config, hostConfig *containertypes.HostConfig) error {
for spec := range config.Volumes {
mp, err := volume.ParseMountSpec(spec, hostConfig.VolumeDriver)
@@ -31,14 +30,6 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain
}
volumeDriver := hostConfig.VolumeDriver
if mp.Destination != "" && img != nil {
if _, ok := img.ContainerConfig.Volumes[mp.Destination]; ok {
// check for whether bind is not specified and then set to local
if _, ok := container.MountPoints[mp.Destination]; !ok {
volumeDriver = volume.DefaultDriverName
}
}
}
// Create the volume in the volume driver. If it doesn't exist,
// a new one will be created.

View File

@@ -31,6 +31,7 @@ import (
containertypes "github.com/docker/engine-api/types/container"
eventtypes "github.com/docker/engine-api/types/events"
"github.com/docker/engine-api/types/filters"
networktypes "github.com/docker/engine-api/types/network"
registrytypes "github.com/docker/engine-api/types/registry"
"github.com/docker/engine-api/types/strslice"
// register graph drivers
@@ -99,46 +100,11 @@ func (e ErrImageDoesNotExist) Error() string {
return fmt.Sprintf("no such id: %s", e.RefOrID)
}
type contStore struct {
s map[string]*container.Container
sync.Mutex
}
func (c *contStore) Add(id string, cont *container.Container) {
c.Lock()
c.s[id] = cont
c.Unlock()
}
func (c *contStore) Get(id string) *container.Container {
c.Lock()
res := c.s[id]
c.Unlock()
return res
}
func (c *contStore) Delete(id string) {
c.Lock()
delete(c.s, id)
c.Unlock()
}
func (c *contStore) List() []*container.Container {
containers := new(History)
c.Lock()
for _, cont := range c.s {
containers.Add(cont)
}
c.Unlock()
containers.sort()
return *containers
}
// Daemon holds information about the Docker daemon.
type Daemon struct {
ID string
repository string
containers *contStore
containers container.Store
execCommands *exec.Store
referenceStore reference.Store
downloadManager *xfer.LayerDownloadManager
@@ -282,10 +248,6 @@ func (daemon *Daemon) Register(container *container.Container) error {
}
}
if err := daemon.prepareMountPoints(container); err != nil {
return err
}
return nil
}
@@ -408,6 +370,23 @@ func (daemon *Daemon) restore() error {
}
group.Wait()
// any containers that were started above would already have had this done,
// however we need to now prepare the mountpoints for the rest of the containers as well.
// This shouldn't cause any issue running on the containers that already had this run.
// This must be run after any containers with a restart policy so that containerized plugins
// can have a chance to be running before we try to initialize them.
for _, c := range containers {
group.Add(1)
go func(c *container.Container) {
defer group.Done()
if err := daemon.prepareMountPoints(c); err != nil {
logrus.Error(err)
}
}(c)
}
group.Wait()
if !debug {
if logrus.GetLevel() == logrus.InfoLevel {
fmt.Println()
@@ -601,6 +580,10 @@ func (daemon *Daemon) parents(c *container.Container) map[string]*container.Cont
func (daemon *Daemon) registerLink(parent, child *container.Container, alias string) error {
fullName := path.Join(parent.Name, alias)
if err := daemon.nameIndex.Reserve(fullName, child.ID); err != nil {
if err == registrar.ErrNameReserved {
logrus.Warnf("error registering link for %s, to %s, as alias %s, ignoring: %v", parent.ID, child.ID, alias, err)
return nil
}
return err
}
daemon.linkIndex.link(parent, child, fullName)
@@ -612,8 +595,8 @@ func (daemon *Daemon) registerLink(parent, child *container.Container, alias str
func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemon, err error) {
setDefaultMtu(config)
// Ensure we have compatible configuration options
if err := checkConfigOptions(config); err != nil {
// Ensure we have compatible and valid configuration options
if err := verifyDaemonSettings(config); err != nil {
return nil, err
}
@@ -765,7 +748,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
migrationStart := time.Now()
if err := v1.Migrate(config.Root, graphDriver, d.layerStore, d.imageStore, referenceStore, distributionMetadataStore); err != nil {
return nil, err
logrus.Errorf("Graph migration failed: %q. Your old graph data was found to be too inconsistent for upgrading to content-addressable storage. Some of the old data was probably not upgraded. We recommend starting over with a clean storage directory if possible.", err)
}
logrus.Infof("Graph migration to content-addressability took %.2f seconds", time.Since(migrationStart).Seconds())
@@ -794,7 +777,7 @@ func NewDaemon(config *Config, registryService *registry.Service) (daemon *Daemo
d.ID = trustKey.PublicKey().KeyID()
d.repository = daemonRepo
d.containers = &contStore{s: make(map[string]*container.Container)}
d.containers = container.NewMemoryStore()
d.execCommands = exec.NewStore()
d.referenceStore = referenceStore
d.distributionMetadataStore = distributionMetadataStore
@@ -873,24 +856,18 @@ func (daemon *Daemon) shutdownContainer(c *container.Container) error {
func (daemon *Daemon) Shutdown() error {
daemon.shutdown = true
if daemon.containers != nil {
group := sync.WaitGroup{}
logrus.Debug("starting clean shutdown of all containers...")
for _, cont := range daemon.List() {
if !cont.IsRunning() {
continue
daemon.containers.ApplyAll(func(c *container.Container) {
if !c.IsRunning() {
return
}
logrus.Debugf("stopping %s", cont.ID)
group.Add(1)
go func(c *container.Container) {
defer group.Done()
if err := daemon.shutdownContainer(c); err != nil {
logrus.Errorf("Stop container error: %v", err)
return
}
logrus.Debugf("container stopped %s", c.ID)
}(cont)
}
group.Wait()
logrus.Debugf("stopping %s", c.ID)
if err := daemon.shutdownContainer(c); err != nil {
logrus.Errorf("Stop container error: %v", err)
return
}
logrus.Debugf("container stopped %s", c.ID)
})
}
// trigger libnetwork Stop only if it's initialized
@@ -1252,6 +1229,9 @@ func (daemon *Daemon) ImageHistory(name string) ([]*types.ImageHistory, error) {
func (daemon *Daemon) GetImageID(refOrID string) (image.ID, error) {
// Treat as an ID
if id, err := digest.ParseDigest(refOrID); err == nil {
if _, err := daemon.imageStore.Get(image.ID(id)); err != nil {
return "", ErrImageDoesNotExist{refOrID}
}
return image.ID(id), nil
}
@@ -1314,35 +1294,45 @@ func (daemon *Daemon) GetRemappedUIDGID() (int, int) {
return uid, gid
}
// ImageGetCached returns the earliest created image that is a child
// ImageGetCached returns the most recent created image that is a child
// of the image with imgID, that had the same config when it was
// created. nil is returned if a child cannot be found. An error is
// returned if the parent image cannot be found.
func (daemon *Daemon) ImageGetCached(imgID image.ID, config *containertypes.Config) (*image.Image, error) {
// Retrieve all images
imgs := daemon.Map()
var siblings []image.ID
for id, img := range imgs {
if img.Parent == imgID {
siblings = append(siblings, id)
}
}
// Loop on the children of the given image and check the config
var match *image.Image
for _, id := range siblings {
img, ok := imgs[id]
if !ok {
return nil, fmt.Errorf("unable to find image %q", id)
}
if runconfig.Compare(&img.ContainerConfig, config) {
if match == nil || match.Created.Before(img.Created) {
match = img
getMatch := func(siblings []image.ID) (*image.Image, error) {
var match *image.Image
for _, id := range siblings {
img, err := daemon.imageStore.Get(id)
if err != nil {
return nil, fmt.Errorf("unable to find image %q", id)
}
if runconfig.Compare(&img.ContainerConfig, config) {
// check for the most up to date match
if match == nil || match.Created.Before(img.Created) {
match = img
}
}
}
return match, nil
}
return match, nil
// In this case, this is `FROM scratch`, which isn't an actual image.
if imgID == "" {
images := daemon.imageStore.Map()
var siblings []image.ID
for id, img := range images {
if img.Parent == imgID {
siblings = append(siblings, id)
}
}
return getMatch(siblings)
}
// find match from child images
siblings := daemon.imageStore.Children(imgID)
return getMatch(siblings)
}
// tempDir returns the default directory to use for temporary files.
@@ -1440,6 +1430,18 @@ func (daemon *Daemon) verifyContainerSettings(hostConfig *containertypes.HostCon
return verifyPlatformContainerSettings(daemon, hostConfig, config)
}
// Checks if the client set configurations for more than one network while creating a container
func (daemon *Daemon) verifyNetworkingConfig(nwConfig *networktypes.NetworkingConfig) error {
if nwConfig == nil || len(nwConfig.EndpointsConfig) <= 1 {
return nil
}
l := make([]string, 0, len(nwConfig.EndpointsConfig))
for k := range nwConfig.EndpointsConfig {
l = append(l, k)
}
return derr.ErrorCodeMultipleNetworkConnect.WithArgs(fmt.Sprintf("%v", l))
}
func configureVolumes(config *Config, rootUID, rootGID int) (*store.VolumeStore, error) {
volumesDriver, err := local.New(config.Root, rootUID, rootGID)
if err != nil {
@@ -1536,13 +1538,12 @@ func (daemon *Daemon) initDiscovery(config *Config) error {
// daemon according to those changes.
// This are the settings that Reload changes:
// - Daemon labels.
// - Cluster discovery (reconfigure and restart).
func (daemon *Daemon) Reload(config *Config) error {
daemon.configStore.reloadLock.Lock()
defer daemon.configStore.reloadLock.Unlock()
daemon.configStore.Labels = config.Labels
return daemon.reloadClusterDiscovery(config)
daemon.configStore.reloadLock.Unlock()
return nil
}
func (daemon *Daemon) reloadClusterDiscovery(config *Config) error {

View File

@@ -61,15 +61,12 @@ func TestGetContainer(t *testing.T) {
},
}
store := &contStore{
s: map[string]*container.Container{
c1.ID: c1,
c2.ID: c2,
c3.ID: c3,
c4.ID: c4,
c5.ID: c5,
},
}
store := container.NewMemoryStore()
store.Add(c1.ID, c1)
store.Add(c2.ID, c2)
store.Add(c3.ID, c3)
store.Add(c4.ID, c4)
store.Add(c5.ID, c5)
index := truncindex.NewTruncIndex([]string{})
index.Add(c1.ID)
@@ -440,7 +437,7 @@ func TestDaemonDiscoveryReload(t *testing.T) {
&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
}
if err := daemon.Reload(newConfig); err != nil {
if err := daemon.reloadClusterDiscovery(newConfig); err != nil {
t.Fatal(err)
}
ch, errCh = daemon.discoveryWatcher.Watch(stopCh)
@@ -472,7 +469,7 @@ func TestDaemonDiscoveryReloadFromEmptyDiscovery(t *testing.T) {
&discovery.Entry{Host: "127.0.0.1", Port: "5555"},
}
if err := daemon.Reload(newConfig); err != nil {
if err := daemon.reloadClusterDiscovery(newConfig); err != nil {
t.Fatal(err)
}
stopCh := make(chan struct{})

View File

@@ -18,6 +18,7 @@ import (
"github.com/docker/docker/image"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/idtools"
"github.com/docker/docker/pkg/parsers"
"github.com/docker/docker/pkg/parsers/kernel"
"github.com/docker/docker/pkg/sysinfo"
"github.com/docker/docker/reference"
@@ -361,6 +362,24 @@ func verifyContainerResources(resources *containertypes.Resources) ([]string, er
return warnings, nil
}
func usingSystemd(config *Config) bool {
for _, option := range config.ExecOptions {
key, val, err := parsers.ParseKeyValueOpt(option)
if err != nil || !strings.EqualFold(key, "native.cgroupdriver") {
continue
}
if val == "systemd" {
return true
}
}
return false
}
func (daemon *Daemon) usingSystemd() bool {
return usingSystemd(daemon.configStore)
}
// verifyPlatformContainerSettings performs platform-specific validation of the
// hostconfig and config structures.
func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.HostConfig, config *containertypes.Config) ([]string, error) {
@@ -407,20 +426,31 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
return warnings, fmt.Errorf("Cannot use the --read-only option when user namespaces are enabled.")
}
}
if hostConfig.CgroupParent != "" && daemon.usingSystemd() {
// CgroupParent for systemd cgroup should be named as "xxx.slice"
if len(hostConfig.CgroupParent) <= 6 || !strings.HasSuffix(hostConfig.CgroupParent, ".slice") {
return warnings, fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
}
}
return warnings, nil
}
// checkConfigOptions checks for mutually incompatible config options
func checkConfigOptions(config *Config) error {
// verifyDaemonSettings performs validation of daemon config struct
func verifyDaemonSettings(config *Config) error {
// Check for mutually incompatible config options
if config.Bridge.Iface != "" && config.Bridge.IP != "" {
if config.bridgeConfig.Iface != "" && config.bridgeConfig.IP != "" {
return fmt.Errorf("You specified -b & --bip, mutually exclusive options. Please specify only one.")
}
if !config.Bridge.EnableIPTables && !config.Bridge.InterContainerCommunication {
if !config.bridgeConfig.EnableIPTables && !config.bridgeConfig.InterContainerCommunication {
return fmt.Errorf("You specified --iptables=false with --icc=false. ICC=false uses iptables to function. Please set --icc or --iptables to true.")
}
if !config.Bridge.EnableIPTables && config.Bridge.EnableIPMasq {
config.Bridge.EnableIPMasq = false
if !config.bridgeConfig.EnableIPTables && config.bridgeConfig.EnableIPMasq {
config.bridgeConfig.EnableIPMasq = false
}
if config.CgroupParent != "" && usingSystemd(config) {
if len(config.CgroupParent) <= 6 || !strings.HasSuffix(config.CgroupParent, ".slice") {
return fmt.Errorf("cgroup-parent for systemd cgroup should be a valid slice named as \"xxx.slice\"")
}
}
return nil
}
@@ -452,7 +482,7 @@ func configureKernelSecuritySupport(config *Config, driverName string) error {
}
func isBridgeNetworkDisabled(config *Config) bool {
return config.Bridge.Iface == disableNetworkBridge
return config.bridgeConfig.Iface == disableNetworkBridge
}
func (daemon *Daemon) networkOptions(dconfig *Config) ([]nwconfig.Option, error) {
@@ -526,9 +556,9 @@ func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkC
func driverOptions(config *Config) []nwconfig.Option {
bridgeConfig := options.Generic{
"EnableIPForwarding": config.Bridge.EnableIPForward,
"EnableIPTables": config.Bridge.EnableIPTables,
"EnableUserlandProxy": config.Bridge.EnableUserlandProxy}
"EnableIPForwarding": config.bridgeConfig.EnableIPForward,
"EnableIPTables": config.bridgeConfig.EnableIPTables,
"EnableUserlandProxy": config.bridgeConfig.EnableUserlandProxy}
bridgeOption := options.Generic{netlabel.GenericData: bridgeConfig}
dOptions := []nwconfig.Option{}
@@ -544,20 +574,20 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
}
bridgeName := bridge.DefaultBridgeName
if config.Bridge.Iface != "" {
bridgeName = config.Bridge.Iface
if config.bridgeConfig.Iface != "" {
bridgeName = config.bridgeConfig.Iface
}
netOption := map[string]string{
bridge.BridgeName: bridgeName,
bridge.DefaultBridge: strconv.FormatBool(true),
netlabel.DriverMTU: strconv.Itoa(config.Mtu),
bridge.EnableIPMasquerade: strconv.FormatBool(config.Bridge.EnableIPMasq),
bridge.EnableICC: strconv.FormatBool(config.Bridge.InterContainerCommunication),
bridge.EnableIPMasquerade: strconv.FormatBool(config.bridgeConfig.EnableIPMasq),
bridge.EnableICC: strconv.FormatBool(config.bridgeConfig.InterContainerCommunication),
}
// --ip processing
if config.Bridge.DefaultIP != nil {
netOption[bridge.DefaultBindingIP] = config.Bridge.DefaultIP.String()
if config.bridgeConfig.DefaultIP != nil {
netOption[bridge.DefaultBindingIP] = config.bridgeConfig.DefaultIP.String()
}
var (
@@ -576,9 +606,9 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
}
}
if config.Bridge.IP != "" {
ipamV4Conf.PreferredPool = config.Bridge.IP
ip, _, err := net.ParseCIDR(config.Bridge.IP)
if config.bridgeConfig.IP != "" {
ipamV4Conf.PreferredPool = config.bridgeConfig.IP
ip, _, err := net.ParseCIDR(config.bridgeConfig.IP)
if err != nil {
return err
}
@@ -587,8 +617,8 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
logrus.Infof("Default bridge (%s) is assigned with an IP address %s. Daemon option --bip can be used to set a preferred IP address", bridgeName, ipamV4Conf.PreferredPool)
}
if config.Bridge.FixedCIDR != "" {
_, fCIDR, err := net.ParseCIDR(config.Bridge.FixedCIDR)
if config.bridgeConfig.FixedCIDR != "" {
_, fCIDR, err := net.ParseCIDR(config.bridgeConfig.FixedCIDR)
if err != nil {
return err
}
@@ -596,13 +626,13 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
ipamV4Conf.SubPool = fCIDR.String()
}
if config.Bridge.DefaultGatewayIPv4 != nil {
ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.Bridge.DefaultGatewayIPv4.String()
if config.bridgeConfig.DefaultGatewayIPv4 != nil {
ipamV4Conf.AuxAddresses["DefaultGatewayIPv4"] = config.bridgeConfig.DefaultGatewayIPv4.String()
}
var deferIPv6Alloc bool
if config.Bridge.FixedCIDRv6 != "" {
_, fCIDRv6, err := net.ParseCIDR(config.Bridge.FixedCIDRv6)
if config.bridgeConfig.FixedCIDRv6 != "" {
_, fCIDRv6, err := net.ParseCIDR(config.bridgeConfig.FixedCIDRv6)
if err != nil {
return err
}
@@ -632,11 +662,11 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
}
}
if config.Bridge.DefaultGatewayIPv6 != nil {
if config.bridgeConfig.DefaultGatewayIPv6 != nil {
if ipamV6Conf == nil {
ipamV6Conf = &libnetwork.IpamConf{AuxAddresses: make(map[string]string)}
}
ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.Bridge.DefaultGatewayIPv6.String()
ipamV6Conf.AuxAddresses["DefaultGatewayIPv6"] = config.bridgeConfig.DefaultGatewayIPv6.String()
}
v4Conf := []*libnetwork.IpamConf{ipamV4Conf}
@@ -648,7 +678,7 @@ func initBridgeDriver(controller libnetwork.NetworkController, config *Config) e
_, err = controller.NewNetwork("bridge", "bridge",
libnetwork.NetworkOptionGeneric(options.Generic{
netlabel.GenericData: netOption,
netlabel.EnableIPv6: config.Bridge.EnableIPv6,
netlabel.EnableIPv6: config.bridgeConfig.EnableIPv6,
}),
libnetwork.NetworkOptionIpam("default", "", v4Conf, v6Conf, nil),
libnetwork.NetworkOptionDeferIPv6Alloc(deferIPv6Alloc))

View File

@@ -88,8 +88,8 @@ func verifyPlatformContainerSettings(daemon *Daemon, hostConfig *containertypes.
return nil, nil
}
// checkConfigOptions checks for mutually incompatible config options
func checkConfigOptions(config *Config) error {
// verifyDaemonSettings performs validation of daemon config struct
func verifyDaemonSettings(config *Config) error {
return nil
}
@@ -121,8 +121,8 @@ func isBridgeNetworkDisabled(config *Config) bool {
func (daemon *Daemon) initNetworkController(config *Config) (libnetwork.NetworkController, error) {
// Set the name of the virtual switch if not specified by -b on daemon start
if config.Bridge.VirtualSwitchName == "" {
config.Bridge.VirtualSwitchName = defaultVirtualSwitch
if config.bridgeConfig.VirtualSwitchName == "" {
config.bridgeConfig.VirtualSwitchName = defaultVirtualSwitch
}
return nil, nil
}

View File

@@ -43,15 +43,14 @@ func (daemon *Daemon) ContainerRm(name string, config *types.ContainerRmConfig)
return daemon.rmLink(container, name)
}
if err := daemon.cleanupContainer(container, config.ForceRemove); err != nil {
return err
err = daemon.cleanupContainer(container, config.ForceRemove)
if err == nil || config.ForceRemove {
if e := daemon.removeMountPoints(container, config.RemoveVolume); e != nil {
logrus.Error(e)
}
}
if err := daemon.removeMountPoints(container, config.RemoveVolume); err != nil {
logrus.Error(err)
}
return nil
return err
}
func (daemon *Daemon) rmLink(container *container.Container, name string) error {

View File

@@ -20,7 +20,7 @@ func TestContainerDoubleDelete(t *testing.T) {
repository: tmp,
root: tmp,
}
daemon.containers = &contStore{s: make(map[string]*container.Container)}
daemon.containers = container.NewMemoryStore()
container := &container.Container{
CommonContainer: container.CommonContainer{

View File

@@ -52,6 +52,9 @@ func (d *Daemon) getExecConfig(name string) (*exec.Config, error) {
if container.IsPaused() {
return nil, derr.ErrorCodeExecPaused.WithArgs(container.ID)
}
if container.IsRestarting() {
return nil, derr.ErrorCodeExecRestarting.WithArgs(container.ID)
}
return ec, nil
}
}
@@ -76,6 +79,9 @@ func (d *Daemon) getActiveContainer(name string) (*container.Container, error) {
if container.IsPaused() {
return nil, derr.ErrorCodeExecPaused.WithArgs(name)
}
if container.IsRestarting() {
return nil, derr.ErrorCodeExecRestarting.WithArgs(name)
}
return container, nil
}
@@ -135,6 +141,11 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io.
}
ec.Lock()
if ec.ExitCode != nil {
ec.Unlock()
return derr.ErrorCodeExecExited.WithArgs(ec.ID)
}
if ec.Running {
ec.Unlock()
return derr.ErrorCodeExecRunning.WithArgs(ec.ID)
@@ -146,7 +157,7 @@ func (d *Daemon) ContainerExecStart(name string, stdin io.ReadCloser, stdout io.
logrus.Debugf("starting exec command %s in container %s", ec.ID, c.ID)
d.LogContainerEvent(c, "exec_start: "+ec.ProcessConfig.Entrypoint+" "+strings.Join(ec.ProcessConfig.Arguments, " "))
if ec.OpenStdin {
if ec.OpenStdin && stdin != nil {
r, w := io.Pipe()
go func() {
defer w.Close()
@@ -214,7 +225,7 @@ func (d *Daemon) Exec(c *container.Container, execConfig *exec.Config, pipes *ex
exitStatus = 128
}
execConfig.ExitCode = exitStatus
execConfig.ExitCode = &exitStatus
execConfig.Running = false
return exitStatus, err

View File

@@ -18,7 +18,7 @@ type Config struct {
*runconfig.StreamConfig
ID string
Running bool
ExitCode int
ExitCode *int
ProcessConfig *execdriver.ProcessConfig
OpenStdin bool
OpenStderr bool
@@ -53,7 +53,13 @@ func NewStore() *Store {
// Commands returns the exec configurations in the store.
func (e *Store) Commands() map[string]*Config {
return e.commands
e.RLock()
commands := make(map[string]*Config, len(e.commands))
for id, config := range e.commands {
commands[id] = config
}
e.RUnlock()
return commands
}
// Add adds a new exec configuration to the store.

View File

@@ -140,7 +140,7 @@ func InitContainer(c *Command) *configs.Config {
container.Hostname = getEnv("HOSTNAME", c.ProcessConfig.Env)
container.Cgroups.Name = c.ID
container.Cgroups.Resources.AllowedDevices = c.AllowedDevices
container.Devices = c.AutoCreatedDevices
container.Devices = filterDevices(c.AutoCreatedDevices, (c.RemappedRoot.UID != 0))
container.Rootfs = c.Rootfs
container.Readonlyfs = c.ReadonlyRootfs
// This can be overridden later by driver during mount setup based
@@ -154,6 +154,24 @@ func InitContainer(c *Command) *configs.Config {
return container
}
func filterDevices(devices []*configs.Device, userNamespacesEnabled bool) []*configs.Device {
if !userNamespacesEnabled {
return devices
}
filtered := []*configs.Device{}
// if we have user namespaces enabled, these devices will not be created
// because of the mknod limitation in the kernel for an unprivileged process.
// Rather, they will be bind-mounted, which will only work if they exist;
// check for existence and remove non-existent entries from the list
for _, device := range devices {
if _, err := os.Stat(device.Path); err == nil {
filtered = append(filtered, device)
}
}
return filtered
}
func getEnv(key string, env []string) string {
for _, pair := range env {
parts := strings.SplitN(pair, "=", 2)

View File

@@ -103,7 +103,7 @@ func (d *Driver) createContainer(c *execdriver.Command, hooks execdriver.Hooks)
if container.Readonlyfs {
for i := range container.Mounts {
switch container.Mounts[i].Destination {
case "/proc", "/dev", "/dev/pts":
case "/proc", "/dev", "/dev/pts", "/dev/mqueue":
continue
}
container.Mounts[i].Flags |= syscall.MS_RDONLY
@@ -436,7 +436,6 @@ func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) e
flags = syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
err error
)
fulldest := filepath.Join(c.Rootfs, m.Destination)
if m.Data != "" {
flags, data, err = mount.ParseTmpfsOptions(m.Data)
if err != nil {
@@ -449,8 +448,6 @@ func (d *Driver) setupMounts(container *configs.Config, c *execdriver.Command) e
Data: data,
Device: "tmpfs",
Flags: flags,
PremountCmds: genTmpfsPremountCmd(c.TmpDir, fulldest, m.Destination),
PostmountCmds: genTmpfsPostmountCmd(c.TmpDir, fulldest, m.Destination),
PropagationFlags: []int{mountPropagationMap[volume.DefaultPropagationMode]},
})
continue

View File

@@ -17,7 +17,7 @@ func arches() []string {
var a = native.String()
switch a {
case "amd64":
return []string{"amd64", "x86"}
return []string{"amd64", "x86", "x32"}
case "arm64":
return []string{"arm64", "arm"}
case "mips64":
@@ -624,6 +624,11 @@ var defaultSeccompProfile = &configs.Seccomp{
Action: configs.Allow,
Args: []*configs.Arg{},
},
{
Name: "ipc",
Action: configs.Allow,
Args: []*configs.Arg{},
},
{
Name: "kill",
Action: configs.Allow,
@@ -864,6 +869,39 @@ var defaultSeccompProfile = &configs.Seccomp{
Action: configs.Allow,
Args: []*configs.Arg{},
},
{
Name: "personality",
Action: configs.Allow,
Args: []*configs.Arg{
{
Index: 0,
Value: 0x0,
Op: configs.EqualTo,
},
},
},
{
Name: "personality",
Action: configs.Allow,
Args: []*configs.Arg{
{
Index: 0,
Value: 0x0008,
Op: configs.EqualTo,
},
},
},
{
Name: "personality",
Action: configs.Allow,
Args: []*configs.Arg{
{
Index: 0,
Value: 0xffffffff,
Op: configs.EqualTo,
},
},
},
{
Name: "pipe",
Action: configs.Allow,
@@ -944,6 +982,11 @@ var defaultSeccompProfile = &configs.Seccomp{
Action: configs.Allow,
Args: []*configs.Arg{},
},
{
Name: "recv",
Action: configs.Allow,
Args: []*configs.Arg{},
},
{
Name: "recvfrom",
Action: configs.Allow,
@@ -1119,6 +1162,11 @@ var defaultSeccompProfile = &configs.Seccomp{
Action: configs.Allow,
Args: []*configs.Arg{},
},
{
Name: "send",
Action: configs.Allow,
Args: []*configs.Arg{},
},
{
Name: "sendfile",
Action: configs.Allow,

View File

@@ -64,6 +64,12 @@ func New() *configs.Config {
Flags: syscall.MS_NOSUID | syscall.MS_NOEXEC,
Data: "newinstance,ptmxmode=0666,mode=0620,gid=5",
},
{
Source: "mqueue",
Destination: "/dev/mqueue",
Device: "mqueue",
Flags: defaultMountFlags,
},
{
Source: "sysfs",
Destination: "/sys",

View File

@@ -1,56 +0,0 @@
package native
import (
"fmt"
"os"
"os/exec"
"strings"
"github.com/Sirupsen/logrus"
"github.com/opencontainers/runc/libcontainer/configs"
)
func genTmpfsPremountCmd(tmpDir string, fullDest string, dest string) []configs.Command {
var premount []configs.Command
tarPath, err := exec.LookPath("tar")
if err != nil {
logrus.Warn("tar command is not available for tmpfs mount: %s", err)
return premount
}
if _, err = exec.LookPath("rm"); err != nil {
logrus.Warn("rm command is not available for tmpfs mount: %s", err)
return premount
}
tarFile := fmt.Sprintf("%s/%s.tar", tmpDir, strings.Replace(dest, "/", "_", -1))
if _, err := os.Stat(fullDest); err == nil {
premount = append(premount, configs.Command{
Path: tarPath,
Args: []string{"-cf", tarFile, "-C", fullDest, "."},
})
}
return premount
}
func genTmpfsPostmountCmd(tmpDir string, fullDest string, dest string) []configs.Command {
var postmount []configs.Command
tarPath, err := exec.LookPath("tar")
if err != nil {
return postmount
}
rmPath, err := exec.LookPath("rm")
if err != nil {
return postmount
}
if _, err := os.Stat(fullDest); os.IsNotExist(err) {
return postmount
}
tarFile := fmt.Sprintf("%s/%s.tar", tmpDir, strings.Replace(dest, "/", "_", -1))
postmount = append(postmount, configs.Command{
Path: tarPath,
Args: []string{"-xf", tarFile, "-C", fullDest, "."},
})
return append(postmount, configs.Command{
Path: rmPath,
Args: []string{"-f", tarFile},
})
}

View File

@@ -374,20 +374,10 @@ func (a *Driver) DiffPath(id string) (string, func() error, error) {
}
func (a *Driver) applyDiff(id string, diff archive.Reader) error {
dir := path.Join(a.rootPath(), "diff", id)
if err := chrootarchive.UntarUncompressed(diff, dir, &archive.TarOptions{
return chrootarchive.UntarUncompressed(diff, path.Join(a.rootPath(), "diff", id), &archive.TarOptions{
UIDMaps: a.uidMaps,
GIDMaps: a.gidMaps,
}); err != nil {
return err
}
// show invalid whiteouts warning.
files, err := ioutil.ReadDir(path.Join(dir, archive.WhiteoutLinkDir))
if err == nil && len(files) > 0 {
logrus.Warnf("Archive contains aufs hardlink references that are not supported.")
}
return nil
})
}
// DiffSize calculates the changes between the specified id
@@ -517,7 +507,7 @@ func (a *Driver) aufsMount(ro []string, rw, target, mountLabel string) (err erro
}
if firstMount {
opts := "dio,noplink,xino=/dev/shm/aufs.xino"
opts := "dio,xino=/dev/shm/aufs.xino"
if useDirperm() {
opts += ",dirperm1"
}

View File

@@ -638,88 +638,6 @@ func TestApplyDiff(t *testing.T) {
}
}
func TestHardlinks(t *testing.T) {
// Copy 2 layers that have linked files to new layers and check if hardlink are preserved
d := newDriver(t)
defer os.RemoveAll(tmp)
defer d.Cleanup()
origFile := "test_file"
linkedFile := "linked_file"
if err := d.Create("source-1", "", ""); err != nil {
t.Fatal(err)
}
mountPath, err := d.Get("source-1", "")
if err != nil {
t.Fatal(err)
}
f, err := os.Create(path.Join(mountPath, origFile))
if err != nil {
t.Fatal(err)
}
f.Close()
layerTar1, err := d.Diff("source-1", "")
if err != nil {
t.Fatal(err)
}
if err := d.Create("source-2", "source-1", ""); err != nil {
t.Fatal(err)
}
mountPath, err = d.Get("source-2", "")
if err != nil {
t.Fatal(err)
}
if err := os.Link(path.Join(mountPath, origFile), path.Join(mountPath, linkedFile)); err != nil {
t.Fatal(err)
}
layerTar2, err := d.Diff("source-2", "source-1")
if err != nil {
t.Fatal(err)
}
if err := d.Create("target-1", "", ""); err != nil {
t.Fatal(err)
}
if _, err := d.ApplyDiff("target-1", "", layerTar1); err != nil {
t.Fatal(err)
}
if err := d.Create("target-2", "target-1", ""); err != nil {
t.Fatal(err)
}
if _, err := d.ApplyDiff("target-2", "target-1", layerTar2); err != nil {
t.Fatal(err)
}
mountPath, err = d.Get("target-2", "")
if err != nil {
t.Fatal(err)
}
fi1, err := os.Lstat(path.Join(mountPath, origFile))
if err != nil {
t.Fatal(err)
}
fi2, err := os.Lstat(path.Join(mountPath, linkedFile))
if err != nil {
t.Fatal(err)
}
if !os.SameFile(fi1, fi2) {
t.Fatal("Target files are not linked")
}
}
func hash(c string) string {
h := sha256.New()
fmt.Fprint(h, c)

View File

@@ -18,6 +18,8 @@ const (
FsMagicExtfs = FsMagic(0x0000EF53)
// FsMagicF2fs filesystem id for F2fs
FsMagicF2fs = FsMagic(0xF2F52010)
// FsMagicGPFS filesystem id for GPFS
FsMagicGPFS = FsMagic(0x47504653)
// FsMagicJffs2Fs filesystem if for Jffs2Fs
FsMagicJffs2Fs = FsMagic(0x000072b6)
// FsMagicJfs filesystem id for Jfs
@@ -60,6 +62,7 @@ var (
FsMagicCramfs: "cramfs",
FsMagicExtfs: "extfs",
FsMagicF2fs: "f2fs",
FsMagicGPFS: "gpfs",
FsMagicJffs2Fs: "jffs2",
FsMagicJfs: "jfs",
FsMagicNfsFs: "nfs",

View File

@@ -308,10 +308,14 @@ func (d *Driver) Get(id, mountLabel string) (string, error) {
return "", err
}
err = mount.Mount(filesystem, mountpoint, "zfs", options)
if err != nil {
if err := mount.Mount(filesystem, mountpoint, "zfs", options); err != nil {
return "", fmt.Errorf("error creating zfs mount of %s to %s: %v", filesystem, mountpoint, err)
}
// this could be our first mount after creation of the filesystem, and the root dir may still have root
// permissions instead of the remapped root uid:gid (if user namespaces are enabled):
if err := os.Chown(mountpoint, rootUID, rootGID); err != nil {
return "", fmt.Errorf("error modifying zfs mountpoint (%s) directory ownership: %v", mountpoint, err)
}
return mountpoint, nil
}

View File

@@ -179,13 +179,9 @@ func isImageIDPrefix(imageID, possiblePrefix string) bool {
// getContainerUsingImage returns a container that was created using the given
// imageID. Returns nil if there is no such container.
func (daemon *Daemon) getContainerUsingImage(imageID image.ID) *container.Container {
for _, container := range daemon.List() {
if container.ImageID == imageID {
return container
}
}
return nil
return daemon.containers.First(func(c *container.Container) bool {
return c.ImageID == imageID
})
}
// removeImageRef attempts to parse and remove the given image reference from
@@ -328,19 +324,15 @@ func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, mask conflictType
if mask&conflictRunningContainer != 0 {
// Check if any running container is using the image.
for _, container := range daemon.List() {
if !container.IsRunning() {
// Skip this until we check for soft conflicts later.
continue
}
if container.ImageID == imgID {
return &imageDeleteConflict{
imgID: imgID,
hard: true,
used: true,
message: fmt.Sprintf("image is being used by running container %s", stringid.TruncateID(container.ID)),
}
running := func(c *container.Container) bool {
return c.IsRunning() && c.ImageID == imgID
}
if container := daemon.containers.First(running); container != nil {
return &imageDeleteConflict{
imgID: imgID,
hard: true,
used: true,
message: fmt.Sprintf("image is being used by running container %s", stringid.TruncateID(container.ID)),
}
}
}
@@ -355,18 +347,14 @@ func (daemon *Daemon) checkImageDeleteConflict(imgID image.ID, mask conflictType
if mask&conflictStoppedContainer != 0 {
// Check if any stopped containers reference this image.
for _, container := range daemon.List() {
if container.IsRunning() {
// Skip this as it was checked above in hard conflict conditions.
continue
}
if container.ImageID == imgID {
return &imageDeleteConflict{
imgID: imgID,
used: true,
message: fmt.Sprintf("image is being used by stopped container %s", stringid.TruncateID(container.ID)),
}
stopped := func(c *container.Container) bool {
return !c.IsRunning() && c.ImageID == imgID
}
if container := daemon.containers.First(stopped); container != nil {
return &imageDeleteConflict{
imgID: imgID,
used: true,
message: fmt.Sprintf("image is being used by stopped container %s", stringid.TruncateID(container.ID)),
}
}
}

View File

@@ -11,6 +11,7 @@ import (
"github.com/docker/docker/dockerversion"
"github.com/docker/docker/image"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/archive"
"github.com/docker/docker/pkg/httputils"
"github.com/docker/docker/pkg/progress"
"github.com/docker/docker/pkg/streamformatter"
@@ -24,13 +25,13 @@ import (
// the repo and tag arguments, respectively.
func (daemon *Daemon) ImportImage(src string, newRef reference.Named, msg string, inConfig io.ReadCloser, outStream io.Writer, config *container.Config) error {
var (
sf = streamformatter.NewJSONStreamFormatter()
archive io.ReadCloser
resp *http.Response
sf = streamformatter.NewJSONStreamFormatter()
rc io.ReadCloser
resp *http.Response
)
if src == "-" {
archive = inConfig
rc = inConfig
} else {
inConfig.Close()
u, err := url.Parse(src)
@@ -48,15 +49,20 @@ func (daemon *Daemon) ImportImage(src string, newRef reference.Named, msg string
return err
}
progressOutput := sf.NewProgressOutput(outStream, true)
archive = progress.NewProgressReader(resp.Body, progressOutput, resp.ContentLength, "", "Importing")
rc = progress.NewProgressReader(resp.Body, progressOutput, resp.ContentLength, "", "Importing")
}
defer archive.Close()
defer rc.Close()
if len(msg) == 0 {
msg = "Imported from " + src
}
inflatedLayerData, err := archive.DecompressStream(rc)
if err != nil {
return err
}
// TODO: support windows baselayer?
l, err := daemon.layerStore.Register(archive, "")
l, err := daemon.layerStore.Register(inflatedLayerData, "")
if err != nil {
return err
}

View File

@@ -4,9 +4,11 @@ import (
"os"
"runtime"
"strings"
"sync/atomic"
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/container"
"github.com/docker/docker/dockerversion"
"github.com/docker/docker/pkg/fileutils"
"github.com/docker/docker/pkg/parsers/kernel"
@@ -54,24 +56,24 @@ func (daemon *Daemon) SystemInfo() (*types.Info, error) {
initPath := utils.DockerInitPath("")
sysInfo := sysinfo.New(true)
var cRunning, cPaused, cStopped int
for _, c := range daemon.List() {
var cRunning, cPaused, cStopped int32
daemon.containers.ApplyAll(func(c *container.Container) {
switch c.StateString() {
case "paused":
cPaused++
atomic.AddInt32(&cPaused, 1)
case "running":
cRunning++
atomic.AddInt32(&cRunning, 1)
default:
cStopped++
atomic.AddInt32(&cStopped, 1)
}
}
})
v := &types.Info{
ID: daemon.ID,
Containers: len(daemon.List()),
ContainersRunning: cRunning,
ContainersPaused: cPaused,
ContainersStopped: cStopped,
Containers: int(cRunning + cPaused + cStopped),
ContainersRunning: int(cRunning),
ContainersPaused: int(cPaused),
ContainersStopped: int(cStopped),
Images: len(daemon.imageStore.Map()),
Driver: daemon.GraphDriverName(),
DriverStatus: daemon.layerStore.DriverStatus(),

View File

@@ -39,12 +39,9 @@ func TestMigrateLegacySqliteLinks(t *testing.T) {
},
}
store := &contStore{
s: map[string]*container.Container{
c1.ID: c1,
c2.ID: c2,
},
}
store := container.NewMemoryStore()
store.Add(c1.ID, c1)
store.Add(c2.ID, c2)
d := &Daemon{root: tmpDir, containers: store}
db, err := graphdb.NewSqliteConn(filepath.Join(d.root, "linkgraph.db"))

View File

@@ -15,6 +15,10 @@ import (
"github.com/docker/go-connections/nat"
)
var acceptedVolumeFilterTags = map[string]bool{
"dangling": true,
}
// iterationAction represents possible outcomes happening during the container iteration.
type iterationAction int
@@ -70,6 +74,13 @@ type listContext struct {
filters filters.Args
// exitAllowed is a list of exit codes allowed to filter with
exitAllowed []int
// FIXME Remove this for 1.12 as --since and --before are deprecated
// beforeContainer is a filter to ignore containers that appear before the one given
beforeContainer *container.Container
// sinceContainer is a filter to stop the filtering when the iterator arrive to the given container
sinceContainer *container.Container
// beforeFilter is a filter to ignore containers that appear before the one given
// this is used for --filter=before= and --before=, the latter is deprecated.
beforeFilter *container.Container
@@ -161,6 +172,9 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
}
var beforeContFilter, sinceContFilter *container.Container
// FIXME remove this for 1.12 as --since and --before are deprecated
var beforeContainer, sinceContainer *container.Container
err = psFilters.WalkValues("before", func(value string) error {
beforeContFilter, err = daemon.GetContainer(value)
return err
@@ -197,15 +211,17 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
})
}
if config.Before != "" && beforeContFilter == nil {
beforeContFilter, err = daemon.GetContainer(config.Before)
// FIXME remove this for 1.12 as --since and --before are deprecated
if config.Before != "" {
beforeContainer, err = daemon.GetContainer(config.Before)
if err != nil {
return nil, err
}
}
if config.Since != "" && sinceContFilter == nil {
sinceContFilter, err = daemon.GetContainer(config.Since)
// FIXME remove this for 1.12 as --since and --before are deprecated
if config.Since != "" {
sinceContainer, err = daemon.GetContainer(config.Since)
if err != nil {
return nil, err
}
@@ -216,6 +232,8 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
ancestorFilter: ancestorFilter,
images: imagesFilter,
exitAllowed: filtExited,
beforeContainer: beforeContainer,
sinceContainer: sinceContainer,
beforeFilter: beforeContFilter,
sinceFilter: sinceContFilter,
ContainersConfig: config,
@@ -227,7 +245,8 @@ func (daemon *Daemon) foldFilter(config *ContainersConfig) (*listContext, error)
// It also decides if the iteration should be stopped or not.
func includeContainerInList(container *container.Container, ctx *listContext) iterationAction {
// Do not include container if it's stopped and we're not filters
if !container.Running && !ctx.All && ctx.Limit <= 0 && ctx.beforeFilter == nil && ctx.sinceFilter == nil {
// FIXME remove the ctx.beforContainer part of the condition for 1.12 as --since and --before are deprecated
if !container.Running && !ctx.All && ctx.Limit <= 0 && ctx.beforeContainer == nil && ctx.sinceContainer == nil {
return excludeContainer
}
@@ -251,6 +270,21 @@ func includeContainerInList(container *container.Container, ctx *listContext) it
return excludeContainer
}
// FIXME remove this for 1.12 as --since and --before are deprecated
if ctx.beforeContainer != nil {
if container.ID == ctx.beforeContainer.ID {
ctx.beforeContainer = nil
}
return excludeContainer
}
// FIXME remove this for 1.12 as --since and --before are deprecated
if ctx.sinceContainer != nil {
if container.ID == ctx.sinceContainer.ID {
return stopIteration
}
}
// Do not include container if it's in the list before the filter container.
// Set the filter container to nil to include the rest of containers after this one.
if ctx.beforeFilter != nil {
@@ -410,21 +444,33 @@ func (daemon *Daemon) transformContainer(container *container.Container, ctx *li
// Volumes lists known volumes, using the filter to restrict the range
// of volumes returned.
func (daemon *Daemon) Volumes(filter string) ([]*types.Volume, []string, error) {
var volumesOut []*types.Volume
var (
volumesOut []*types.Volume
danglingOnly = false
)
volFilters, err := filters.FromParam(filter)
if err != nil {
return nil, nil, err
}
filterUsed := volFilters.Include("dangling") &&
(volFilters.ExactMatch("dangling", "true") || volFilters.ExactMatch("dangling", "1"))
if err := volFilters.Validate(acceptedVolumeFilterTags); err != nil {
return nil, nil, err
}
if volFilters.Include("dangling") {
if volFilters.ExactMatch("dangling", "true") || volFilters.ExactMatch("dangling", "1") {
danglingOnly = true
} else if !volFilters.ExactMatch("dangling", "false") && !volFilters.ExactMatch("dangling", "0") {
return nil, nil, fmt.Errorf("Invalid filter 'dangling=%s'", volFilters.Get("dangling"))
}
}
volumes, warnings, err := daemon.volumes.List()
if err != nil {
return nil, nil, err
}
if filterUsed {
volumes = daemon.volumes.FilterByUsed(volumes)
if volFilters.Include("dangling") {
volumes = daemon.volumes.FilterByUsed(volumes, !danglingOnly)
}
for _, v := range volumes {
volumesOut = append(volumesOut, volumeToAPIType(v))

View File

@@ -20,14 +20,16 @@ type Copier struct {
srcs map[string]io.Reader
dst Logger
copyJobs sync.WaitGroup
closed chan struct{}
}
// NewCopier creates a new Copier
func NewCopier(cid string, srcs map[string]io.Reader, dst Logger) *Copier {
return &Copier{
cid: cid,
srcs: srcs,
dst: dst,
cid: cid,
srcs: srcs,
dst: dst,
closed: make(chan struct{}),
}
}
@@ -44,24 +46,28 @@ func (c *Copier) copySrc(name string, src io.Reader) {
reader := bufio.NewReader(src)
for {
line, err := reader.ReadBytes('\n')
line = bytes.TrimSuffix(line, []byte{'\n'})
// ReadBytes can return full or partial output even when it failed.
// e.g. it can return a full entry and EOF.
if err == nil || len(line) > 0 {
if logErr := c.dst.Log(&Message{ContainerID: c.cid, Line: line, Source: name, Timestamp: time.Now().UTC()}); logErr != nil {
logrus.Errorf("Failed to log msg %q for logger %s: %s", line, c.dst.Name(), logErr)
}
}
if err != nil {
if err != io.EOF {
logrus.Errorf("Error scanning log stream: %s", err)
}
select {
case <-c.closed:
return
}
default:
line, err := reader.ReadBytes('\n')
line = bytes.TrimSuffix(line, []byte{'\n'})
// ReadBytes can return full or partial output even when it failed.
// e.g. it can return a full entry and EOF.
if err == nil || len(line) > 0 {
if logErr := c.dst.Log(&Message{ContainerID: c.cid, Line: line, Source: name, Timestamp: time.Now().UTC()}); logErr != nil {
logrus.Errorf("Failed to log msg %q for logger %s: %s", line, c.dst.Name(), logErr)
}
}
if err != nil {
if err != io.EOF {
logrus.Errorf("Error scanning log stream: %s", err)
}
return
}
}
}
}
@@ -69,3 +75,12 @@ func (c *Copier) copySrc(name string, src io.Reader) {
func (c *Copier) Wait() {
c.copyJobs.Wait()
}
// Close closes the copier
func (c *Copier) Close() {
select {
case <-c.closed:
default:
close(c.closed)
}
}

View File

@@ -10,9 +10,15 @@ import (
type TestLoggerJSON struct {
*json.Encoder
delay time.Duration
}
func (l *TestLoggerJSON) Log(m *Message) error { return l.Encode(m) }
func (l *TestLoggerJSON) Log(m *Message) error {
if l.delay > 0 {
time.Sleep(l.delay)
}
return l.Encode(m)
}
func (l *TestLoggerJSON) Close() error { return nil }
@@ -94,3 +100,33 @@ func TestCopier(t *testing.T) {
}
}
}
func TestCopierSlow(t *testing.T) {
stdoutLine := "Line that thinks that it is log line from docker stdout"
var stdout bytes.Buffer
for i := 0; i < 30; i++ {
if _, err := stdout.WriteString(stdoutLine + "\n"); err != nil {
t.Fatal(err)
}
}
var jsonBuf bytes.Buffer
//encoder := &encodeCloser{Encoder: json.NewEncoder(&jsonBuf)}
jsonLog := &TestLoggerJSON{Encoder: json.NewEncoder(&jsonBuf), delay: 100 * time.Millisecond}
cid := "a7317399f3f857173c6179d44823594f8294678dea9999662e5c625b5a1c7657"
c := NewCopier(cid, map[string]io.Reader{"stdout": &stdout}, jsonLog)
c.Run()
wait := make(chan struct{})
go func() {
c.Wait()
close(wait)
}()
<-time.After(150 * time.Millisecond)
c.Close()
select {
case <-time.After(200 * time.Millisecond):
t.Fatalf("failed to exit in time after the copier is closed")
case <-wait:
}
}

View File

@@ -25,6 +25,11 @@ func (daemon *Daemon) removeMountPoints(container *container.Container, rm bool)
}
daemon.volumes.Dereference(m.Volume, container.ID)
if rm {
// Do not remove named mountpoints
// these are mountpoints specified like `docker run -v <name>:/foo`
if m.Named {
continue
}
err := daemon.volumes.Remove(m.Volume)
// Ignore volume in use errors because having this
// volume being referenced by other container is

View File

@@ -90,6 +90,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
Driver: m.Driver,
Destination: m.Destination,
Propagation: m.Propagation,
Named: m.Named,
}
if len(cp.Source) == 0 {
@@ -126,7 +127,10 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
bind.Source = v.Path()
// bind.Name is an already existing volume, we need to use that here
bind.Driver = v.DriverName()
bind = setBindModeIfNull(bind)
bind.Named = true
if bind.Driver == "local" {
bind = setBindModeIfNull(bind)
}
}
if label.RelabelNeeded(bind.Mode) {
if err := label.Relabel(bind.Source, container.MountLabel, label.IsShared(bind.Mode)); err != nil {
@@ -159,7 +163,6 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
func (daemon *Daemon) lazyInitializeVolume(containerID string, m *volume.MountPoint) error {
if len(m.Driver) > 0 && m.Volume == nil {
v, err := daemon.volumes.GetWithRef(m.Name, m.Driver, containerID)
if err != nil {
return err
}

View File

@@ -3,7 +3,6 @@ package distribution
import (
"fmt"
"os"
"strings"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/api"
@@ -97,13 +96,12 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
}
var (
// use a slice to append the error strings and return a joined string to caller
errors []string
lastErr error
// discardNoSupportErrors is used to track whether an endpoint encountered an error of type registry.ErrNoSupport
// By default it is false, which means that if a ErrNoSupport error is encountered, it will be saved in errors.
// By default it is false, which means that if a ErrNoSupport error is encountered, it will be saved in lastErr.
// As soon as another kind of error is encountered, discardNoSupportErrors is set to true, avoiding the saving of
// any subsequent ErrNoSupport errors in errors.
// any subsequent ErrNoSupport errors in lastErr.
// It's needed for pull-by-digest on v1 endpoints: if there are only v1 endpoints configured, the error should be
// returned and displayed, but if there was a v2 endpoint which supports pull-by-digest, then the last relevant
// error is the ones from v2 endpoints not v1.
@@ -123,7 +121,7 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
puller, err := newPuller(endpoint, repoInfo, imagePullConfig)
if err != nil {
errors = append(errors, err.Error())
lastErr = err
continue
}
if err := puller.Pull(ctx, ref); err != nil {
@@ -144,34 +142,28 @@ func Pull(ctx context.Context, ref reference.Named, imagePullConfig *ImagePullCo
// Because we found an error that's not ErrNoSupport, discard all subsequent ErrNoSupport errors.
discardNoSupportErrors = true
// append subsequent errors
errors = append(errors, err.Error())
lastErr = err
} else if !discardNoSupportErrors {
// Save the ErrNoSupport error, because it's either the first error or all encountered errors
// were also ErrNoSupport errors.
// append subsequent errors
errors = append(errors, err.Error())
lastErr = err
}
continue
}
errors = append(errors, err.Error())
logrus.Debugf("Not continuing with error: %v", fmt.Errorf(strings.Join(errors, "\n")))
if len(errors) > 0 {
return fmt.Errorf(strings.Join(errors, "\n"))
}
logrus.Debugf("Not continuing with error: %v", err)
return err
}
imagePullConfig.ImageEventLogger(ref.String(), repoInfo.Name(), "pull")
return nil
}
if len(errors) == 0 {
return fmt.Errorf("no endpoints found for %s", ref.String())
if lastErr == nil {
lastErr = fmt.Errorf("no endpoints found for %s", ref.String())
}
if len(errors) > 0 {
return fmt.Errorf(strings.Join(errors, "\n"))
}
return nil
return lastErr
}
// writeStatus writes a status message to out. If layersDownloaded is true, the

View File

@@ -171,6 +171,10 @@ func (ld *v2LayerDescriptor) Download(ctx context.Context, progressOutput progre
_, err = io.Copy(tmpFile, io.TeeReader(reader, verifier))
if err != nil {
tmpFile.Close()
if err := os.Remove(tmpFile.Name()); err != nil {
logrus.Errorf("Failed to remove temp file: %s", tmpFile.Name())
}
return nil, 0, retryOnError(err)
}
@@ -179,8 +183,9 @@ func (ld *v2LayerDescriptor) Download(ctx context.Context, progressOutput progre
if !verifier.Verified() {
err = fmt.Errorf("filesystem layer verification failed for digest %s", ld.digest)
logrus.Error(err)
tmpFile.Close()
if err := os.RemoveAll(tmpFile.Name()); err != nil {
if err := os.Remove(tmpFile.Name()); err != nil {
logrus.Errorf("Failed to remove temp file: %s", tmpFile.Name())
}
@@ -191,7 +196,14 @@ func (ld *v2LayerDescriptor) Download(ctx context.Context, progressOutput progre
logrus.Debugf("Downloaded %s to tempfile %s", ld.ID(), tmpFile.Name())
tmpFile.Seek(0, 0)
_, err = tmpFile.Seek(0, os.SEEK_SET)
if err != nil {
tmpFile.Close()
if err := os.Remove(tmpFile.Name()); err != nil {
logrus.Errorf("Failed to remove temp file: %s", tmpFile.Name())
}
return nil, 0, xfer.DoNotRetry{Err: err}
}
return ioutils.NewReadCloserWrapper(tmpFile, tmpFileCloser(tmpFile)), size, nil
}

View File

@@ -171,7 +171,14 @@ func Push(ctx context.Context, ref reference.Named, imagePushConfig *ImagePushCo
// argument so that it can be used with httpBlobWriter's ReadFrom method.
// Using httpBlobWriter's Write method would send a PATCH request for every
// Write call.
func compress(in io.Reader) io.ReadCloser {
//
// The second return value is a channel that gets closed when the goroutine
// is finished. This allows the caller to make sure the goroutine finishes
// before it releases any resources connected with the reader that was
// passed in.
func compress(in io.Reader) (io.ReadCloser, chan struct{}) {
compressionDone := make(chan struct{})
pipeReader, pipeWriter := io.Pipe()
// Use a bufio.Writer to avoid excessive chunking in HTTP request.
bufWriter := bufio.NewWriterSize(pipeWriter, compressionBufSize)
@@ -190,7 +197,8 @@ func compress(in io.Reader) io.ReadCloser {
} else {
pipeWriter.Close()
}
close(compressionDone)
}()
return pipeReader
return pipeReader, compressionDone
}

View File

@@ -42,7 +42,7 @@ type v2Pusher struct {
config *ImagePushConfig
repo distribution.Repository
// pushState is state built by the Download functions.
// pushState is state built by the Upload functions.
pushState pushState
}
@@ -216,6 +216,7 @@ type v2PushDescriptor struct {
repoInfo reference.Named
repo distribution.Repository
pushState *pushState
remoteDescriptor distribution.Descriptor
}
func (pd *v2PushDescriptor) Key() string {
@@ -230,16 +231,16 @@ func (pd *v2PushDescriptor) DiffID() layer.DiffID {
return pd.layer.DiffID()
}
func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.Output) error {
func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.Output) (distribution.Descriptor, error) {
diffID := pd.DiffID()
pd.pushState.Lock()
if _, ok := pd.pushState.remoteLayers[diffID]; ok {
if descriptor, ok := pd.pushState.remoteLayers[diffID]; ok {
// it is already known that the push is not needed and
// therefore doing a stat is unnecessary
pd.pushState.Unlock()
progress.Update(progressOutput, pd.ID(), "Layer already exists")
return nil
return descriptor, nil
}
pd.pushState.Unlock()
@@ -249,14 +250,14 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
descriptor, exists, err := layerAlreadyExists(ctx, v2Metadata, pd.repoInfo, pd.repo, pd.pushState)
if err != nil {
progress.Update(progressOutput, pd.ID(), "Image push failed")
return retryOnError(err)
return distribution.Descriptor{}, retryOnError(err)
}
if exists {
progress.Update(progressOutput, pd.ID(), "Layer already exists")
pd.pushState.Lock()
pd.pushState.remoteLayers[diffID] = descriptor
pd.pushState.Unlock()
return nil
return descriptor, nil
}
}
@@ -286,7 +287,7 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
if mountFrom.SourceRepository != "" {
namedRef, err := reference.WithName(mountFrom.SourceRepository)
if err != nil {
return err
return distribution.Descriptor{}, err
}
// TODO (brianbland): We need to construct a reference where the Name is
@@ -294,12 +295,12 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
// richer reference package
remoteRef, err := distreference.WithName(namedRef.RemoteName())
if err != nil {
return err
return distribution.Descriptor{}, err
}
canonicalRef, err := distreference.WithDigest(remoteRef, mountFrom.Digest)
if err != nil {
return err
return distribution.Descriptor{}, err
}
createOpts = append(createOpts, client.WithMountFrom(canonicalRef))
@@ -311,6 +312,8 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
case distribution.ErrBlobMounted:
progress.Updatef(progressOutput, pd.ID(), "Mounted from %s", err.From.Name())
err.Descriptor.MediaType = schema2.MediaTypeLayer
pd.pushState.Lock()
pd.pushState.confirmedV2 = true
pd.pushState.remoteLayers[diffID] = err.Descriptor
@@ -318,10 +321,10 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
// Cache mapping from this layer's DiffID to the blobsum
if err := pd.v2MetadataService.Add(diffID, metadata.V2Metadata{Digest: mountFrom.Digest, SourceRepository: pd.repoInfo.FullName()}); err != nil {
return xfer.DoNotRetry{Err: err}
return distribution.Descriptor{}, xfer.DoNotRetry{Err: err}
}
return nil
return err.Descriptor, nil
}
if mountFrom.SourceRepository != "" {
// unable to mount layer from this repository, so this source mapping is no longer valid
@@ -330,21 +333,24 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
}
if err != nil {
return retryOnError(err)
return distribution.Descriptor{}, retryOnError(err)
}
defer layerUpload.Close()
arch, err := pd.layer.TarStream()
if err != nil {
return xfer.DoNotRetry{Err: err}
return distribution.Descriptor{}, xfer.DoNotRetry{Err: err}
}
// don't care if this fails; best effort
size, _ := pd.layer.DiffSize()
reader := progress.NewProgressReader(ioutils.NewCancelReadCloser(ctx, arch), progressOutput, size, pd.ID(), "Pushing")
defer reader.Close()
compressedReader := compress(reader)
compressedReader, compressionDone := compress(reader)
defer func() {
reader.Close()
<-compressionDone
}()
digester := digest.Canonical.New()
tee := io.TeeReader(compressedReader, digester.Hash())
@@ -352,12 +358,12 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
nn, err := layerUpload.ReadFrom(tee)
compressedReader.Close()
if err != nil {
return retryOnError(err)
return distribution.Descriptor{}, retryOnError(err)
}
pushDigest := digester.Digest()
if _, err := layerUpload.Commit(ctx, distribution.Descriptor{Digest: pushDigest}); err != nil {
return retryOnError(err)
return distribution.Descriptor{}, retryOnError(err)
}
logrus.Debugf("uploaded layer %s (%s), %d bytes", diffID, pushDigest, nn)
@@ -365,7 +371,7 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
// Cache mapping from this layer's DiffID to the blobsum
if err := pd.v2MetadataService.Add(diffID, metadata.V2Metadata{Digest: pushDigest, SourceRepository: pd.repoInfo.FullName()}); err != nil {
return xfer.DoNotRetry{Err: err}
return distribution.Descriptor{}, xfer.DoNotRetry{Err: err}
}
pd.pushState.Lock()
@@ -374,23 +380,24 @@ func (pd *v2PushDescriptor) Upload(ctx context.Context, progressOutput progress.
// speaks the v2 protocol.
pd.pushState.confirmedV2 = true
pd.pushState.remoteLayers[diffID] = distribution.Descriptor{
descriptor := distribution.Descriptor{
Digest: pushDigest,
MediaType: schema2.MediaTypeLayer,
Size: nn,
}
pd.pushState.remoteLayers[diffID] = descriptor
pd.pushState.Unlock()
return nil
return descriptor, nil
}
func (pd *v2PushDescriptor) SetRemoteDescriptor(descriptor distribution.Descriptor) {
pd.remoteDescriptor = descriptor
}
func (pd *v2PushDescriptor) Descriptor() distribution.Descriptor {
// Not necessary to lock pushStatus because this is always
// called after all the mutation in pushStatus.
// By the time this function is called, every layer will have
// an entry in remoteLayers.
return pd.pushState.remoteLayers[pd.DiffID()]
return pd.remoteDescriptor
}
// layerAlreadyExists checks if the registry already know about any of the

View File

@@ -6,6 +6,7 @@ import (
"net/http"
"net/url"
"strings"
"syscall"
"time"
"github.com/docker/distribution"
@@ -139,14 +140,22 @@ func (th *existingTokenHandler) AuthorizeRequest(req *http.Request, params map[s
func retryOnError(err error) error {
switch v := err.(type) {
case errcode.Errors:
return retryOnError(v[0])
if len(v) != 0 {
return retryOnError(v[0])
}
case errcode.Error:
switch v.Code {
case errcode.ErrorCodeUnauthorized, errcode.ErrorCodeUnsupported, errcode.ErrorCodeDenied:
return xfer.DoNotRetry{Err: err}
}
case *url.Error:
return retryOnError(v.Err)
case *client.UnexpectedHTTPResponseError:
return xfer.DoNotRetry{Err: err}
case error:
if strings.Contains(err.Error(), strings.ToLower(syscall.ENOSPC.Error())) {
return xfer.DoNotRetry{Err: err}
}
}
// let's be nice and fallback if the error is a completely
// unexpected one.

View File

@@ -1,6 +1,7 @@
package xfer
import (
"runtime"
"sync"
"github.com/docker/docker/pkg/progress"
@@ -38,7 +39,7 @@ type Transfer interface {
Watch(progressOutput progress.Output) *Watcher
Release(*Watcher)
Context() context.Context
Cancel()
Close()
Done() <-chan struct{}
Released() <-chan struct{}
Broadcast(masterProgressChan <-chan progress.Progress)
@@ -61,11 +62,14 @@ type transfer struct {
// running remains open as long as the transfer is in progress.
running chan struct{}
// hasWatchers stays open until all watchers release the transfer.
hasWatchers chan struct{}
// released stays open until all watchers release the transfer and
// the transfer is no longer tracked by the transfer manager.
released chan struct{}
// broadcastDone is true if the master progress channel has closed.
broadcastDone bool
// closed is true if Close has been called
closed bool
// broadcastSyncChan allows watchers to "ping" the broadcasting
// goroutine to wait for it for deplete its input channel. This ensures
// a detaching watcher won't miss an event that was sent before it
@@ -78,7 +82,7 @@ func NewTransfer() Transfer {
t := &transfer{
watchers: make(map[chan struct{}]*Watcher),
running: make(chan struct{}),
hasWatchers: make(chan struct{}),
released: make(chan struct{}),
broadcastSyncChan: make(chan struct{}),
}
@@ -144,13 +148,13 @@ func (t *transfer) Watch(progressOutput progress.Output) *Watcher {
running: make(chan struct{}),
}
t.watchers[w.releaseChan] = w
if t.broadcastDone {
close(w.running)
return w
}
t.watchers[w.releaseChan] = w
go func() {
defer func() {
close(w.running)
@@ -202,8 +206,19 @@ func (t *transfer) Release(watcher *Watcher) {
delete(t.watchers, watcher.releaseChan)
if len(t.watchers) == 0 {
close(t.hasWatchers)
t.cancel()
if t.closed {
// released may have been closed already if all
// watchers were released, then another one was added
// while waiting for a previous watcher goroutine to
// finish.
select {
case <-t.released:
default:
close(t.released)
}
} else {
t.cancel()
}
}
t.mu.Unlock()
@@ -223,9 +238,9 @@ func (t *transfer) Done() <-chan struct{} {
}
// Released returns a channel which is closed once all watchers release the
// transfer.
// transfer AND the transfer is no longer tracked by the transfer manager.
func (t *transfer) Released() <-chan struct{} {
return t.hasWatchers
return t.released
}
// Context returns the context associated with the transfer.
@@ -233,9 +248,15 @@ func (t *transfer) Context() context.Context {
return t.ctx
}
// Cancel cancels the context associated with the transfer.
func (t *transfer) Cancel() {
t.cancel()
// Close is called by the transfer manager when the transfer is no longer
// being tracked.
func (t *transfer) Close() {
t.mu.Lock()
t.closed = true
if len(t.watchers) == 0 {
close(t.released)
}
t.mu.Unlock()
}
// DoFunc is a function called by the transfer manager to actually perform
@@ -280,10 +301,33 @@ func (tm *transferManager) Transfer(key string, xferFunc DoFunc, progressOutput
tm.mu.Lock()
defer tm.mu.Unlock()
if xfer, present := tm.transfers[key]; present {
for {
xfer, present := tm.transfers[key]
if !present {
break
}
// Transfer is already in progress.
watcher := xfer.Watch(progressOutput)
return xfer, watcher
select {
case <-xfer.Context().Done():
// We don't want to watch a transfer that has been cancelled.
// Wait for it to be removed from the map and try again.
xfer.Release(watcher)
tm.mu.Unlock()
// The goroutine that removes this transfer from the
// map is also waiting for xfer.Done(), so yield to it.
// This could be avoided by adding a Closed method
// to Transfer to allow explicitly waiting for it to be
// removed the map, but forcing a scheduling round in
// this very rare case seems better than bloating the
// interface definition.
runtime.Gosched()
<-xfer.Done()
tm.mu.Lock()
default:
return xfer, watcher
}
}
start := make(chan struct{})
@@ -318,6 +362,7 @@ func (tm *transferManager) Transfer(key string, xferFunc DoFunc, progressOutput
}
delete(tm.transfers, key)
tm.mu.Unlock()
xfer.Close()
return
}
}

View File

@@ -291,6 +291,44 @@ func TestWatchRelease(t *testing.T) {
}
}
func TestWatchFinishedTransfer(t *testing.T) {
makeXferFunc := func(id string) DoFunc {
return func(progressChan chan<- progress.Progress, start <-chan struct{}, inactive chan<- struct{}) Transfer {
xfer := NewTransfer()
go func() {
// Finish immediately
close(progressChan)
}()
return xfer
}
}
tm := NewTransferManager(5)
// Start a transfer
watchers := make([]*Watcher, 3)
var xfer Transfer
xfer, watchers[0] = tm.Transfer("id1", makeXferFunc("id1"), progress.ChanOutput(make(chan progress.Progress)))
// Give it a watcher immediately
watchers[1] = xfer.Watch(progress.ChanOutput(make(chan progress.Progress)))
// Wait for the transfer to complete
<-xfer.Done()
// Set up another watcher
watchers[2] = xfer.Watch(progress.ChanOutput(make(chan progress.Progress)))
// Release the watchers
for _, w := range watchers {
xfer.Release(w)
}
// Now that all watchers have been released, Released() should
// return a closed channel.
<-xfer.Released()
}
func TestDuplicateTransfer(t *testing.T) {
ready := make(chan struct{})

View File

@@ -5,6 +5,7 @@ import (
"time"
"github.com/Sirupsen/logrus"
"github.com/docker/distribution"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/progress"
"golang.org/x/net/context"
@@ -28,8 +29,8 @@ func NewLayerUploadManager(concurrencyLimit int) *LayerUploadManager {
type uploadTransfer struct {
Transfer
diffID layer.DiffID
err error
remoteDescriptor distribution.Descriptor
err error
}
// An UploadDescriptor references a layer that may need to be uploaded.
@@ -41,7 +42,12 @@ type UploadDescriptor interface {
// DiffID should return the DiffID for this layer.
DiffID() layer.DiffID
// Upload is called to perform the Upload.
Upload(ctx context.Context, progressOutput progress.Output) error
Upload(ctx context.Context, progressOutput progress.Output) (distribution.Descriptor, error)
// SetRemoteDescriptor provides the distribution.Descriptor that was
// returned by Upload. This descriptor is not to be confused with
// the UploadDescriptor interface, which is used for internally
// identifying layers that are being uploaded.
SetRemoteDescriptor(descriptor distribution.Descriptor)
}
// Upload is a blocking function which ensures the listed layers are present on
@@ -50,7 +56,7 @@ type UploadDescriptor interface {
func (lum *LayerUploadManager) Upload(ctx context.Context, layers []UploadDescriptor, progressOutput progress.Output) error {
var (
uploads []*uploadTransfer
dedupDescriptors = make(map[string]struct{})
dedupDescriptors = make(map[string]*uploadTransfer)
)
for _, descriptor := range layers {
@@ -60,12 +66,12 @@ func (lum *LayerUploadManager) Upload(ctx context.Context, layers []UploadDescri
if _, present := dedupDescriptors[key]; present {
continue
}
dedupDescriptors[key] = struct{}{}
xferFunc := lum.makeUploadFunc(descriptor)
upload, watcher := lum.tm.Transfer(descriptor.Key(), xferFunc, progressOutput)
defer upload.Release(watcher)
uploads = append(uploads, upload.(*uploadTransfer))
dedupDescriptors[key] = upload.(*uploadTransfer)
}
for _, upload := range uploads {
@@ -78,6 +84,9 @@ func (lum *LayerUploadManager) Upload(ctx context.Context, layers []UploadDescri
}
}
}
for _, l := range layers {
l.SetRemoteDescriptor(dedupDescriptors[l.Key()].remoteDescriptor)
}
return nil
}
@@ -86,7 +95,6 @@ func (lum *LayerUploadManager) makeUploadFunc(descriptor UploadDescriptor) DoFun
return func(progressChan chan<- progress.Progress, start <-chan struct{}, inactive chan<- struct{}) Transfer {
u := &uploadTransfer{
Transfer: NewTransfer(),
diffID: descriptor.DiffID(),
}
go func() {
@@ -105,8 +113,9 @@ func (lum *LayerUploadManager) makeUploadFunc(descriptor UploadDescriptor) DoFun
retries := 0
for {
err := descriptor.Upload(u.Transfer.Context(), progressOutput)
remoteDescriptor, err := descriptor.Upload(u.Transfer.Context(), progressOutput)
if err == nil {
u.remoteDescriptor = remoteDescriptor
break
}

View File

@@ -6,6 +6,7 @@ import (
"testing"
"time"
"github.com/docker/distribution"
"github.com/docker/distribution/digest"
"github.com/docker/docker/layer"
"github.com/docker/docker/pkg/progress"
@@ -35,13 +36,17 @@ func (u *mockUploadDescriptor) DiffID() layer.DiffID {
return u.diffID
}
// SetRemoteDescriptor is not used in the mock.
func (u *mockUploadDescriptor) SetRemoteDescriptor(remoteDescriptor distribution.Descriptor) {
}
// Upload is called to perform the upload.
func (u *mockUploadDescriptor) Upload(ctx context.Context, progressOutput progress.Output) error {
func (u *mockUploadDescriptor) Upload(ctx context.Context, progressOutput progress.Output) (distribution.Descriptor, error) {
if u.currentUploads != nil {
defer atomic.AddInt32(u.currentUploads, -1)
if atomic.AddInt32(u.currentUploads, 1) > maxUploadConcurrency {
return errors.New("concurrency limit exceeded")
return distribution.Descriptor{}, errors.New("concurrency limit exceeded")
}
}
@@ -49,7 +54,7 @@ func (u *mockUploadDescriptor) Upload(ctx context.Context, progressOutput progre
for i := int64(0); i <= 10; i++ {
select {
case <-ctx.Done():
return ctx.Err()
return distribution.Descriptor{}, ctx.Err()
case <-time.After(10 * time.Millisecond):
progressOutput.WriteProgress(progress.Progress{ID: u.ID(), Current: i, Total: 10})
}
@@ -57,10 +62,10 @@ func (u *mockUploadDescriptor) Upload(ctx context.Context, progressOutput progre
if u.simulateRetries != 0 {
u.simulateRetries--
return errors.New("simulating retry")
return distribution.Descriptor{}, errors.New("simulating retry")
}
return nil
return distribution.Descriptor{}, nil
}
func uploadDescriptors(currentUploads *int32) []UploadDescriptor {

View File

@@ -6,6 +6,7 @@ import (
"github.com/docker/docker/cli"
"github.com/docker/docker/cliconfig"
flag "github.com/docker/docker/pkg/mflag"
"github.com/docker/docker/utils"
)
var clientFlags = &cli.ClientFlags{FlagSet: new(flag.FlagSet), Common: commonFlags}
@@ -24,5 +25,9 @@ func init() {
if clientFlags.Common.TrustKey == "" {
clientFlags.Common.TrustKey = filepath.Join(cliconfig.ConfigDir(), defaultTrustKeyFile)
}
if clientFlags.Common.Debug {
utils.EnableDebug()
}
}
}

View File

@@ -18,6 +18,7 @@ const (
defaultCaFile = "ca.pem"
defaultKeyFile = "key.pem"
defaultCertFile = "cert.pem"
tlsVerifyKey = "tlsverify"
)
var (
@@ -55,21 +56,12 @@ func init() {
func postParseCommon() {
cmd := commonFlags.FlagSet
if commonFlags.LogLevel != "" {
lvl, err := logrus.ParseLevel(commonFlags.LogLevel)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", commonFlags.LogLevel)
os.Exit(1)
}
logrus.SetLevel(lvl)
} else {
logrus.SetLevel(logrus.InfoLevel)
}
setDaemonLogLevel(commonFlags.LogLevel)
// Regardless of whether the user sets it to true or false, if they
// specify --tlsverify at all then we need to turn on tls
// TLSVerify can be true even if not set due to DOCKER_TLS_VERIFY env var, so we need to check that here as well
if cmd.IsSet("-tlsverify") || commonFlags.TLSVerify {
if cmd.IsSet("-"+tlsVerifyKey) || commonFlags.TLSVerify {
commonFlags.TLS = true
}
@@ -93,3 +85,16 @@ func postParseCommon() {
}
}
}
func setDaemonLogLevel(logLevel string) {
if logLevel != "" {
lvl, err := logrus.ParseLevel(logLevel)
if err != nil {
fmt.Fprintf(os.Stderr, "Unable to parse logging level: %s\n", logLevel)
os.Exit(1)
}
logrus.SetLevel(lvl)
} else {
logrus.SetLevel(logrus.InfoLevel)
}
}

Some files were not shown because too many files have changed in this diff Show More