commit
faa90e9378
7 changed files with 218 additions and 7 deletions
|
@ -22,6 +22,7 @@ Upgrading from Docker 1.13.1 to 17.03.0 is expected to be simple and low-risk.
|
||||||
### Contrib
|
### Contrib
|
||||||
|
|
||||||
* Update various `bash` and `zsh` completion scripts [#30823](https://github.com/docker/docker/pull/30823), [#30945](https://github.com/docker/docker/pull/30945) and more...
|
* Update various `bash` and `zsh` completion scripts [#30823](https://github.com/docker/docker/pull/30823), [#30945](https://github.com/docker/docker/pull/30945) and more...
|
||||||
|
* Block obsolete socket families in default seccomp profile - mitigates unpatched kernels' CVE-2017-6074 [#29076](https://github.com/docker/docker/pull/29076)
|
||||||
|
|
||||||
### Networking
|
### Networking
|
||||||
|
|
||||||
|
@ -36,6 +37,14 @@ Upgrading from Docker 1.13.1 to 17.03.0 is expected to be simple and low-risk.
|
||||||
|
|
||||||
* Fix a deadlock in docker logs [#30223](https://github.com/docker/docker/pull/30223)
|
* Fix a deadlock in docker logs [#30223](https://github.com/docker/docker/pull/30223)
|
||||||
* Fix cpu spin waiting for log write events [#31070](https://github.com/docker/docker/pull/31070)
|
* Fix cpu spin waiting for log write events [#31070](https://github.com/docker/docker/pull/31070)
|
||||||
|
* Fix a possible crash when using journald [#31231](https://github.com/docker/docker/pull/31231) [#31263](https://github.com/docker/docker/pull/31231)
|
||||||
|
* Fix a panic on close of nil channel [#31274](https://github.com/docker/docker/pull/31274)
|
||||||
|
* Fix duplicate mount point for `--volumes-from` in `docker run` [#29563](https://github.com/docker/docker/pull/29563)
|
||||||
|
* Fix `--cache-from` does not cache last step [#31189](https://github.com/docker/docker/pull/31189)
|
||||||
|
|
||||||
|
### Swarm Mode
|
||||||
|
|
||||||
|
* Shutdown leaks an error when the container was never started [#31279](https://github.com/docker/docker/pull/31279)
|
||||||
|
|
||||||
### Swarm Mode
|
### Swarm Mode
|
||||||
|
|
||||||
|
|
|
@ -215,7 +215,7 @@ func isValidParent(img, parent *image.Image) bool {
|
||||||
if len(parent.History) >= len(img.History) {
|
if len(parent.History) >= len(img.History) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if len(parent.RootFS.DiffIDs) >= len(img.RootFS.DiffIDs) {
|
if len(parent.RootFS.DiffIDs) > len(img.RootFS.DiffIDs) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -323,8 +323,10 @@ func (r *controller) Shutdown(ctx context.Context) error {
|
||||||
|
|
||||||
// remove container from service binding
|
// remove container from service binding
|
||||||
if err := r.adapter.deactivateServiceBinding(); err != nil {
|
if err := r.adapter.deactivateServiceBinding(); err != nil {
|
||||||
log.G(ctx).WithError(err).Errorf("failed to deactivate service binding for container %s", r.adapter.container.name())
|
log.G(ctx).WithError(err).Warningf("failed to deactivate service binding for container %s", r.adapter.container.name())
|
||||||
return err
|
// Don't return an error here, because failure to deactivate
|
||||||
|
// the service binding is expected if the container was never
|
||||||
|
// started.
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := r.adapter.shutdown(ctx); err != nil {
|
if err := r.adapter.shutdown(ctx); err != nil {
|
||||||
|
|
|
@ -237,7 +237,10 @@ drain:
|
||||||
|
|
||||||
// free(NULL) is safe
|
// free(NULL) is safe
|
||||||
C.free(unsafe.Pointer(oldCursor))
|
C.free(unsafe.Pointer(oldCursor))
|
||||||
C.sd_journal_get_cursor(j, &cursor)
|
if C.sd_journal_get_cursor(j, &cursor) != 0 {
|
||||||
|
// ensure that we won't be freeing an address that's invalid
|
||||||
|
cursor = nil
|
||||||
|
}
|
||||||
return cursor
|
return cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -245,6 +248,9 @@ func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.Re
|
||||||
s.readers.mu.Lock()
|
s.readers.mu.Lock()
|
||||||
s.readers.readers[logWatcher] = logWatcher
|
s.readers.readers[logWatcher] = logWatcher
|
||||||
s.readers.mu.Unlock()
|
s.readers.mu.Unlock()
|
||||||
|
|
||||||
|
newCursor := make(chan *C.char)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
// Keep copying journal data out until we're notified to stop
|
// Keep copying journal data out until we're notified to stop
|
||||||
// or we hit an error.
|
// or we hit an error.
|
||||||
|
@ -264,8 +270,8 @@ func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.Re
|
||||||
s.readers.mu.Lock()
|
s.readers.mu.Lock()
|
||||||
delete(s.readers.readers, logWatcher)
|
delete(s.readers.readers, logWatcher)
|
||||||
s.readers.mu.Unlock()
|
s.readers.mu.Unlock()
|
||||||
C.sd_journal_close(j)
|
|
||||||
close(logWatcher.Msg)
|
close(logWatcher.Msg)
|
||||||
|
newCursor <- cursor
|
||||||
}()
|
}()
|
||||||
// Wait until we're told to stop.
|
// Wait until we're told to stop.
|
||||||
select {
|
select {
|
||||||
|
@ -274,6 +280,8 @@ func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.Re
|
||||||
C.close(pfd[1])
|
C.close(pfd[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cursor = <-newCursor
|
||||||
|
|
||||||
return cursor
|
return cursor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -298,9 +306,9 @@ func (s *journald) readLogs(logWatcher *logger.LogWatcher, config logger.ReadCon
|
||||||
following := false
|
following := false
|
||||||
defer func(pfollowing *bool) {
|
defer func(pfollowing *bool) {
|
||||||
if !*pfollowing {
|
if !*pfollowing {
|
||||||
C.sd_journal_close(j)
|
|
||||||
close(logWatcher.Msg)
|
close(logWatcher.Msg)
|
||||||
}
|
}
|
||||||
|
C.sd_journal_close(j)
|
||||||
}(&following)
|
}(&following)
|
||||||
// Remove limits on the size of data items that we'll retrieve.
|
// Remove limits on the size of data items that we'll retrieve.
|
||||||
rc = C.sd_journal_set_data_threshold(j, C.size_t(0))
|
rc = C.sd_journal_set_data_threshold(j, C.size_t(0))
|
||||||
|
|
|
@ -85,6 +85,15 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
dereferenceIfExists := func(destination string) {
|
||||||
|
if v, ok := mountPoints[destination]; ok {
|
||||||
|
logrus.Debugf("Duplicate mount point '%s'", destination)
|
||||||
|
if v.Volume != nil {
|
||||||
|
daemon.volumes.Dereference(v.Volume, container.ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 1. Read already configured mount points.
|
// 1. Read already configured mount points.
|
||||||
for destination, point := range container.MountPoints {
|
for destination, point := range container.MountPoints {
|
||||||
mountPoints[destination] = point
|
mountPoints[destination] = point
|
||||||
|
@ -121,7 +130,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
|
||||||
}
|
}
|
||||||
cp.Volume = v
|
cp.Volume = v
|
||||||
}
|
}
|
||||||
|
dereferenceIfExists(cp.Destination)
|
||||||
mountPoints[cp.Destination] = cp
|
mountPoints[cp.Destination] = cp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,6 +164,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
|
||||||
}
|
}
|
||||||
|
|
||||||
binds[bind.Destination] = true
|
binds[bind.Destination] = true
|
||||||
|
dereferenceIfExists(bind.Destination)
|
||||||
mountPoints[bind.Destination] = bind
|
mountPoints[bind.Destination] = bind
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -199,6 +209,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
|
||||||
}
|
}
|
||||||
|
|
||||||
binds[mp.Destination] = true
|
binds[mp.Destination] = true
|
||||||
|
dereferenceIfExists(mp.Destination)
|
||||||
mountPoints[mp.Destination] = mp
|
mountPoints[mp.Destination] = mp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7081,6 +7081,27 @@ func (s *DockerSuite) TestBuildWithFailure(c *check.C) {
|
||||||
c.Assert(stdout, checker.Not(checker.Contains), "Step 2/2 : RUN nobody")
|
c.Assert(stdout, checker.Not(checker.Contains), "Step 2/2 : RUN nobody")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *DockerSuite) TestBuildCacheFromEqualDiffIDsLength(c *check.C) {
|
||||||
|
dockerfile := `
|
||||||
|
FROM busybox
|
||||||
|
RUN echo "test"
|
||||||
|
ENTRYPOINT ["sh"]`
|
||||||
|
ctx, err := fakeContext(dockerfile, map[string]string{
|
||||||
|
"Dockerfile": dockerfile,
|
||||||
|
})
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
defer ctx.Close()
|
||||||
|
|
||||||
|
id1, err := buildImageFromContext("build1", ctx, true)
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
|
||||||
|
// rebuild with cache-from
|
||||||
|
id2, out, err := buildImageFromContextWithOut("build2", ctx, true, "--cache-from=build1")
|
||||||
|
c.Assert(err, checker.IsNil)
|
||||||
|
c.Assert(id1, checker.Equals, id2)
|
||||||
|
c.Assert(strings.Count(out, "Using cache"), checker.Equals, 2)
|
||||||
|
}
|
||||||
|
|
||||||
func (s *DockerSuite) TestBuildCacheFrom(c *check.C) {
|
func (s *DockerSuite) TestBuildCacheFrom(c *check.C) {
|
||||||
testRequires(c, DaemonIsLinux) // All tests that do save are skipped in windows
|
testRequires(c, DaemonIsLinux) // All tests that do save are skipped in windows
|
||||||
dockerfile := `
|
dockerfile := `
|
||||||
|
|
|
@ -3,6 +3,7 @@ package main
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
@ -425,3 +426,162 @@ func (s *DockerSuite) TestVolumeCliInspectWithVolumeOpts(c *check.C) {
|
||||||
c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k2, v2))
|
c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k2, v2))
|
||||||
c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k3, v3))
|
c.Assert(strings.TrimSpace(out), checker.Contains, fmt.Sprintf("%s:%s", k3, v3))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Test case (1) for 21845: duplicate targets for --volumes-from
|
||||||
|
func (s *DockerSuite) TestDuplicateMountpointsForVolumesFrom(c *check.C) {
|
||||||
|
testRequires(c, DaemonIsLinux)
|
||||||
|
|
||||||
|
image := "vimage"
|
||||||
|
_, err := buildImage(
|
||||||
|
image,
|
||||||
|
`
|
||||||
|
FROM busybox
|
||||||
|
VOLUME ["/tmp/data"]
|
||||||
|
`,
|
||||||
|
true)
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
|
dockerCmd(c, "run", "--name=data1", image, "true")
|
||||||
|
dockerCmd(c, "run", "--name=data2", image, "true")
|
||||||
|
|
||||||
|
out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
|
||||||
|
data1 := strings.TrimSpace(out)
|
||||||
|
c.Assert(data1, checker.Not(checker.Equals), "")
|
||||||
|
|
||||||
|
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
|
||||||
|
data2 := strings.TrimSpace(out)
|
||||||
|
c.Assert(data2, checker.Not(checker.Equals), "")
|
||||||
|
|
||||||
|
// Both volume should exist
|
||||||
|
out, _ = dockerCmd(c, "volume", "ls", "-q")
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Contains, data1)
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Contains, data2)
|
||||||
|
|
||||||
|
out, _, err = dockerCmdWithError("run", "--name=app", "--volumes-from=data1", "--volumes-from=data2", "-d", "busybox", "top")
|
||||||
|
c.Assert(err, checker.IsNil, check.Commentf("Out: %s", out))
|
||||||
|
|
||||||
|
// Only the second volume will be referenced, this is backward compatible
|
||||||
|
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Equals, data2)
|
||||||
|
|
||||||
|
dockerCmd(c, "rm", "-f", "-v", "app")
|
||||||
|
dockerCmd(c, "rm", "-f", "-v", "data1")
|
||||||
|
dockerCmd(c, "rm", "-f", "-v", "data2")
|
||||||
|
|
||||||
|
// Both volume should not exist
|
||||||
|
out, _ = dockerCmd(c, "volume", "ls", "-q")
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test case (2) for 21845: duplicate targets for --volumes-from and -v (bind)
|
||||||
|
func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndBind(c *check.C) {
|
||||||
|
testRequires(c, DaemonIsLinux)
|
||||||
|
|
||||||
|
image := "vimage"
|
||||||
|
_, err := buildImage(image,
|
||||||
|
`
|
||||||
|
FROM busybox
|
||||||
|
VOLUME ["/tmp/data"]
|
||||||
|
`,
|
||||||
|
true)
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
|
dockerCmd(c, "run", "--name=data1", image, "true")
|
||||||
|
dockerCmd(c, "run", "--name=data2", image, "true")
|
||||||
|
|
||||||
|
out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
|
||||||
|
data1 := strings.TrimSpace(out)
|
||||||
|
c.Assert(data1, checker.Not(checker.Equals), "")
|
||||||
|
|
||||||
|
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
|
||||||
|
data2 := strings.TrimSpace(out)
|
||||||
|
c.Assert(data2, checker.Not(checker.Equals), "")
|
||||||
|
|
||||||
|
// Both volume should exist
|
||||||
|
out, _ = dockerCmd(c, "volume", "ls", "-q")
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Contains, data1)
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Contains, data2)
|
||||||
|
|
||||||
|
out, _, err = dockerCmdWithError("run", "--name=app", "--volumes-from=data1", "--volumes-from=data2", "-v", "/tmp/data:/tmp/data", "-d", "busybox", "top")
|
||||||
|
c.Assert(err, checker.IsNil, check.Commentf("Out: %s", out))
|
||||||
|
|
||||||
|
// No volume will be referenced (mount is /tmp/data), this is backward compatible
|
||||||
|
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
|
||||||
|
|
||||||
|
dockerCmd(c, "rm", "-f", "-v", "app")
|
||||||
|
dockerCmd(c, "rm", "-f", "-v", "data1")
|
||||||
|
dockerCmd(c, "rm", "-f", "-v", "data2")
|
||||||
|
|
||||||
|
// Both volume should not exist
|
||||||
|
out, _ = dockerCmd(c, "volume", "ls", "-q")
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test case (3) for 21845: duplicate targets for --volumes-from and `Mounts` (API only)
|
||||||
|
func (s *DockerSuite) TestDuplicateMountpointsForVolumesFromAndMounts(c *check.C) {
|
||||||
|
testRequires(c, DaemonIsLinux)
|
||||||
|
|
||||||
|
image := "vimage"
|
||||||
|
_, err := buildImage(image,
|
||||||
|
`
|
||||||
|
FROM busybox
|
||||||
|
VOLUME ["/tmp/data"]
|
||||||
|
`,
|
||||||
|
true)
|
||||||
|
c.Assert(err, check.IsNil)
|
||||||
|
|
||||||
|
dockerCmd(c, "run", "--name=data1", image, "true")
|
||||||
|
dockerCmd(c, "run", "--name=data2", image, "true")
|
||||||
|
|
||||||
|
out, _ := dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data1")
|
||||||
|
data1 := strings.TrimSpace(out)
|
||||||
|
c.Assert(data1, checker.Not(checker.Equals), "")
|
||||||
|
|
||||||
|
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "data2")
|
||||||
|
data2 := strings.TrimSpace(out)
|
||||||
|
c.Assert(data2, checker.Not(checker.Equals), "")
|
||||||
|
|
||||||
|
// Both volume should exist
|
||||||
|
out, _ = dockerCmd(c, "volume", "ls", "-q")
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Contains, data1)
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Contains, data2)
|
||||||
|
|
||||||
|
// Mounts is available in API
|
||||||
|
status, body, err := sockRequest("POST", "/containers/create?name=app", map[string]interface{}{
|
||||||
|
"Image": "busybox",
|
||||||
|
"Cmd": []string{"top"},
|
||||||
|
"HostConfig": map[string]interface{}{
|
||||||
|
"VolumesFrom": []string{
|
||||||
|
"data1",
|
||||||
|
"data2",
|
||||||
|
},
|
||||||
|
"Mounts": []map[string]interface{}{
|
||||||
|
{
|
||||||
|
"Type": "bind",
|
||||||
|
"Source": "/tmp/data",
|
||||||
|
"Target": "/tmp/data",
|
||||||
|
},
|
||||||
|
}},
|
||||||
|
})
|
||||||
|
|
||||||
|
c.Assert(err, checker.IsNil, check.Commentf(string(body)))
|
||||||
|
c.Assert(status, checker.Equals, http.StatusCreated, check.Commentf(string(body)))
|
||||||
|
|
||||||
|
// No volume will be referenced (mount is /tmp/data), this is backward compatible
|
||||||
|
out, _ = dockerCmd(c, "inspect", "--format", "{{(index .Mounts 0).Name}}", "app")
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
|
||||||
|
|
||||||
|
dockerCmd(c, "rm", "-f", "-v", "app")
|
||||||
|
dockerCmd(c, "rm", "-f", "-v", "data1")
|
||||||
|
dockerCmd(c, "rm", "-f", "-v", "data2")
|
||||||
|
|
||||||
|
// Both volume should not exist
|
||||||
|
out, _ = dockerCmd(c, "volume", "ls", "-q")
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data1)
|
||||||
|
c.Assert(strings.TrimSpace(out), checker.Not(checker.Contains), data2)
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue