github.com/Shopify/docker@v1.13.1/volume/local/local_unix.go (about) 1 // +build linux freebsd solaris 2 3 // Package local provides the default implementation for volumes. It 4 // is used to mount data volume containers and directories local to 5 // the host server. 6 package local 7 8 import ( 9 "fmt" 10 "net" 11 "path/filepath" 12 "strings" 13 14 "github.com/pkg/errors" 15 16 "github.com/docker/docker/pkg/mount" 17 ) 18 19 var ( 20 oldVfsDir = filepath.Join("vfs", "dir") 21 22 validOpts = map[string]bool{ 23 "type": true, // specify the filesystem type for mount, e.g. nfs 24 "o": true, // generic mount options 25 "device": true, // device to mount from 26 } 27 ) 28 29 type optsConfig struct { 30 MountType string 31 MountOpts string 32 MountDevice string 33 } 34 35 func (o *optsConfig) String() string { 36 return fmt.Sprintf("type='%s' device='%s' o='%s'", o.MountType, o.MountDevice, o.MountOpts) 37 } 38 39 // scopedPath verifies that the path where the volume is located 40 // is under Docker's root and the valid local paths. 41 func (r *Root) scopedPath(realPath string) bool { 42 // Volumes path for Docker version >= 1.7 43 if strings.HasPrefix(realPath, filepath.Join(r.scope, volumesPathName)) && realPath != filepath.Join(r.scope, volumesPathName) { 44 return true 45 } 46 47 // Volumes path for Docker version < 1.7 48 if strings.HasPrefix(realPath, filepath.Join(r.scope, oldVfsDir)) { 49 return true 50 } 51 52 return false 53 } 54 55 func setOpts(v *localVolume, opts map[string]string) error { 56 if len(opts) == 0 { 57 return nil 58 } 59 if err := validateOpts(opts); err != nil { 60 return err 61 } 62 63 v.opts = &optsConfig{ 64 MountType: opts["type"], 65 MountOpts: opts["o"], 66 MountDevice: opts["device"], 67 } 68 return nil 69 } 70 71 func (v *localVolume) mount() error { 72 if v.opts.MountDevice == "" { 73 return fmt.Errorf("missing device in volume options") 74 } 75 mountOpts := v.opts.MountOpts 76 if v.opts.MountType == "nfs" { 77 if addrValue := getAddress(v.opts.MountOpts); addrValue != "" && net.ParseIP(addrValue).To4() == nil { 78 ipAddr, err := net.ResolveIPAddr("ip", addrValue) 79 if err != nil { 80 return errors.Wrapf(err, "error resolving passed in nfs address") 81 } 82 mountOpts = strings.Replace(mountOpts, "addr="+addrValue, "addr="+ipAddr.String(), 1) 83 } 84 } 85 err := mount.Mount(v.opts.MountDevice, v.path, v.opts.MountType, mountOpts) 86 return errors.Wrapf(err, "error while mounting volume with options: %s", v.opts) 87 }