Pārlūkot izejas kodu

Cleanup: initializeVolume

- Use a common struct for Volumes
- Split out some functionality in intializeVolume into separate functions
- Removes some duplicate code
- In general much easier to grok the code now

Docker-DCO-1.1-Signed-off-by: Brian Goff <cpuguy83@gmail.com> (github: cpuguy83)
Brian Goff 11 gadi atpakaļ
vecāks
revīzija
e350df5b2c
1 mainītis faili ar 107 papildinājumiem un 105 dzēšanām
  1. 107 105
      daemon/volumes.go

+ 107 - 105
daemon/volumes.go

@@ -13,10 +13,24 @@ import (
 	"github.com/docker/docker/pkg/symlink"
 	"github.com/docker/docker/pkg/symlink"
 )
 )
 
 
-type BindMap struct {
-	SrcPath string
-	DstPath string
-	Mode    string
+type Volume struct {
+	HostPath    string
+	VolPath     string
+	Mode        string
+	isBindMount bool
+}
+
+func (v *Volume) isRw() bool {
+	return v.Mode == "" || strings.ToLower(v.Mode) == "rw"
+}
+
+func (v *Volume) isDir() (bool, error) {
+	stat, err := os.Stat(v.HostPath)
+	if err != nil {
+		return false, err
+	}
+
+	return stat.IsDir(), nil
 }
 }
 
 
 func prepareVolumesForContainer(container *Container) error {
 func prepareVolumesForContainer(container *Container) error {
@@ -122,35 +136,40 @@ func applyVolumesFrom(container *Container) error {
 	return nil
 	return nil
 }
 }
 
 
-func parseBindVolumeSpec(spec string) (BindMap, error) {
+func parseBindVolumeSpec(spec string) (Volume, error) {
 	var (
 	var (
-		arr       = strings.Split(spec, ":")
-		err error = nil
-		vol BindMap
+		arr = strings.Split(spec, ":")
+		vol Volume
 	)
 	)
 
 
+	vol.isBindMount = true
 	switch len(arr) {
 	switch len(arr) {
 	case 1:
 	case 1:
-		vol.DstPath = spec
+		vol.VolPath = spec
 		vol.Mode = "rw"
 		vol.Mode = "rw"
 	case 2:
 	case 2:
-		vol.SrcPath = arr[0]
-		vol.DstPath = arr[1]
+		vol.HostPath = arr[0]
+		vol.VolPath = arr[1]
 		vol.Mode = "rw"
 		vol.Mode = "rw"
 	case 3:
 	case 3:
-		vol.SrcPath = arr[0]
-		vol.DstPath = arr[1]
+		vol.HostPath = arr[0]
+		vol.VolPath = arr[1]
 		vol.Mode = arr[2]
 		vol.Mode = arr[2]
 	default:
 	default:
-		err = fmt.Errorf("Invalid volume specification: %s", spec)
+		return vol, fmt.Errorf("Invalid volume specification: %s", spec)
 	}
 	}
-	return vol, err
+
+	if !filepath.IsAbs(vol.HostPath) {
+		return vol, fmt.Errorf("cannot bind mount volume: %s volume paths must be absolute.", vol.HostPath)
+	}
+
+	return vol, nil
 }
 }
 
 
-func getBindMap(container *Container) (map[string]BindMap, error) {
+func getBindMap(container *Container) (map[string]Volume, error) {
 	var (
 	var (
 		// Create the requested bind mounts
 		// Create the requested bind mounts
-		binds = make(map[string]BindMap)
+		volumes = map[string]Volume{}
 		// Define illegal container destinations
 		// Define illegal container destinations
 		illegalDsts = []string{"/", "."}
 		illegalDsts = []string{"/", "."}
 	)
 	)
@@ -158,151 +177,134 @@ func getBindMap(container *Container) (map[string]BindMap, error) {
 	for _, bind := range container.hostConfig.Binds {
 	for _, bind := range container.hostConfig.Binds {
 		vol, err := parseBindVolumeSpec(bind)
 		vol, err := parseBindVolumeSpec(bind)
 		if err != nil {
 		if err != nil {
-			return binds, err
+			return volumes, err
 		}
 		}
 		// Bail if trying to mount to an illegal destination
 		// Bail if trying to mount to an illegal destination
 		for _, illegal := range illegalDsts {
 		for _, illegal := range illegalDsts {
-			if vol.DstPath == illegal {
-				return nil, fmt.Errorf("Illegal bind destination: %s", vol.DstPath)
+			if vol.VolPath == illegal {
+				return nil, fmt.Errorf("Illegal bind destination: %s", vol.VolPath)
 			}
 			}
 		}
 		}
 
 
-		binds[filepath.Clean(vol.DstPath)] = vol
+		volumes[filepath.Clean(vol.VolPath)] = vol
 	}
 	}
-	return binds, nil
+	return volumes, nil
 }
 }
 
 
 func createVolumes(container *Container) error {
 func createVolumes(container *Container) error {
-	binds, err := getBindMap(container)
+	// Get all the bindmounts
+	volumes, err := getBindMap(container)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	// Create the requested volumes if they don't exist
+	// Get all the rest of the volumes
 	for volPath := range container.Config.Volumes {
 	for volPath := range container.Config.Volumes {
-		if err := initializeVolume(container, volPath, binds); err != nil {
-			return err
+		// Make sure the the volume isn't already specified as a bindmount
+		if _, exists := volumes[volPath]; !exists {
+			volumes[volPath] = Volume{
+				VolPath:     volPath,
+				Mode:        "rw",
+				isBindMount: false,
+			}
 		}
 		}
 	}
 	}
 
 
-	for volPath := range binds {
-		if err := initializeVolume(container, volPath, binds); err != nil {
+	for _, vol := range volumes {
+		if err = vol.initialize(container); err != nil {
 			return err
 			return err
 		}
 		}
 	}
 	}
 	return nil
 	return nil
+
 }
 }
 
 
-func createIfNotExists(destination string, isDir bool) error {
-	if _, err := os.Stat(destination); err != nil && os.IsNotExist(err) {
-		if isDir {
-			if err := os.MkdirAll(destination, 0755); err != nil {
-				return err
-			}
-		} else {
-			if err := os.MkdirAll(filepath.Dir(destination), 0755); err != nil {
-				return err
-			}
+func createVolumeHostPath(container *Container) (string, error) {
+	volumesDriver := container.daemon.volumes.Driver()
 
 
-			f, err := os.OpenFile(destination, os.O_CREATE, 0755)
-			if err != nil {
-				return err
-			}
-			f.Close()
-		}
+	// Do not pass a container as the parameter for the volume creation.
+	// The graph driver using the container's information ( Image ) to
+	// create the parent.
+	c, err := container.daemon.volumes.Create(nil, "", "", "", "", nil, nil)
+	if err != nil {
+		return "", err
+	}
+	hostPath, err := volumesDriver.Get(c.ID, "")
+	if err != nil {
+		return hostPath, fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
 	}
 	}
 
 
-	return nil
+	return hostPath, nil
 }
 }
 
 
-func initializeVolume(container *Container, volPath string, binds map[string]BindMap) error {
-	volumesDriver := container.daemon.volumes.Driver()
-	volPath = filepath.Clean(volPath)
+func (v *Volume) initialize(container *Container) error {
+	var err error
+	v.VolPath = filepath.Clean(v.VolPath)
 
 
-	// Skip existing volumes
-	if _, exists := container.Volumes[volPath]; exists {
+	// Do not initialize an existing volume
+	if _, exists := container.Volumes[v.VolPath]; exists {
 		return nil
 		return nil
 	}
 	}
 
 
-	var (
-		destination string
-		isBindMount bool
-		volIsDir    = true
-
-		srcRW = false
-	)
-
-	// If an external bind is defined for this volume, use that as a source
-	if bindMap, exists := binds[volPath]; exists {
-		isBindMount = true
-		destination = bindMap.SrcPath
-
-		if !filepath.IsAbs(destination) {
-			return fmt.Errorf("cannot bind mount volume: %s volume paths must be absolute.", destination)
-		}
-
-		if strings.ToLower(bindMap.Mode) == "rw" {
-			srcRW = true
-		}
-
-		if stat, err := os.Stat(bindMap.SrcPath); err != nil {
-			return err
-		} else {
-			volIsDir = stat.IsDir()
-		}
-	} else {
-		// Do not pass a container as the parameter for the volume creation.
-		// The graph driver using the container's information ( Image ) to
-		// create the parent.
-		c, err := container.daemon.volumes.Create(nil, "", "", "", "", nil, nil)
+	// If it's not a bindmount we need to create the dir on the host
+	if !v.isBindMount {
+		v.HostPath, err = createVolumeHostPath(container)
 		if err != nil {
 		if err != nil {
 			return err
 			return err
 		}
 		}
-
-		destination, err = volumesDriver.Get(c.ID, "")
-		if err != nil {
-			return fmt.Errorf("Driver %s failed to get volume rootfs %s: %s", volumesDriver, c.ID, err)
-		}
-
-		srcRW = true
 	}
 	}
 
 
-	if p, err := filepath.EvalSymlinks(destination); err != nil {
+	hostPath, err := filepath.EvalSymlinks(v.HostPath)
+	if err != nil {
 		return err
 		return err
-	} else {
-		destination = p
 	}
 	}
 
 
 	// Create the mountpoint
 	// Create the mountpoint
-	source, err := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, volPath), container.basefs)
+	// This is the path to the volume within the container FS
+	// This differs from `hostPath` in that `hostPath` refers to the place where
+	// the volume data is actually stored on the host
+	fullVolPath, err := symlink.FollowSymlinkInScope(filepath.Join(container.basefs, v.VolPath), container.basefs)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	newVolPath, err := filepath.Rel(container.basefs, source)
+	container.Volumes[v.VolPath] = hostPath
+	container.VolumesRW[v.VolPath] = v.isRw()
+
+	volIsDir, err := v.isDir()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
-	newVolPath = "/" + newVolPath
+	if err := createIfNotExists(fullVolPath, volIsDir); err != nil {
+		return err
+	}
 
 
-	if volPath != newVolPath {
-		delete(container.Volumes, volPath)
-		delete(container.VolumesRW, volPath)
+	// Do not copy or change permissions if we are mounting from the host
+	if v.isRw() && !v.isBindMount {
+		return copyExistingContents(fullVolPath, hostPath)
 	}
 	}
+	return nil
+}
 
 
-	container.Volumes[volPath] = destination
-	container.VolumesRW[volPath] = srcRW
+func createIfNotExists(destination string, isDir bool) error {
+	if _, err := os.Stat(destination); err == nil || !os.IsNotExist(err) {
+		return nil
+	}
 
 
-	if err := createIfNotExists(source, volIsDir); err != nil {
+	if isDir {
+		return os.MkdirAll(destination, 0755)
+	}
+
+	if err := os.MkdirAll(filepath.Dir(destination), 0755); err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	// Do not copy or change permissions if we are mounting from the host
-	if srcRW && !isBindMount {
-		if err := copyExistingContents(source, destination); err != nil {
-			return err
-		}
+	f, err := os.OpenFile(destination, os.O_CREATE, 0755)
+	if err != nil {
+		return err
 	}
 	}
+	f.Close()
+
 	return nil
 	return nil
 }
 }