summaryrefslogtreecommitdiff
path: root/daemon/volumes_linux.go
diff options
context:
space:
mode:
authorJohn Howard <jhoward@microsoft.com>2015-07-16 14:14:58 -0700
committerJohn Howard <jhoward@microsoft.com>2015-07-27 17:44:18 -0700
commit47c56e4353792e16f994a35ea4063768bee6590e (patch)
tree9b9366401dd5ae3a5f8cd40d4ed1002cb14babea /daemon/volumes_linux.go
parent33358f80e592686bb1872d9d50a4dd1e0391487f (diff)
downloaddocker-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.go280
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
+}