// migrateVolume links the contents of a volume created pre Docker 1.7 // into the location expected by the local driver. // It creates a symlink from DOCKER_ROOT/vfs/dir/VOLUME_ID to DOCKER_ROOT/volumes/VOLUME_ID/_container_data. // It preserves the volume json configuration generated pre Docker 1.7 to be able to // downgrade from Docker 1.7 to Docker 1.6 without losing volume compatibility. func migrateVolume(id, vfs string) error { l, err := volumedrivers.Lookup(volume.DefaultDriverName) if err != nil { return err } newDataPath := l.(*local.Root).DataPath(id) fi, err := os.Stat(newDataPath) if err != nil && !os.IsNotExist(err) { return err } if fi != nil && fi.IsDir() { return nil } return os.Symlink(vfs, newDataPath) }
// verifyVolumesInfo ports volumes configured for the containers pre docker 1.7. // It reads the container configuration and creates valid mount points for the old volumes. func (daemon *Daemon) verifyVolumesInfo(container *Container) error { // Inspect old structures only when we're upgrading from old versions // to versions >= 1.7 and the MountPoints has not been populated with volumes data. if len(container.MountPoints) == 0 && len(container.Volumes) > 0 { for destination, hostPath := range container.Volumes { vfsPath := filepath.Join(daemon.root, "vfs", "dir") rw := container.VolumesRW != nil && container.VolumesRW[destination] if strings.HasPrefix(hostPath, vfsPath) { id := filepath.Base(hostPath) if err := migrateVolume(id, hostPath); err != nil { return err } container.addLocalMountPoint(id, destination, rw) } else { // Bind mount id, source := volume.ParseVolumeSource(hostPath) container.addBindMountPoint(id, source, destination, rw) } } } else if len(container.MountPoints) > 0 { // Volumes created with a Docker version >= 1.7. We verify integrity in case of data created // with Docker 1.7 RC versions that put the information in // DOCKER_ROOT/volumes/VOLUME_ID rather than DOCKER_ROOT/volumes/VOLUME_ID/_container_data. l, err := volumedrivers.Lookup(volume.DefaultDriverName) if err != nil { return err } for _, m := range container.MountPoints { if m.Driver != volume.DefaultDriverName { continue } dataPath := l.(*local.Root).DataPath(m.Name) volumePath := filepath.Dir(dataPath) d, err := ioutil.ReadDir(volumePath) if err != nil { // If the volume directory doesn't exist yet it will be recreated, // so we only return the error when there is a different issue. if !os.IsNotExist(err) { return err } // Do not check when the volume directory does not exist. continue } if validVolumeLayout(d) { continue } if err := os.Mkdir(dataPath, 0755); err != nil { return err } // Move data inside the data directory for _, f := range d { oldp := filepath.Join(volumePath, f.Name()) newp := filepath.Join(dataPath, f.Name()) if err := os.Rename(oldp, newp); err != nil { logrus.Errorf("Unable to move %s to %s\n", oldp, newp) } } } return container.toDiskLocking() } return nil }