On create, copy image data for named volumes.
| ... | ... |
@@ -6,6 +6,7 @@ import ( |
| 6 | 6 |
"os" |
| 7 | 7 |
"path/filepath" |
| 8 | 8 |
|
| 9 |
+ "github.com/Sirupsen/logrus" |
|
| 9 | 10 |
"github.com/docker/docker/container" |
| 10 | 11 |
derr "github.com/docker/docker/errors" |
| 11 | 12 |
"github.com/docker/docker/image" |
| ... | ... |
@@ -60,14 +61,24 @@ func (daemon *Daemon) createContainerPlatformSpecificSettings(container *contain |
| 60 | 60 |
return err |
| 61 | 61 |
} |
| 62 | 62 |
|
| 63 |
- // never attempt to copy existing content in a container FS to a shared volume |
|
| 64 |
- if v.DriverName() == volume.DefaultDriverName {
|
|
| 65 |
- if err := container.CopyImagePathContent(v, destination); err != nil {
|
|
| 66 |
- return err |
|
| 67 |
- } |
|
| 63 |
+ container.AddMountPointWithVolume(destination, v, true) |
|
| 64 |
+ } |
|
| 65 |
+ return daemon.populateVolumes(container) |
|
| 66 |
+} |
|
| 67 |
+ |
|
| 68 |
+// populateVolumes copies data from the container's rootfs into the volume for non-binds. |
|
| 69 |
+// this is only called when the container is created. |
|
| 70 |
+func (daemon *Daemon) populateVolumes(c *container.Container) error {
|
|
| 71 |
+ for _, mnt := range c.MountPoints {
|
|
| 72 |
+ // skip binds and volumes referenced by other containers (ie, volumes-from) |
|
| 73 |
+ if mnt.Driver == "" || mnt.Volume == nil || len(daemon.volumes.Refs(mnt.Volume)) > 1 {
|
|
| 74 |
+ continue |
|
| 68 | 75 |
} |
| 69 | 76 |
|
| 70 |
- container.AddMountPointWithVolume(destination, v, true) |
|
| 77 |
+ logrus.Debugf("copying image data from %s:%s, to %s", c.ID, mnt.Destination, mnt.Name)
|
|
| 78 |
+ if err := c.CopyImagePathContent(mnt.Volume, mnt.Destination); err != nil {
|
|
| 79 |
+ return err |
|
| 80 |
+ } |
|
| 71 | 81 |
} |
| 72 | 82 |
return nil |
| 73 | 83 |
} |
| ... | ... |
@@ -3931,5 +3931,19 @@ func (s *DockerSuite) TestRunNamedVolumesMountedAsShared(c *check.C) {
|
| 3931 | 3931 |
if expected := "Invalid volume specification"; !strings.Contains(out, expected) {
|
| 3932 | 3932 |
c.Fatalf(`Expected %q in output; got: %s`, expected, out) |
| 3933 | 3933 |
} |
| 3934 |
+} |
|
| 3935 |
+ |
|
| 3936 |
+func (s *DockerSuite) TestRunNamedVolumeCopyImageData(c *check.C) {
|
|
| 3937 |
+ testRequires(c, DaemonIsLinux) |
|
| 3934 | 3938 |
|
| 3939 |
+ testImg := "testvolumecopy" |
|
| 3940 |
+ _, err := buildImage(testImg, ` |
|
| 3941 |
+ FROM busybox |
|
| 3942 |
+ RUN mkdir -p /foo && echo hello > /foo/hello |
|
| 3943 |
+ `, true) |
|
| 3944 |
+ c.Assert(err, check.IsNil) |
|
| 3945 |
+ |
|
| 3946 |
+ dockerCmd(c, "run", "-v", "foo:/foo", testImg) |
|
| 3947 |
+ out, _ := dockerCmd(c, "run", "-v", "foo:/foo", "busybox", "cat", "/foo/hello") |
|
| 3948 |
+ c.Assert(strings.TrimSpace(out), check.Equals, "hello") |
|
| 3935 | 3949 |
} |
| ... | ... |
@@ -296,6 +296,23 @@ func (s *VolumeStore) Dereference(v volume.Volume, ref string) {
|
| 296 | 296 |
s.globalLock.Unlock() |
| 297 | 297 |
} |
| 298 | 298 |
|
| 299 |
+// Refs gets the current list of refs for the given volume |
|
| 300 |
+func (s *VolumeStore) Refs(v volume.Volume) []string {
|
|
| 301 |
+ s.locks.Lock(v.Name()) |
|
| 302 |
+ defer s.locks.Unlock(v.Name()) |
|
| 303 |
+ |
|
| 304 |
+ s.globalLock.Lock() |
|
| 305 |
+ defer s.globalLock.Unlock() |
|
| 306 |
+ refs, exists := s.refs[v.Name()] |
|
| 307 |
+ if !exists {
|
|
| 308 |
+ return nil |
|
| 309 |
+ } |
|
| 310 |
+ |
|
| 311 |
+ refsOut := make([]string, len(refs)) |
|
| 312 |
+ copy(refsOut, refs) |
|
| 313 |
+ return refsOut |
|
| 314 |
+} |
|
| 315 |
+ |
|
| 299 | 316 |
// FilterByDriver returns the available volumes filtered by driver name |
| 300 | 317 |
func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) {
|
| 301 | 318 |
vd, err := volumedrivers.GetDriver(name) |