Merge pull request #20195 from tiborvass/1.10.1-cherrypicks
1.10.1 cherrypicks
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 2d19c20..b067233 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,6 +5,44 @@
https://docs.docker.com/misc/deprecated/ where target removal dates can also
be found.
+## 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 work without needing `-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)
+- 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.
diff --git a/container/container_unix.go b/container/container_unix.go
index 6fa7215..b8bae23 100644
--- a/container/container_unix.go
+++ b/container/container_unix.go
@@ -44,7 +44,6 @@
HostnamePath string
HostsPath string
ShmPath string
- MqueuePath string
ResolvConfPath string
SeccompProfile string
}
@@ -563,18 +562,6 @@
}
}
- 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"))
}
@@ -593,16 +580,6 @@
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
}
diff --git a/contrib/completion/bash/docker b/contrib/completion/bash/docker
index e731de8..c5049a8 100644
--- a/contrib/completion/bash/docker
+++ b/contrib/completion/bash/docker
@@ -1758,6 +1758,11 @@
__docker_nospace
fi
;;
+ seccomp:*)
+ local cur=${cur##*:}
+ _filedir
+ COMPREPLY+=( $( compgen -W "unconfined" -- "$cur" ) )
+ ;;
*)
COMPREPLY=( $( compgen -W "label apparmor seccomp" -S ":" -- "$cur") )
__docker_nospace
diff --git a/contrib/init/systemd/docker.service b/contrib/init/systemd/docker.service
index d43658e..6015b74 100644
--- a/contrib/init/systemd/docker.service
+++ b/contrib/init/systemd/docker.service
@@ -11,7 +11,6 @@
LimitNOFILE=1048576
LimitNPROC=1048576
LimitCORE=infinity
-TasksMax=1048576
TimeoutStartSec=0
[Install]
diff --git a/daemon/container_operations_unix.go b/daemon/container_operations_unix.go
index 46096b8..a96e394 100644
--- a/daemon/container_operations_unix.go
+++ b/daemon/container_operations_unix.go
@@ -93,11 +93,6 @@
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 {
@@ -105,18 +100,13 @@
}
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"
}
}
@@ -1057,21 +1047,6 @@
}
}
- 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
}
diff --git a/daemon/execdriver/native/template/default_template_linux.go b/daemon/execdriver/native/template/default_template_linux.go
index 7e7fe28..073bcac 100644
--- a/daemon/execdriver/native/template/default_template_linux.go
+++ b/daemon/execdriver/native/template/default_template_linux.go
@@ -65,6 +65,12 @@
Data: "newinstance,ptmxmode=0666,mode=0620,gid=5",
},
{
+ Source: "mqueue",
+ Destination: "/dev/mqueue",
+ Device: "mqueue",
+ Flags: defaultMountFlags,
+ },
+ {
Source: "sysfs",
Destination: "/sys",
Device: "sysfs",
diff --git a/daemon/graphdriver/zfs/zfs.go b/daemon/graphdriver/zfs/zfs.go
index e096798..5cc10d2 100644
--- a/daemon/graphdriver/zfs/zfs.go
+++ b/daemon/graphdriver/zfs/zfs.go
@@ -308,10 +308,14 @@
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
}
diff --git a/daemon/list.go b/daemon/list.go
index 5aebb74..e2828b1 100644
--- a/daemon/list.go
+++ b/daemon/list.go
@@ -74,6 +74,13 @@
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
@@ -165,6 +172,9 @@
}
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
@@ -201,15 +211,17 @@
})
}
- 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
}
@@ -220,6 +232,8 @@
ancestorFilter: ancestorFilter,
images: imagesFilter,
exitAllowed: filtExited,
+ beforeContainer: beforeContainer,
+ sinceContainer: sinceContainer,
beforeFilter: beforeContFilter,
sinceFilter: sinceContFilter,
ContainersConfig: config,
@@ -231,7 +245,8 @@
// 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
}
@@ -255,6 +270,21 @@
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 {
diff --git a/hack/install.sh b/hack/install.sh
index 79ac0ad..5afb445 100755
--- a/hack/install.sh
+++ b/hack/install.sh
@@ -367,7 +367,7 @@
# aufs is preferred over devicemapper; try to ensure the driver is available.
if ! grep -q aufs /proc/filesystems && ! $sh_c 'modprobe aufs'; then
- if uname -r | grep -q -- '-generic' && dpkg -l 'linux-image-*-generic' | grep -q '^ii' 2>/dev/null; then
+ if uname -r | grep -q -- '-generic' && dpkg -l 'linux-image-*-generic' | grep -qE '^ii|^hi' 2>/dev/null; then
kern_extras="linux-image-extra-$(uname -r) linux-image-extra-virtual"
apt_get_update
diff --git a/hack/vendor.sh b/hack/vendor.sh
index 71d3375..d872c8b 100755
--- a/hack/vendor.sh
+++ b/hack/vendor.sh
@@ -27,7 +27,7 @@
clone git github.com/imdario/mergo 0.2.1
#get libnetwork packages
-clone git github.com/docker/libnetwork v0.6.0-rc7
+clone git github.com/docker/libnetwork v0.6.1-rc2
clone git github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
clone git github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
clone git github.com/hashicorp/memberlist 9a1e242e454d2443df330bdd51a436d5a9058fc4
diff --git a/image/store.go b/image/store.go
index 302be2f..1279f59 100644
--- a/image/store.go
+++ b/image/store.go
@@ -231,6 +231,9 @@
if parentMeta == nil {
return fmt.Errorf("unknown parent image ID %s", parent.String())
}
+ if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil {
+ delete(is.images[parent].children, id)
+ }
parentMeta.children[id] = struct{}{}
return is.fs.SetMetadata(id, "parent", []byte(parent))
}
diff --git a/image/store_test.go b/image/store_test.go
index 279708f..50f8aa8 100644
--- a/image/store_test.go
+++ b/image/store_test.go
@@ -233,6 +233,62 @@
}
}
+func TestParentReset(t *testing.T) {
+ tmpdir, err := ioutil.TempDir("", "images-fs-store")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+ fs, err := NewFSStoreBackend(tmpdir)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ is, err := NewImageStore(fs, &mockLayerGetReleaser{})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ id, err := is.Create([]byte(`{"comment": "abc1", "rootfs": {"type": "layers"}}`))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ id2, err := is.Create([]byte(`{"comment": "abc2", "rootfs": {"type": "layers"}}`))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ id3, err := is.Create([]byte(`{"comment": "abc3", "rootfs": {"type": "layers"}}`))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err := is.SetParent(id, id2); err != nil {
+ t.Fatal(err)
+ }
+
+ ids := is.Children(id2)
+ if actual, expected := len(ids), 1; expected != actual {
+ t.Fatalf("wrong number of children: %d, got %d", expected, actual)
+ }
+
+ if err := is.SetParent(id, id3); err != nil {
+ t.Fatal(err)
+ }
+
+ ids = is.Children(id2)
+ if actual, expected := len(ids), 0; expected != actual {
+ t.Fatalf("wrong number of children after parent reset: %d, got %d", expected, actual)
+ }
+
+ ids = is.Children(id3)
+ if actual, expected := len(ids), 1; expected != actual {
+ t.Fatalf("wrong number of children after parent reset: %d, got %d", expected, actual)
+ }
+
+}
+
type mockLayerGetReleaser struct{}
func (ls *mockLayerGetReleaser) Get(layer.ChainID) (layer.Layer, error) {
diff --git a/integration-cli/docker_cli_authz_unix_test.go b/integration-cli/docker_cli_authz_unix_test.go
index 71a64f3..4ab83b9 100644
--- a/integration-cli/docker_cli_authz_unix_test.go
+++ b/integration-cli/docker_cli_authz_unix_test.go
@@ -11,10 +11,15 @@
"os"
"strings"
+ "bufio"
+ "bytes"
"github.com/docker/docker/pkg/authorization"
"github.com/docker/docker/pkg/integration/checker"
"github.com/docker/docker/pkg/plugins"
"github.com/go-check/check"
+ "os/exec"
+ "strconv"
+ "time"
)
const (
@@ -221,6 +226,71 @@
c.Assert(res, check.Equals, fmt.Sprintf("Error response from daemon: authorization denied by plugin %s: %s\n", testAuthZPlugin, unauthorizedMessage))
}
+// TestAuthZPluginAllowEventStream verifies event stream propogates correctly after request pass through by the authorization plugin
+func (s *DockerAuthzSuite) TestAuthZPluginAllowEventStream(c *check.C) {
+ testRequires(c, DaemonIsLinux)
+
+ // Start the authorization plugin
+ err := s.d.Start("--authorization-plugin=" + testAuthZPlugin)
+ c.Assert(err, check.IsNil)
+ s.ctrl.reqRes.Allow = true
+ s.ctrl.resRes.Allow = true
+
+ startTime := strconv.FormatInt(daemonTime(c).Unix(), 10)
+ // Add another command to to enable event pipelining
+ eventsCmd := exec.Command(s.d.cmd.Path, "--host", s.d.sock(), "events", "--since", startTime)
+ stdout, err := eventsCmd.StdoutPipe()
+ if err != nil {
+ c.Assert(err, check.IsNil)
+ }
+
+ observer := eventObserver{
+ buffer: new(bytes.Buffer),
+ command: eventsCmd,
+ scanner: bufio.NewScanner(stdout),
+ startTime: startTime,
+ }
+
+ err = observer.Start()
+ c.Assert(err, checker.IsNil)
+ defer observer.Stop()
+
+ // Create a container and wait for the creation events
+ _, err = s.d.Cmd("pull", "busybox")
+ c.Assert(err, check.IsNil)
+ out, err := s.d.Cmd("run", "-d", "busybox", "top")
+ c.Assert(err, check.IsNil)
+
+ containerID := strings.TrimSpace(out)
+
+ events := map[string]chan bool{
+ "create": make(chan bool),
+ "start": make(chan bool),
+ }
+
+ matcher := matchEventLine(containerID, "container", events)
+ processor := processEventMatch(events)
+ go observer.Match(matcher, processor)
+
+ // Ensure all events are received
+ for event, eventChannel := range events {
+
+ select {
+ case <-time.After(5 * time.Second):
+ // Fail the test
+ observer.CheckEventError(c, containerID, event, matcher)
+ c.FailNow()
+ case <-eventChannel:
+ // Ignore, event received
+ }
+ }
+
+ // Ensure both events and container endpoints are passed to the authorization plugin
+ assertURIRecorded(c, s.ctrl.requestsURIs, "/events")
+ assertURIRecorded(c, s.ctrl.requestsURIs, "/containers/create")
+ assertURIRecorded(c, s.ctrl.requestsURIs, fmt.Sprintf("/containers/%s/start", containerID))
+}
+
func (s *DockerAuthzSuite) TestAuthZPluginErrorResponse(c *check.C) {
err := s.d.Start("--authorization-plugin=" + testAuthZPlugin)
c.Assert(err, check.IsNil)
diff --git a/integration-cli/docker_cli_build_unix_test.go b/integration-cli/docker_cli_build_unix_test.go
index 7d204e1..ea8b32a 100644
--- a/integration-cli/docker_cli_build_unix_test.go
+++ b/integration-cli/docker_cli_build_unix_test.go
@@ -178,7 +178,8 @@
}
matcher := matchEventLine(buildID, "container", testActions)
- go observer.Match(matcher)
+ processor := processEventMatch(testActions)
+ go observer.Match(matcher, processor)
select {
case <-time.After(10 * time.Second):
diff --git a/integration-cli/docker_cli_events_unix_test.go b/integration-cli/docker_cli_events_unix_test.go
index 7afc8fc..2f1cb91 100644
--- a/integration-cli/docker_cli_events_unix_test.go
+++ b/integration-cli/docker_cli_events_unix_test.go
@@ -224,7 +224,8 @@
}
matcher := matchEventLine(containerID, "container", testActions)
- go observer.Match(matcher)
+ processor := processEventMatch(testActions)
+ go observer.Match(matcher, processor)
select {
case <-time.After(5 * time.Second):
@@ -280,7 +281,8 @@
}
matcher := matchEventLine(imageID, "image", testActions)
- go observer.Match(matcher)
+ processor := processEventMatch(testActions)
+ go observer.Match(matcher, processor)
select {
case <-time.After(10 * time.Second):
diff --git a/integration-cli/docker_cli_ps_test.go b/integration-cli/docker_cli_ps_test.go
index 65be5a7..4bda638 100644
--- a/integration-cli/docker_cli_ps_test.go
+++ b/integration-cli/docker_cli_ps_test.go
@@ -48,8 +48,6 @@
out, _ = dockerCmd(c, "ps")
c.Assert(assertContainerList(out, []string{fourthID, secondID, firstID}), checker.Equals, true, check.Commentf("RUNNING: Container list is not in the correct order: \n%s", out))
- // from here all flag '-a' is ignored
-
// limit
out, _ = dockerCmd(c, "ps", "-n=2", "-a")
expected := []string{fourthID, thirdID}
@@ -61,56 +59,138 @@
// filter since
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-a")
expected = []string{fourthID, thirdID, secondID}
- c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE & ALL: Container list is not in the correct order: \n%s", out))
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter & ALL: Container list is not in the correct order: \n%s", out))
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID)
- c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE: Container list is not in the correct order: \n%s", out))
+ expected = []string{fourthID, secondID}
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter: Container list is not in the correct order: \n%s", out))
// filter before
- out, _ = dockerCmd(c, "ps", "-f", "before="+thirdID, "-a")
- expected = []string{secondID, firstID}
- c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE & ALL: Container list is not in the correct order: \n%s", out))
+ out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-a")
+ expected = []string{thirdID, secondID, firstID}
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter & ALL: Container list is not in the correct order: \n%s", out))
- out, _ = dockerCmd(c, "ps", "-f", "before="+thirdID)
- c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE: Container list is not in the correct order: \n%s", out))
+ out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID)
+ expected = []string{secondID, firstID}
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter: Container list is not in the correct order: \n%s", out))
// filter since & before
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-a")
expected = []string{thirdID, secondID}
- c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE & ALL: Container list is not in the correct order: \n%s", out))
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter, BEFORE filter & ALL: Container list is not in the correct order: \n%s", out))
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID)
- c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE: Container list is not in the correct order: \n%s", out))
+ expected = []string{secondID}
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter, BEFORE filter: Container list is not in the correct order: \n%s", out))
// filter since & limit
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-n=2", "-a")
expected = []string{fourthID, thirdID}
- c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-n=2")
- c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, LIMIT: Container list is not in the correct order: \n%s", out))
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter, LIMIT: Container list is not in the correct order: \n%s", out))
// filter before & limit
out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1", "-a")
expected = []string{thirdID}
- c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
out, _ = dockerCmd(c, "ps", "-f", "before="+fourthID, "-n=1")
- c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE, LIMIT: Container list is not in the correct order: \n%s", out))
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE filter, LIMIT: Container list is not in the correct order: \n%s", out))
// filter since & filter before & limit
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1", "-a")
expected = []string{thirdID}
- c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter, BEFORE filter, LIMIT & ALL: Container list is not in the correct order: \n%s", out))
out, _ = dockerCmd(c, "ps", "-f", "since="+firstID, "-f", "before="+fourthID, "-n=1")
- c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE, LIMIT: Container list is not in the correct order: \n%s", out))
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE filter, BEFORE filter, LIMIT: Container list is not in the correct order: \n%s", out))
+
+}
+
+// FIXME remove this for 1.12 as --since and --before are deprecated
+func (s *DockerSuite) TestPsListContainersDeprecatedSinceAndBefore(c *check.C) {
+ out, _ := runSleepingContainer(c, "-d")
+ firstID := strings.TrimSpace(out)
+
+ out, _ = runSleepingContainer(c, "-d")
+ secondID := strings.TrimSpace(out)
+
+ // not long running
+ out, _ = dockerCmd(c, "run", "-d", "busybox", "true")
+ thirdID := strings.TrimSpace(out)
+
+ out, _ = runSleepingContainer(c, "-d")
+ fourthID := strings.TrimSpace(out)
+
+ // make sure the second is running
+ c.Assert(waitRun(secondID), checker.IsNil)
+
+ // make sure third one is not running
+ dockerCmd(c, "wait", thirdID)
+
+ // make sure the forth is running
+ c.Assert(waitRun(fourthID), checker.IsNil)
+
+ // since
+ out, _ = dockerCmd(c, "ps", "--since="+firstID, "-a")
+ expected := []string{fourthID, thirdID, secondID}
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE & ALL: Container list is not in the correct order: %v \n%s", expected, out))
+
+ out, _ = dockerCmd(c, "ps", "--since="+firstID)
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE: Container list is not in the correct order: %v \n%s", expected, out))
+
+ // before
+ out, _ = dockerCmd(c, "ps", "--before="+thirdID, "-a")
+ expected = []string{secondID, firstID}
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE & ALL: Container list is not in the correct order: %v \n%s", expected, out))
+
+ out, _ = dockerCmd(c, "ps", "--before="+thirdID)
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE: Container list is not in the correct order: %v \n%s", expected, out))
+
+ // since & before
+ out, _ = dockerCmd(c, "ps", "--since="+firstID, "--before="+fourthID, "-a")
+ expected = []string{thirdID, secondID}
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE & ALL: Container list is not in the correct order: %v \n%s", expected, out))
+
+ out, _ = dockerCmd(c, "ps", "--since="+firstID, "--before="+fourthID)
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE: Container list is not in the correct order: %v \n%s", expected, out))
+
+ // since & limit
+ out, _ = dockerCmd(c, "ps", "--since="+firstID, "-n=2", "-a")
+ expected = []string{fourthID, thirdID}
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, LIMIT & ALL: Container list is not in the correct order: %v \n%s", expected, out))
+
+ out, _ = dockerCmd(c, "ps", "--since="+firstID, "-n=2")
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, LIMIT: Container list is not in the correct order: %v \n%s", expected, out))
+
+ // before & limit
+ out, _ = dockerCmd(c, "ps", "--before="+fourthID, "-n=1", "-a")
+ expected = []string{thirdID}
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE, LIMIT & ALL: Container list is not in the correct order: %v \n%s", expected, out))
+
+ out, _ = dockerCmd(c, "ps", "--before="+fourthID, "-n=1")
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("BEFORE, LIMIT: Container list is not in the correct order: %v \n%s", expected, out))
+
+ // since & before & limit
+ out, _ = dockerCmd(c, "ps", "--since="+firstID, "--before="+fourthID, "-n=1", "-a")
+ expected = []string{thirdID}
+ c.Assert(assertContainerList(out, expected), checker.Equals, true, check.Commentf("SINCE, BEFORE, LIMIT & ALL: Container list is not in the correct order: %v \n%s", expected, out))
}
func assertContainerList(out string, expected []string) bool {
lines := strings.Split(strings.Trim(out, "\n "), "\n")
+ // FIXME remove this for 1.12 as --since and --before are deprecated
+ // This is here to remove potential Warning: lines (printed out with deprecated flags)
+ for i := 0; i < 2; i++ {
+ if strings.Contains(lines[0], "Warning:") {
+ lines = lines[1:]
+ }
+ }
+
if len(lines)-1 != len(expected) {
return false
}
diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go
index e4f8045..d70d478 100644
--- a/integration-cli/docker_cli_run_test.go
+++ b/integration-cli/docker_cli_run_test.go
@@ -2365,7 +2365,7 @@
// Not applicable on Windows as uses Unix-specific capabilities
testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
- out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "echo -n test > /dev/shm/test && top")
+ out, _ := dockerCmd(c, "run", "-d", "busybox", "sh", "-c", "echo -n test > /dev/shm/test && touch /dev/mqueue/toto && top")
id := strings.TrimSpace(out)
state, err := inspectField(id, "State.Running")
@@ -2391,6 +2391,18 @@
if catOutput != "test" {
c.Fatalf("Output of /dev/shm/test expected test but found: %s", catOutput)
}
+
+ // check that /dev/mqueue is actually of mqueue type
+ grepOutput, _ := dockerCmd(c, "run", fmt.Sprintf("--ipc=container:%s", id), "busybox", "grep", "/dev/mqueue", "/proc/mounts")
+ if !strings.HasPrefix(grepOutput, "mqueue /dev/mqueue mqueue rw") {
+ c.Fatalf("Output of 'grep /proc/mounts' expected 'mqueue /dev/mqueue mqueue rw' but found: %s", grepOutput)
+ }
+
+ lsOutput, _ := dockerCmd(c, "run", fmt.Sprintf("--ipc=container:%s", id), "busybox", "ls", "/dev/mqueue")
+ lsOutput = strings.Trim(lsOutput, "\n")
+ if lsOutput != "toto" {
+ c.Fatalf("Output of 'ls /dev/mqueue' expected 'toto' but found: %s", lsOutput)
+ }
}
func (s *DockerSuite) TestRunModeIpcContainerNotExists(c *check.C) {
@@ -2417,9 +2429,11 @@
func (s *DockerSuite) TestRunMountShmMqueueFromHost(c *check.C) {
// Not applicable on Windows as uses Unix-specific capabilities
- testRequires(c, SameHostDaemon, DaemonIsLinux)
+ testRequires(c, SameHostDaemon, DaemonIsLinux, NotUserNamespace)
- dockerCmd(c, "run", "-d", "--name", "shmfromhost", "-v", "/dev/shm:/dev/shm", "busybox", "sh", "-c", "echo -n test > /dev/shm/test && top")
+ dockerCmd(c, "run", "-d", "--name", "shmfromhost", "-v", "/dev/shm:/dev/shm", "-v", "/dev/mqueue:/dev/mqueue", "busybox", "sh", "-c", "echo -n test > /dev/shm/test && touch /dev/mqueue/toto && top")
+ defer os.Remove("/dev/mqueue/toto")
+ defer os.Remove("/dev/shm/test")
volPath, err := inspectMountSourceField("shmfromhost", "/dev/shm")
c.Assert(err, check.IsNil)
if volPath != "/dev/shm" {
@@ -2430,6 +2444,11 @@
if out != "test" {
c.Fatalf("Output of /dev/shm/test expected test but found: %s", out)
}
+
+ // Check that the mq was created
+ if _, err := os.Stat("/dev/mqueue/toto"); err != nil {
+ c.Fatalf("Failed to confirm '/dev/mqueue/toto' presence on host: %s", err.Error())
+ }
}
func (s *DockerSuite) TestContainerNetworkMode(c *check.C) {
diff --git a/integration-cli/docker_cli_volume_driver_compat_unix_test.go b/integration-cli/docker_cli_volume_driver_compat_unix_test.go
index b15bacc..2207822 100644
--- a/integration-cli/docker_cli_volume_driver_compat_unix_test.go
+++ b/integration-cli/docker_cli_volume_driver_compat_unix_test.go
@@ -24,11 +24,18 @@
})
}
+type vol struct {
+ Name string
+ Mountpoint string
+ Opts map[string]string
+}
+
type DockerExternalVolumeSuiteCompatV1_1 struct {
- server *httptest.Server
- ds *DockerSuite
- d *Daemon
- ec *eventCounter
+ server *httptest.Server
+ ds *DockerSuite
+ d *Daemon
+ ec *eventCounter
+ volList []vol
}
func (s *DockerExternalVolumeSuiteCompatV1_1) SetUpTest(c *check.C) {
@@ -47,6 +54,7 @@
type pluginRequest struct {
Name string
+ Opts map[string]string
}
type pluginResp struct {
@@ -54,12 +62,6 @@
Err string `json:",omitempty"`
}
- type vol struct {
- Name string
- Mountpoint string
- }
- var volList []vol
-
read := func(b io.ReadCloser) (pluginRequest, error) {
defer b.Close()
var pr pluginRequest
@@ -94,7 +96,7 @@
send(w, err)
return
}
- volList = append(volList, vol{Name: pr.Name})
+ s.volList = append(s.volList, vol{Name: pr.Name, Opts: pr.Opts})
send(w, nil)
})
@@ -111,13 +113,13 @@
return
}
- for i, v := range volList {
+ for i, v := range s.volList {
if v.Name == pr.Name {
if err := os.RemoveAll(hostVolumePath(v.Name)); err != nil {
send(w, fmt.Sprintf(`{"Err": "%v"}`, err))
return
}
- volList = append(volList[:i], volList[i+1:]...)
+ s.volList = append(s.volList[:i], s.volList[i+1:]...)
break
}
}
@@ -213,3 +215,20 @@
out, err = s.d.Cmd("volume", "rm", "foo")
c.Assert(err, checker.IsNil, check.Commentf(out))
}
+
+func (s *DockerExternalVolumeSuiteCompatV1_1) TestExternalVolumeDriverCompatOptionsV1_1(c *check.C) {
+ err := s.d.StartWithBusybox()
+ c.Assert(err, checker.IsNil)
+
+ out, err := s.d.Cmd("volume", "create", "--name", "optvol", "--driver", "test-external-volume-driver", "--opt", "opt1=opt1val", "--opt", "opt2=opt2val")
+ c.Assert(err, checker.IsNil, check.Commentf(out))
+
+ out, err = s.d.Cmd("volume", "inspect", "optvol")
+ c.Assert(err, checker.IsNil, check.Commentf(out))
+
+ c.Assert(s.volList[0].Opts["opt1"], checker.Equals, "opt1val")
+ c.Assert(s.volList[0].Opts["opt2"], checker.Equals, "opt2val")
+
+ out, err = s.d.Cmd("volume", "rm", "optvol")
+ c.Assert(err, checker.IsNil, check.Commentf(out))
+}
diff --git a/integration-cli/docker_utils.go b/integration-cli/docker_utils.go
index 4734c89..9b76892 100644
--- a/integration-cli/docker_utils.go
+++ b/integration-cli/docker_utils.go
@@ -1704,3 +1704,19 @@
c.Assert(status, check.Equals, http.StatusOK)
return body
}
+
+// Run a long running idle task in a background container using the
+// system-specific default image and command.
+func runSleepingContainer(c *check.C, extraArgs ...string) (string, int) {
+ return runSleepingContainerInImage(c, defaultSleepImage, extraArgs...)
+}
+
+// Run a long running idle task in a background container using the specified
+// image and the system-specific command.
+func runSleepingContainerInImage(c *check.C, image string, extraArgs ...string) (string, int) {
+ args := []string{"run", "-d"}
+ args = append(args, extraArgs...)
+ args = append(args, image)
+ args = append(args, defaultSleepCommand...)
+ return dockerCmd(c, args...)
+}
diff --git a/integration-cli/events_utils.go b/integration-cli/events_utils.go
index 8397a57..77ec33d 100644
--- a/integration-cli/events_utils.go
+++ b/integration-cli/events_utils.go
@@ -28,7 +28,13 @@
)
// eventMatcher is a function that tries to match an event input.
-type eventMatcher func(text string) bool
+// It returns true if the event matches and a map with
+// a set of key/value to identify the match.
+type eventMatcher func(text string) (map[string]string, bool)
+
+// eventMatchProcessor is a function to handle an event match.
+// It receives a map of key/value with the information extracted in a match.
+type eventMatchProcessor func(matches map[string]string)
// eventObserver runs an events commands and observes its output.
type eventObserver struct {
@@ -79,13 +85,15 @@
}
// Match tries to match the events output with a given matcher.
-func (e *eventObserver) Match(match eventMatcher) {
+func (e *eventObserver) Match(match eventMatcher, process eventMatchProcessor) {
for e.scanner.Scan() {
text := e.scanner.Text()
e.buffer.WriteString(text)
e.buffer.WriteString("\n")
- match(text)
+ if matches, ok := match(text); ok {
+ process(matches)
+ }
}
err := e.scanner.Err()
@@ -106,7 +114,7 @@
out, _ := dockerCmd(c, "events", "--since", e.startTime, "--until", until)
events := strings.Split(strings.TrimSpace(out), "\n")
for _, e := range events {
- if match(e) {
+ if _, ok := match(e); ok {
foundEvent = true
break
}
@@ -119,22 +127,30 @@
}
// matchEventLine matches a text with the event regular expression.
-// It returns the action and true if the regular expression matches with the given id and event type.
-// It returns an empty string and false if there is no match.
+// It returns the matches and true if the regular expression matches with the given id and event type.
+// It returns an empty map and false if there is no match.
func matchEventLine(id, eventType string, actions map[string]chan bool) eventMatcher {
- return func(text string) bool {
+ return func(text string) (map[string]string, bool) {
matches := parseEventText(text)
if len(matches) == 0 {
- return false
+ return matches, false
}
if matchIDAndEventType(matches, id, eventType) {
- if ch, ok := actions[matches["action"]]; ok {
- close(ch)
- return true
+ if _, ok := actions[matches["action"]]; ok {
+ return matches, true
}
}
- return false
+ return matches, false
+ }
+}
+
+// processEventMatch closes an action channel when an event line matches the expected action.
+func processEventMatch(actions map[string]chan bool) eventMatchProcessor {
+ return func(matches map[string]string) {
+ if ch, ok := actions[matches["action"]]; ok {
+ close(ch)
+ }
}
}
diff --git a/integration-cli/test_vars_unix.go b/integration-cli/test_vars_unix.go
index 1ab8a5c..853889a 100644
--- a/integration-cli/test_vars_unix.go
+++ b/integration-cli/test_vars_unix.go
@@ -7,4 +7,10 @@
isUnixCli = true
expectedFileChmod = "-rw-r--r--"
+
+ // On Unix variants, the busybox image comes with the `top` command which
+ // runs indefinitely while still being interruptible by a signal.
+ defaultSleepImage = "busybox"
)
+
+var defaultSleepCommand = []string{"top"}
diff --git a/integration-cli/test_vars_windows.go b/integration-cli/test_vars_windows.go
index f81ac53..a1b916c 100644
--- a/integration-cli/test_vars_windows.go
+++ b/integration-cli/test_vars_windows.go
@@ -8,4 +8,10 @@
// this is the expected file permission set on windows: gh#11395
expectedFileChmod = "-rwxr-xr-x"
+
+ // On Windows, the busybox image doesn't have the `top` command, so we rely
+ // on `sleep` with a high duration.
+ defaultSleepImage = "busybox"
)
+
+var defaultSleepCommand = []string{"sleep", "60"}
diff --git a/man/config-json.5.md b/man/config-json.5.md
index af274c9..7e0b640 100644
--- a/man/config-json.5.md
+++ b/man/config-json.5.md
@@ -2,7 +2,7 @@
% Docker Community
% JANUARY 2016
# NAME
-HOME/.docker/confg.json - Default Docker configuration file
+HOME/.docker/config.json - Default Docker configuration file
# INTRODUCTION
diff --git a/pkg/authorization/authz.go b/pkg/authorization/authz.go
index c0ef387..8a15b2b 100644
--- a/pkg/authorization/authz.go
+++ b/pkg/authorization/authz.go
@@ -116,7 +116,7 @@
}
}
- rm.Flush()
+ rm.FlushAll()
return nil
}
diff --git a/pkg/authorization/authz_test.go b/pkg/authorization/authz_test.go
index 75c549b..3a6a991 100644
--- a/pkg/authorization/authz_test.go
+++ b/pkg/authorization/authz_test.go
@@ -118,7 +118,7 @@
m.Write([]byte("body"))
m.WriteHeader(500)
- m.Flush()
+ m.FlushAll()
if r.Header().Get("h1") != "v1" {
t.Fatalf("Header value must exists %s", r.Header().Get("h1"))
}
@@ -147,7 +147,7 @@
m.OverrideHeader(overrideHeaderBytes)
m.OverrideBody([]byte("override body"))
m.OverrideStatusCode(404)
- m.Flush()
+ m.FlushAll()
if r.Header().Get("h1") != "v2" {
t.Fatalf("Header value must exists %s", r.Header().Get("h1"))
}
diff --git a/pkg/authorization/response.go b/pkg/authorization/response.go
index 8acbcd1..abe3c9f 100644
--- a/pkg/authorization/response.go
+++ b/pkg/authorization/response.go
@@ -5,6 +5,7 @@
"bytes"
"encoding/json"
"fmt"
+ "github.com/Sirupsen/logrus"
"net"
"net/http"
)
@@ -12,6 +13,8 @@
// ResponseModifier allows authorization plugins to read and modify the content of the http.response
type ResponseModifier interface {
http.ResponseWriter
+ http.Flusher
+ http.CloseNotifier
// RawBody returns the current http content
RawBody() []byte
@@ -32,7 +35,10 @@
OverrideStatusCode(statusCode int)
// Flush flushes all data to the HTTP response
- Flush() error
+ FlushAll() error
+
+ // Hijacked indicates the response has been hijacked by the Docker daemon
+ Hijacked() bool
}
// NewResponseModifier creates a wrapper to an http.ResponseWriter to allow inspecting and modifying the content
@@ -44,7 +50,10 @@
// the http request/response from docker daemon
type responseModifier struct {
// The original response writer
- rw http.ResponseWriter
+ rw http.ResponseWriter
+
+ r *http.Request
+
status int
// body holds the response body
body []byte
@@ -52,15 +61,34 @@
header http.Header
// statusCode holds the response status code
statusCode int
+ // hijacked indicates the request has been hijacked
+ hijacked bool
+}
+
+func (rm *responseModifier) Hijacked() bool {
+ return rm.hijacked
}
// WriterHeader stores the http status code
func (rm *responseModifier) WriteHeader(s int) {
+
+ // Use original request if hijacked
+ if rm.hijacked {
+ rm.rw.WriteHeader(s)
+ return
+ }
+
rm.statusCode = s
}
// Header returns the internal http header
func (rm *responseModifier) Header() http.Header {
+
+ // Use original header if hijacked
+ if rm.hijacked {
+ return rm.rw.Header()
+ }
+
return rm.header
}
@@ -90,6 +118,11 @@
// Write stores the byte array inside content
func (rm *responseModifier) Write(b []byte) (int, error) {
+
+ if rm.hijacked {
+ return rm.rw.Write(b)
+ }
+
rm.body = append(rm.body, b...)
return len(b), nil
}
@@ -109,6 +142,10 @@
// Hijack returns the internal connection of the wrapped http.ResponseWriter
func (rm *responseModifier) Hijack() (net.Conn, *bufio.ReadWriter, error) {
+
+ rm.hijacked = true
+ rm.FlushAll()
+
hijacker, ok := rm.rw.(http.Hijacker)
if !ok {
return nil, nil, fmt.Errorf("Internal reponse writer doesn't support the Hijacker interface")
@@ -116,8 +153,30 @@
return hijacker.Hijack()
}
-// Flush flushes all data to the HTTP response
-func (rm *responseModifier) Flush() error {
+// CloseNotify uses the internal close notify API of the wrapped http.ResponseWriter
+func (rm *responseModifier) CloseNotify() <-chan bool {
+ closeNotifier, ok := rm.rw.(http.CloseNotifier)
+ if !ok {
+ logrus.Errorf("Internal reponse writer doesn't support the CloseNotifier interface")
+ return nil
+ }
+ return closeNotifier.CloseNotify()
+}
+
+// Flush uses the internal flush API of the wrapped http.ResponseWriter
+func (rm *responseModifier) Flush() {
+ flusher, ok := rm.rw.(http.Flusher)
+ if !ok {
+ logrus.Errorf("Internal reponse writer doesn't support the Flusher interface")
+ return
+ }
+
+ rm.FlushAll()
+ flusher.Flush()
+}
+
+// FlushAll flushes all data to the HTTP response
+func (rm *responseModifier) FlushAll() error {
// Copy the status code
if rm.statusCode > 0 {
rm.rw.WriteHeader(rm.statusCode)
@@ -130,7 +189,15 @@
}
}
- // Write body
- _, err := rm.rw.Write(rm.body)
+ var err error
+ if len(rm.body) > 0 {
+ // Write body
+ _, err = rm.rw.Write(rm.body)
+ }
+
+ // Clean previous data
+ rm.body = nil
+ rm.statusCode = 0
+ rm.header = http.Header{}
return err
}
diff --git a/pkg/urlutil/urlutil.go b/pkg/urlutil/urlutil.go
index f7094b1..1135a4c 100644
--- a/pkg/urlutil/urlutil.go
+++ b/pkg/urlutil/urlutil.go
@@ -11,7 +11,7 @@
validPrefixes = map[string][]string{
"url": {"http://", "https://"},
"git": {"git://", "github.com/", "git@"},
- "transport": {"tcp://", "udp://", "unix://"},
+ "transport": {"tcp://", "tcp+tls://", "udp://", "unix://"},
}
urlPathWithFragmentSuffix = regexp.MustCompile(".git(?:#.+)?$")
)
@@ -35,7 +35,7 @@
return IsURL(str) || strings.HasPrefix(str, "git://") || strings.HasPrefix(str, "git@")
}
-// IsTransportURL returns true if the provided str is a transport (tcp, udp, unix) URL.
+// IsTransportURL returns true if the provided str is a transport (tcp, tcp+tls, udp, unix) URL.
func IsTransportURL(str string) bool {
return checkURL(str, "transport")
}
diff --git a/pkg/urlutil/urlutil_test.go b/pkg/urlutil/urlutil_test.go
index bb89d8b..86d48cf 100644
--- a/pkg/urlutil/urlutil_test.go
+++ b/pkg/urlutil/urlutil_test.go
@@ -18,6 +18,12 @@
invalidGitUrls = []string{
"http://github.com/docker/docker.git:#branch",
}
+ transportUrls = []string{
+ "tcp://example.com",
+ "tcp+tls://example.com",
+ "udp://example.com",
+ "unix:///example",
+ }
)
func TestValidGitTransport(t *testing.T) {
@@ -53,3 +59,11 @@
}
}
}
+
+func TestIsTransport(t *testing.T) {
+ for _, url := range transportUrls {
+ if IsTransportURL(url) == false {
+ t.Fatalf("%q should be detected as valid Transport url", url)
+ }
+ }
+}
diff --git a/project/PACKAGERS.md b/project/PACKAGERS.md
index 780e961..86f05ec 100644
--- a/project/PACKAGERS.md
+++ b/project/PACKAGERS.md
@@ -44,7 +44,8 @@
To build Docker, you will need the following:
* A recent version of Git and Mercurial
-* Go version 1.4 or later
+* Go version 1.4 or later (Go version 1.5 or later required for hardware signing
+ support in Docker Content Trust)
* A clean checkout of the source added to a valid [Go
workspace](https://golang.org/doc/code.html#Workspaces) under the path
*src/github.com/docker/docker* (unless you plan to use `AUTO_GOPATH`,
diff --git a/vendor/src/github.com/docker/libnetwork/CHANGELOG.md b/vendor/src/github.com/docker/libnetwork/CHANGELOG.md
index a47d5fa..2c66eaa 100644
--- a/vendor/src/github.com/docker/libnetwork/CHANGELOG.md
+++ b/vendor/src/github.com/docker/libnetwork/CHANGELOG.md
@@ -1,5 +1,13 @@
# Changelog
+## 0.6.1-rc2 (2016-02-09)
+- Fixes https://github.com/docker/docker/issues/20132
+- Fixes https://github.com/docker/docker/issues/20140
+- Fixes https://github.com/docker/docker/issues/20019
+
+## 0.6.1-rc1 (2016-02-05)
+- Fixes https://github.com/docker/docker/issues/20026
+
## 0.6.0-rc7 (2016-02-01)
- Allow inter-network connections via exposed ports
diff --git a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go
index f5ceed2..16d6158 100644
--- a/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go
+++ b/vendor/src/github.com/docker/libnetwork/drivers/bridge/setup_ip_tables.go
@@ -115,7 +115,7 @@
return iptables.ProgramChain(filterChain, config.BridgeName, hairpinMode, false)
})
- n.portMapper.SetIptablesChain(filterChain, n.getNetworkBridgeName())
+ n.portMapper.SetIptablesChain(natChain, n.getNetworkBridgeName())
}
if err := ensureJumpRule("FORWARD", IsolationChain); err != nil {
@@ -148,6 +148,9 @@
if err := programChainRule(natRule, "NAT", enable); err != nil {
return err
}
+ }
+
+ if ipmasq && !hairpin {
if err := programChainRule(skipDNAT, "SKIP DNAT", enable); err != nil {
return err
}
diff --git a/vendor/src/github.com/docker/libnetwork/iptables/iptables.go b/vendor/src/github.com/docker/libnetwork/iptables/iptables.go
index b972922..ca07893 100644
--- a/vendor/src/github.com/docker/libnetwork/iptables/iptables.go
+++ b/vendor/src/github.com/docker/libnetwork/iptables/iptables.go
@@ -325,9 +325,11 @@
if err == nil || !strings.Contains(err.Error(), "was not provided by any .service files") {
return output, err
}
-
}
+ return raw(args...)
+}
+func raw(args ...string) ([]byte, error) {
if err := initCheck(); err != nil {
return nil, err
}
@@ -362,6 +364,15 @@
return nil
}
+// RawCombinedOutputNative behave as RawCombinedOutput with the difference it
+// will always invoke `iptables` binary
+func RawCombinedOutputNative(args ...string) error {
+ if output, err := raw(args...); err != nil || len(output) != 0 {
+ return fmt.Errorf("%s (%v)", string(output), err)
+ }
+ return nil
+}
+
// ExistChain checks if a chain exists
func ExistChain(chain string, table Table) bool {
if _, err := Raw("-t", string(table), "-L", chain); err == nil {
diff --git a/vendor/src/github.com/docker/libnetwork/resolver.go b/vendor/src/github.com/docker/libnetwork/resolver.go
index a839298..e0a5e49 100644
--- a/vendor/src/github.com/docker/libnetwork/resolver.go
+++ b/vendor/src/github.com/docker/libnetwork/resolver.go
@@ -95,7 +95,7 @@
}
for _, rule := range rules {
- r.err = iptables.RawCombinedOutput(rule...)
+ r.err = iptables.RawCombinedOutputNative(rule...)
if r.err != nil {
return
}
@@ -229,6 +229,7 @@
resp, _, err = c.Exchange(query, addr)
if err == nil {
+ resp.Compress = true
break
}
log.Errorf("external resolution failed, %s", err)
diff --git a/vendor/src/github.com/docker/libnetwork/store.go b/vendor/src/github.com/docker/libnetwork/store.go
index 8924880..dbfdaa0 100644
--- a/vendor/src/github.com/docker/libnetwork/store.go
+++ b/vendor/src/github.com/docker/libnetwork/store.go
@@ -104,7 +104,8 @@
ec := &endpointCnt{n: n}
err = store.GetObject(datastore.Key(ec.Key()...), ec)
if err != nil {
- return nil, fmt.Errorf("could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err)
+ log.Warnf("Could not find endpoint count key %s for network %s while listing: %v", datastore.Key(ec.Key()...), n.Name(), err)
+ continue
}
n.epCnt = ec
diff --git a/volume/drivers/adapter.go b/volume/drivers/adapter.go
index 98e4c11..064dbff 100644
--- a/volume/drivers/adapter.go
+++ b/volume/drivers/adapter.go
@@ -15,7 +15,20 @@
}
func (a *volumeDriverAdapter) Create(name string, opts map[string]string) (volume.Volume, error) {
- err := a.proxy.Create(name, opts)
+ // First try a Get. For drivers that support Get this will return any
+ // existing volume.
+ v, err := a.proxy.Get(name)
+ if v != nil {
+ return &volumeAdapter{
+ proxy: a.proxy,
+ name: v.Name,
+ driverName: a.Name(),
+ eMount: v.Mountpoint,
+ }, nil
+ }
+
+ // Driver didn't support Get or volume didn't exist. Perform Create.
+ err = a.proxy.Create(name, opts)
if err != nil {
return nil, err
}
diff --git a/volume/store/store.go b/volume/store/store.go
index b871902..0d227ae 100644
--- a/volume/store/store.go
+++ b/volume/store/store.go
@@ -192,9 +192,6 @@
return nil, &OpErr{Op: "create", Name: name, Err: err}
}
- if v, err := vd.Get(name); err == nil {
- return v, nil
- }
return vd.Create(name, opts)
}