From b4683327074d193428c724b153e8848ef2068c1d Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Thu, 7 Jan 2016 21:38:38 -0500 Subject: [PATCH] On create, copy image data for named volumes. Signed-off-by: Brian Goff --- daemon/create_unix.go | 23 +++++++++++++++++------ integration-cli/docker_cli_run_test.go | 16 +++++++++++++++- volume/store/store.go | 17 +++++++++++++++++ 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/daemon/create_unix.go b/daemon/create_unix.go index 0f2f4d0270..1701fcfb5b 100644 --- a/daemon/create_unix.go +++ b/daemon/create_unix.go @@ -6,6 +6,7 @@ import ( "os" "path/filepath" + "github.com/Sirupsen/logrus" "github.com/docker/docker/container" derr "github.com/docker/docker/errors" "github.com/docker/docker/image" @@ -60,14 +61,24 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain return err } - // never attempt to copy existing content in a container FS to a shared volume - if v.DriverName() == volume.DefaultDriverName { - if err := container.CopyImagePathContent(v, destination); err != nil { - return err - } + container.AddMountPointWithVolume(destination, v, true) + } + return daemon.populateVolumes(container) +} + +// populateVolumes copies data from the container's rootfs into the volume for non-binds. +// this is only called when the container is created. +func (daemon *Daemon) populateVolumes(c *container.Container) error { + for _, mnt := range c.MountPoints { + // skip binds and volumes referenced by other containers (ie, volumes-from) + if mnt.Driver == "" || mnt.Volume == nil || len(daemon.volumes.Refs(mnt.Volume)) > 1 { + continue } - container.AddMountPointWithVolume(destination, v, true) + logrus.Debugf("copying image data from %s:%s, to %s", c.ID, mnt.Destination, mnt.Name) + if err := c.CopyImagePathContent(mnt.Volume, mnt.Destination); err != nil { + return err + } } return nil } diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index edc331dc05..3b27c779cf 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -3931,5 +3931,19 @@ func (s *DockerSuite) TestRunNamedVolumesMountedAsShared(c *check.C) { if expected := "Invalid volume specification"; !strings.Contains(out, expected) { c.Fatalf(`Expected %q in output; got: %s`, expected, out) } - +} + +func (s *DockerSuite) TestRunNamedVolumeCopyImageData(c *check.C) { + testRequires(c, DaemonIsLinux) + + testImg := "testvolumecopy" + _, err := buildImage(testImg, ` + FROM busybox + RUN mkdir -p /foo && echo hello > /foo/hello + `, true) + c.Assert(err, check.IsNil) + + dockerCmd(c, "run", "-v", "foo:/foo", testImg) + out, _ := dockerCmd(c, "run", "-v", "foo:/foo", "busybox", "cat", "/foo/hello") + c.Assert(strings.TrimSpace(out), check.Equals, "hello") } diff --git a/volume/store/store.go b/volume/store/store.go index e85f542bff..9811fd904a 100644 --- a/volume/store/store.go +++ b/volume/store/store.go @@ -296,6 +296,23 @@ func (s *VolumeStore) Dereference(v volume.Volume, ref string) { s.globalLock.Unlock() } +// Refs gets the current list of refs for the given volume +func (s *VolumeStore) Refs(v volume.Volume) []string { + s.locks.Lock(v.Name()) + defer s.locks.Unlock(v.Name()) + + s.globalLock.Lock() + defer s.globalLock.Unlock() + refs, exists := s.refs[v.Name()] + if !exists { + return nil + } + + refsOut := make([]string, len(refs)) + copy(refsOut, refs) + return refsOut +} + // FilterByDriver returns the available volumes filtered by driver name func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) { vd, err := volumedrivers.GetDriver(name)