diff --git a/daemon/daemon_test.go b/daemon/daemon_test.go index 1fcb13fdd8..e01899649a 100644 --- a/daemon/daemon_test.go +++ b/daemon/daemon_test.go @@ -129,12 +129,25 @@ func TestLoadWithVolume(t *testing.T) { containerId := "d59df5276e7b219d510fe70565e0404bc06350e0d4b43fe961f22f339980170e" containerPath := filepath.Join(tmp, containerId) - if err = os.MkdirAll(containerPath, 0755); err != nil { + if err := os.MkdirAll(containerPath, 0755); err != nil { t.Fatal(err) } hostVolumeId := stringid.GenerateRandomID() - volumePath := filepath.Join(tmp, "vfs", "dir", hostVolumeId) + vfsPath := filepath.Join(tmp, "vfs", "dir", hostVolumeId) + volumePath := filepath.Join(tmp, "volumes", hostVolumeId) + + if err := os.MkdirAll(vfsPath, 0755); err != nil { + t.Fatal(err) + } + if err := os.MkdirAll(volumePath, 0755); err != nil { + t.Fatal(err) + } + + content := filepath.Join(vfsPath, "helo") + if err := ioutil.WriteFile(content, []byte("HELO"), 0644); err != nil { + t.Fatal(err) + } config := `{"State":{"Running":true,"Paused":false,"Restarting":false,"OOMKilled":false,"Dead":false,"Pid":2464,"ExitCode":0, "Error":"","StartedAt":"2015-05-26T16:48:53.869308965Z","FinishedAt":"0001-01-01T00:00:00Z"}, @@ -152,7 +165,7 @@ func TestLoadWithVolume(t *testing.T) { "Name":"/ubuntu","Driver":"aufs","ExecDriver":"native-0.2","MountLabel":"","ProcessLabel":"","AppArmorProfile":"","RestartCount":0, "UpdateDns":false,"Volumes":{"/vol1":"%s"},"VolumesRW":{"/vol1":true},"AppliedVolumesFrom":null}` - cfg := fmt.Sprintf(config, volumePath) + cfg := fmt.Sprintf(config, vfsPath) if err = ioutil.WriteFile(filepath.Join(containerPath, "config.json"), []byte(cfg), 0644); err != nil { t.Fatal(err) } @@ -200,6 +213,15 @@ func TestLoadWithVolume(t *testing.T) { if m.Driver != volume.DefaultDriverName { t.Fatalf("Expected mount driver local, was %s\n", m.Driver) } + + newVolumeContent := filepath.Join(volumePath, "helo") + b, err := ioutil.ReadFile(newVolumeContent) + if err != nil { + t.Fatal(err) + } + if string(b) != "HELO" { + t.Fatalf("Expected HELO, was %s\n", string(b)) + } } func TestLoadWithBindMount(t *testing.T) { diff --git a/daemon/volumes.go b/daemon/volumes.go index 2346eb715f..20638b78f9 100644 --- a/daemon/volumes.go +++ b/daemon/volumes.go @@ -8,6 +8,7 @@ import ( "path/filepath" "strings" + "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/chrootarchive" "github.com/docker/docker/runconfig" "github.com/docker/docker/volume" @@ -272,6 +273,9 @@ func (daemon *Daemon) verifyVolumesInfo(container *Container) error { if strings.HasPrefix(hostPath, vfsPath) { id := filepath.Base(hostPath) + if err := daemon.migrateVolume(id, hostPath); err != nil { + return err + } container.addLocalMountPoint(id, destination, rw) } else { // Bind mount id, source, err := parseVolumeSource(hostPath) @@ -287,6 +291,37 @@ func (daemon *Daemon) verifyVolumesInfo(container *Container) error { return container.ToDisk() } +// migrateVolume moves the contents of a volume created pre Docker 1.7 +// to the location expected by the local driver. Steps: +// 1. Save old directory that includes old volume's config json file. +// 2. Move virtual directory with content to where the local driver expects it to be. +// 3. Remove the backup of the old volume config. +func (daemon *Daemon) migrateVolume(id, vfs string) error { + volumeInfo := filepath.Join(daemon.root, defaultVolumesPathName, id) + backup := filepath.Join(daemon.root, defaultVolumesPathName, id+".back") + + var err error + if err = os.Rename(volumeInfo, backup); err != nil { + return err + } + defer func() { + // Put old configuration back in place in case one of the next steps fails. + if err != nil { + os.Rename(backup, volumeInfo) + } + }() + + if err = os.Rename(vfs, volumeInfo); err != nil { + return err + } + + if err = os.RemoveAll(backup); err != nil { + logrus.Errorf("Unable to remove volume info backup directory %s: %v", backup, err) + } + + return nil +} + func createVolume(name, driverName string) (volume.Volume, error) { vd, err := getVolumeDriver(driverName) if err != nil {