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
|
||||
|
||||
* 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
|
||||
|
||||
|
@ -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 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
|
||||
|
||||
|
|
|
@ -215,7 +215,7 @@ func isValidParent(img, parent *image.Image) bool {
|
|||
if len(parent.History) >= len(img.History) {
|
||||
return false
|
||||
}
|
||||
if len(parent.RootFS.DiffIDs) >= len(img.RootFS.DiffIDs) {
|
||||
if len(parent.RootFS.DiffIDs) > len(img.RootFS.DiffIDs) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
|
@ -323,8 +323,10 @@ func (r *controller) Shutdown(ctx context.Context) error {
|
|||
|
||||
// remove container from service binding
|
||||
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())
|
||||
return err
|
||||
log.G(ctx).WithError(err).Warningf("failed to deactivate service binding for container %s", r.adapter.container.name())
|
||||
// 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 {
|
||||
|
|
|
@ -237,7 +237,10 @@ drain:
|
|||
|
||||
// free(NULL) is safe
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -245,6 +248,9 @@ func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.Re
|
|||
s.readers.mu.Lock()
|
||||
s.readers.readers[logWatcher] = logWatcher
|
||||
s.readers.mu.Unlock()
|
||||
|
||||
newCursor := make(chan *C.char)
|
||||
|
||||
go func() {
|
||||
// Keep copying journal data out until we're notified to stop
|
||||
// or we hit an error.
|
||||
|
@ -264,8 +270,8 @@ func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.Re
|
|||
s.readers.mu.Lock()
|
||||
delete(s.readers.readers, logWatcher)
|
||||
s.readers.mu.Unlock()
|
||||
C.sd_journal_close(j)
|
||||
close(logWatcher.Msg)
|
||||
newCursor <- cursor
|
||||
}()
|
||||
// Wait until we're told to stop.
|
||||
select {
|
||||
|
@ -274,6 +280,8 @@ func (s *journald) followJournal(logWatcher *logger.LogWatcher, config logger.Re
|
|||
C.close(pfd[1])
|
||||
}
|
||||
|
||||
cursor = <-newCursor
|
||||
|
||||
return cursor
|
||||
}
|
||||
|
||||
|
@ -298,9 +306,9 @@ func (s *journald) readLogs(logWatcher *logger.LogWatcher, config logger.ReadCon
|
|||
following := false
|
||||
defer func(pfollowing *bool) {
|
||||
if !*pfollowing {
|
||||
C.sd_journal_close(j)
|
||||
close(logWatcher.Msg)
|
||||
}
|
||||
C.sd_journal_close(j)
|
||||
}(&following)
|
||||
// Remove limits on the size of data items that we'll retrieve.
|
||||
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.
|
||||
for destination, point := range container.MountPoints {
|
||||
mountPoints[destination] = point
|
||||
|
@ -121,7 +130,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
|
|||
}
|
||||
cp.Volume = v
|
||||
}
|
||||
|
||||
dereferenceIfExists(cp.Destination)
|
||||
mountPoints[cp.Destination] = cp
|
||||
}
|
||||
}
|
||||
|
@ -155,6 +164,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
|
|||
}
|
||||
|
||||
binds[bind.Destination] = true
|
||||
dereferenceIfExists(bind.Destination)
|
||||
mountPoints[bind.Destination] = bind
|
||||
}
|
||||
|
||||
|
@ -199,6 +209,7 @@ func (daemon *Daemon) registerMountPoints(container *container.Container, hostCo
|
|||
}
|
||||
|
||||
binds[mp.Destination] = true
|
||||
dereferenceIfExists(mp.Destination)
|
||||
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")
|
||||
}
|
||||
|
||||
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) {
|
||||
testRequires(c, DaemonIsLinux) // All tests that do save are skipped in windows
|
||||
dockerfile := `
|
||||
|
|
|
@ -3,6 +3,7 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"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", 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