github.com/a4a881d4/docker@v1.9.0-rc2/volume/local/local.go (about) 1 // Package local provides the default implementation for volumes. It 2 // is used to mount data volume containers and directories local to 3 // the host server. 4 package local 5 6 import ( 7 "errors" 8 "fmt" 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 "sync" 13 14 derr "github.com/docker/docker/errors" 15 "github.com/docker/docker/pkg/idtools" 16 "github.com/docker/docker/utils" 17 "github.com/docker/docker/volume" 18 ) 19 20 // VolumeDataPathName is the name of the directory where the volume data is stored. 21 // It uses a very distintive name to avoid collisions migrating data between 22 // Docker versions. 23 const ( 24 VolumeDataPathName = "_data" 25 volumesPathName = "volumes" 26 ) 27 28 var ( 29 // ErrNotFound is the typed error returned when the requested volume name can't be found 30 ErrNotFound = errors.New("volume not found") 31 // volumeNameRegex ensures the name asigned for the volume is valid. 32 // This name is used to create the bind directory, so we need to avoid characters that 33 // would make the path to escape the root directory. 34 volumeNameRegex = utils.RestrictedNamePattern 35 ) 36 37 // New instantiates a new Root instance with the provided scope. Scope 38 // is the base path that the Root instance uses to store its 39 // volumes. The base path is created here if it does not exist. 40 func New(scope string, rootUID, rootGID int) (*Root, error) { 41 rootDirectory := filepath.Join(scope, volumesPathName) 42 43 if err := idtools.MkdirAllAs(rootDirectory, 0700, rootUID, rootGID); err != nil { 44 return nil, err 45 } 46 47 r := &Root{ 48 scope: scope, 49 path: rootDirectory, 50 volumes: make(map[string]*localVolume), 51 rootUID: rootUID, 52 rootGID: rootGID, 53 } 54 55 dirs, err := ioutil.ReadDir(rootDirectory) 56 if err != nil { 57 return nil, err 58 } 59 60 for _, d := range dirs { 61 name := filepath.Base(d.Name()) 62 r.volumes[name] = &localVolume{ 63 driverName: r.Name(), 64 name: name, 65 path: r.DataPath(name), 66 } 67 } 68 69 return r, nil 70 } 71 72 // Root implements the Driver interface for the volume package and 73 // manages the creation/removal of volumes. It uses only standard vfs 74 // commands to create/remove dirs within its provided scope. 75 type Root struct { 76 m sync.Mutex 77 scope string 78 path string 79 volumes map[string]*localVolume 80 rootUID int 81 rootGID int 82 } 83 84 // List lists all the volumes 85 func (r *Root) List() []volume.Volume { 86 var ls []volume.Volume 87 for _, v := range r.volumes { 88 ls = append(ls, v) 89 } 90 return ls 91 } 92 93 // DataPath returns the constructed path of this volume. 94 func (r *Root) DataPath(volumeName string) string { 95 return filepath.Join(r.path, volumeName, VolumeDataPathName) 96 } 97 98 // Name returns the name of Root, defined in the volume package in the DefaultDriverName constant. 99 func (r *Root) Name() string { 100 return volume.DefaultDriverName 101 } 102 103 // Create creates a new volume.Volume with the provided name, creating 104 // the underlying directory tree required for this volume in the 105 // process. 106 func (r *Root) Create(name string, _ map[string]string) (volume.Volume, error) { 107 if err := r.validateName(name); err != nil { 108 return nil, err 109 } 110 111 r.m.Lock() 112 defer r.m.Unlock() 113 114 v, exists := r.volumes[name] 115 if exists { 116 return v, nil 117 } 118 119 path := r.DataPath(name) 120 if err := idtools.MkdirAllAs(path, 0755, r.rootUID, r.rootGID); err != nil { 121 if os.IsExist(err) { 122 return nil, fmt.Errorf("volume already exists under %s", filepath.Dir(path)) 123 } 124 return nil, err 125 } 126 v = &localVolume{ 127 driverName: r.Name(), 128 name: name, 129 path: path, 130 } 131 r.volumes[name] = v 132 return v, nil 133 } 134 135 // Remove removes the specified volume and all underlying data. If the 136 // given volume does not belong to this driver and an error is 137 // returned. The volume is reference counted, if all references are 138 // not released then the volume is not removed. 139 func (r *Root) Remove(v volume.Volume) error { 140 r.m.Lock() 141 defer r.m.Unlock() 142 143 lv, ok := v.(*localVolume) 144 if !ok { 145 return errors.New("unknown volume type") 146 } 147 148 realPath, err := filepath.EvalSymlinks(lv.path) 149 if err != nil { 150 if !os.IsNotExist(err) { 151 return err 152 } 153 realPath = filepath.Dir(lv.path) 154 } 155 156 if !r.scopedPath(realPath) { 157 return fmt.Errorf("Unable to remove a directory of out the Docker root %s: %s", r.scope, realPath) 158 } 159 160 if err := removePath(realPath); err != nil { 161 return err 162 } 163 164 delete(r.volumes, lv.name) 165 return removePath(filepath.Dir(lv.path)) 166 } 167 168 func removePath(path string) error { 169 if err := os.RemoveAll(path); err != nil { 170 if os.IsNotExist(err) { 171 return nil 172 } 173 return err 174 } 175 return nil 176 } 177 178 // Get looks up the volume for the given name and returns it if found 179 func (r *Root) Get(name string) (volume.Volume, error) { 180 r.m.Lock() 181 v, exists := r.volumes[name] 182 r.m.Unlock() 183 if !exists { 184 return nil, ErrNotFound 185 } 186 return v, nil 187 } 188 189 func (r *Root) validateName(name string) error { 190 if !volumeNameRegex.MatchString(name) { 191 return derr.ErrorCodeVolumeName.WithArgs(name, utils.RestrictedNameChars) 192 } 193 return nil 194 } 195 196 // localVolume implements the Volume interface from the volume package and 197 // represents the volumes created by Root. 198 type localVolume struct { 199 m sync.Mutex 200 usedCount int 201 // unique name of the volume 202 name string 203 // path is the path on the host where the data lives 204 path string 205 // driverName is the name of the driver that created the volume. 206 driverName string 207 } 208 209 // Name returns the name of the given Volume. 210 func (v *localVolume) Name() string { 211 return v.name 212 } 213 214 // DriverName returns the driver that created the given Volume. 215 func (v *localVolume) DriverName() string { 216 return v.driverName 217 } 218 219 // Path returns the data location. 220 func (v *localVolume) Path() string { 221 return v.path 222 } 223 224 // Mount implements the localVolume interface, returning the data location. 225 func (v *localVolume) Mount() (string, error) { 226 return v.path, nil 227 } 228 229 // Umount is for satisfying the localVolume interface and does not do anything in this driver. 230 func (v *localVolume) Unmount() error { 231 return nil 232 }