Merge pull request #31266 from vieux/17.03-cherry

17.03 cherry-picks
This commit is contained in:
Victor Vieux 2017-02-23 02:02:52 -08:00 committed by GitHub
commit faa90e9378
7 changed files with 218 additions and 7 deletions

View file

@ -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

View file

@ -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
} }

View file

@ -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 {

View file

@ -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))

View file

@ -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
} }

View file

@ -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 := `

View file

@ -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)
}