diff options
author | John Howard <jhoward@microsoft.com> | 2015-07-16 14:14:58 -0700 |
---|---|---|
committer | John Howard <jhoward@microsoft.com> | 2015-07-27 17:44:18 -0700 |
commit | 47c56e4353792e16f994a35ea4063768bee6590e (patch) | |
tree | 9b9366401dd5ae3a5f8cd40d4ed1002cb14babea /daemon/volumes_linux.go | |
parent | 33358f80e592686bb1872d9d50a4dd1e0391487f (diff) | |
download | docker-47c56e4353792e16f994a35ea4063768bee6590e.tar.gz |
Windows: Factoring out unused fields
Signed-off-by: John Howard <jhoward@microsoft.com>
Diffstat (limited to 'daemon/volumes_linux.go')
-rw-r--r-- | daemon/volumes_linux.go | 280 |
1 files changed, 280 insertions, 0 deletions
diff --git a/daemon/volumes_linux.go b/daemon/volumes_linux.go index 0155c52279..d0a752a300 100644 --- a/daemon/volumes_linux.go +++ b/daemon/volumes_linux.go @@ -3,15 +3,21 @@ package daemon import ( + "fmt" + "io/ioutil" "os" "path/filepath" "sort" "strings" + "github.com/Sirupsen/logrus" "github.com/docker/docker/daemon/execdriver" "github.com/docker/docker/pkg/system" + "github.com/docker/docker/runconfig" "github.com/docker/docker/volume" + "github.com/docker/docker/volume/drivers" "github.com/docker/docker/volume/local" + "github.com/opencontainers/runc/libcontainer/label" ) // copyOwnership copies the permissions and uid:gid of the source file @@ -49,6 +55,48 @@ func (container *Container) setupMounts() ([]execdriver.Mount, error) { return append(mounts, container.networkMounts()...), nil } +func parseBindMount(spec string, mountLabel string, config *runconfig.Config) (*mountPoint, error) { + bind := &mountPoint{ + RW: true, + } + arr := strings.Split(spec, ":") + + switch len(arr) { + case 2: + bind.Destination = arr[1] + case 3: + bind.Destination = arr[1] + mode := arr[2] + isValid, isRw := volume.ValidateMountMode(mode) + if !isValid { + return nil, fmt.Errorf("invalid mode for volumes-from: %s", mode) + } + bind.RW = isRw + // Mode field is used by SELinux to decide whether to apply label + bind.Mode = mode + default: + return nil, fmt.Errorf("Invalid volume specification: %s", spec) + } + + name, source, err := parseVolumeSource(arr[0]) + if err != nil { + return nil, err + } + + if len(source) == 0 { + bind.Driver = config.VolumeDriver + if len(bind.Driver) == 0 { + bind.Driver = volume.DefaultDriverName + } + } else { + bind.Source = filepath.Clean(source) + } + + bind.Name = name + bind.Destination = filepath.Clean(bind.Destination) + return bind, nil +} + func sortMounts(m []execdriver.Mount) []execdriver.Mount { sort.Sort(mounts(m)) return m @@ -118,3 +166,235 @@ func validVolumeLayout(files []os.FileInfo) bool { return true } + +// 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, err := parseVolumeSource(hostPath) + // We should not find an error here coming + // from the old configuration, but who knows. + if err != nil { + return err + } + 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 := getVolumeDriver(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.ToDisk() + } + + return nil +} + +func parseVolumesFrom(spec string) (string, string, error) { + if len(spec) == 0 { + return "", "", fmt.Errorf("malformed volumes-from specification: %s", spec) + } + + specParts := strings.SplitN(spec, ":", 2) + id := specParts[0] + mode := "rw" + + if len(specParts) == 2 { + mode = specParts[1] + if isValid, _ := volume.ValidateMountMode(mode); !isValid { + return "", "", fmt.Errorf("invalid mode for volumes-from: %s", mode) + } + } + return id, mode, nil +} + +// registerMountPoints initializes the container mount points with the configured volumes and bind mounts. +// It follows the next sequence to decide what to mount in each final destination: +// +// 1. Select the previously configured mount points for the containers, if any. +// 2. Select the volumes mounted from another containers. Overrides previously configured mount point destination. +// 3. Select the bind mounts set by the client. Overrides previously configured mount point destinations. +func (daemon *Daemon) registerMountPoints(container *Container, hostConfig *runconfig.HostConfig) error { + binds := map[string]bool{} + mountPoints := map[string]*mountPoint{} + + // 1. Read already configured mount points. + for name, point := range container.MountPoints { + mountPoints[name] = point + } + + // 2. Read volumes from other containers. + for _, v := range hostConfig.VolumesFrom { + containerID, mode, err := parseVolumesFrom(v) + if err != nil { + return err + } + + c, err := daemon.Get(containerID) + if err != nil { + return err + } + + for _, m := range c.MountPoints { + cp := &mountPoint{ + Name: m.Name, + Source: m.Source, + RW: m.RW && volume.ReadWrite(mode), + Driver: m.Driver, + Destination: m.Destination, + } + + if len(cp.Source) == 0 { + v, err := createVolume(cp.Name, cp.Driver) + if err != nil { + return err + } + cp.Volume = v + } + + mountPoints[cp.Destination] = cp + } + } + + // 3. Read bind mounts + for _, b := range hostConfig.Binds { + // #10618 + bind, err := parseBindMount(b, container.MountLabel, container.Config) + if err != nil { + return err + } + + if binds[bind.Destination] { + return fmt.Errorf("Duplicate bind mount %s", bind.Destination) + } + + if len(bind.Name) > 0 && len(bind.Driver) > 0 { + // create the volume + v, err := createVolume(bind.Name, bind.Driver) + if err != nil { + return err + } + bind.Volume = v + bind.Source = v.Path() + // Since this is just a named volume and not a typical bind, set to shared mode `z` + if bind.Mode == "" { + bind.Mode = "z" + } + } + + if err := label.Relabel(bind.Source, container.MountLabel, bind.Mode); err != nil { + return err + } + binds[bind.Destination] = true + mountPoints[bind.Destination] = bind + } + + // Keep backwards compatible structures + bcVolumes := map[string]string{} + bcVolumesRW := map[string]bool{} + for _, m := range mountPoints { + if m.BackwardsCompatible() { + bcVolumes[m.Destination] = m.Path() + bcVolumesRW[m.Destination] = m.RW + } + } + + container.Lock() + container.MountPoints = mountPoints + container.Volumes = bcVolumes + container.VolumesRW = bcVolumesRW + container.Unlock() + + return nil +} + +func createVolume(name, driverName string) (volume.Volume, error) { + vd, err := getVolumeDriver(driverName) + if err != nil { + return nil, err + } + return vd.Create(name) +} + +func removeVolume(v volume.Volume) error { + vd, err := getVolumeDriver(v.DriverName()) + if err != nil { + return nil + } + return vd.Remove(v) +} + +func getVolumeDriver(name string) (volume.Driver, error) { + if name == "" { + name = volume.DefaultDriverName + } + return volumedrivers.Lookup(name) +} + +func parseVolumeSource(spec string) (string, string, error) { + if !filepath.IsAbs(spec) { + return spec, "", nil + } + + return "", spec, nil +} + +// BackwardsCompatible decides whether this mount point can be +// used in old versions of Docker or not. +// Only bind mounts and local volumes can be used in old versions of Docker. +func (m *mountPoint) BackwardsCompatible() bool { + return len(m.Source) > 0 || m.Driver == volume.DefaultDriverName +} |