github.com/vieux/docker@v0.6.3-0.20161004191708-e097c2a938c7/volume/store/store.go (about) 1 package store 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "os" 7 "path/filepath" 8 "sync" 9 "time" 10 11 "github.com/pkg/errors" 12 13 "github.com/Sirupsen/logrus" 14 "github.com/boltdb/bolt" 15 "github.com/docker/docker/pkg/locker" 16 "github.com/docker/docker/volume" 17 "github.com/docker/docker/volume/drivers" 18 ) 19 20 const ( 21 volumeDataDir = "volumes" 22 volumeBucketName = "volumes" 23 ) 24 25 type volumeMetadata struct { 26 Name string 27 Labels map[string]string 28 } 29 30 type volumeWrapper struct { 31 volume.Volume 32 labels map[string]string 33 scope string 34 } 35 36 func (v volumeWrapper) Labels() map[string]string { 37 return v.labels 38 } 39 40 func (v volumeWrapper) Scope() string { 41 return v.scope 42 } 43 44 func (v volumeWrapper) CachedPath() string { 45 if vv, ok := v.Volume.(interface { 46 CachedPath() string 47 }); ok { 48 return vv.CachedPath() 49 } 50 return v.Volume.Path() 51 } 52 53 // New initializes a VolumeStore to keep 54 // reference counting of volumes in the system. 55 func New(rootPath string) (*VolumeStore, error) { 56 vs := &VolumeStore{ 57 locks: &locker.Locker{}, 58 names: make(map[string]volume.Volume), 59 refs: make(map[string][]string), 60 labels: make(map[string]map[string]string), 61 } 62 63 if rootPath != "" { 64 // initialize metadata store 65 volPath := filepath.Join(rootPath, volumeDataDir) 66 if err := os.MkdirAll(volPath, 750); err != nil { 67 return nil, err 68 } 69 70 dbPath := filepath.Join(volPath, "metadata.db") 71 72 var err error 73 vs.db, err = bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 1 * time.Second}) 74 if err != nil { 75 return nil, errors.Wrap(err, "error while opening volume store metadata database") 76 } 77 78 // initialize volumes bucket 79 if err := vs.db.Update(func(tx *bolt.Tx) error { 80 if _, err := tx.CreateBucketIfNotExists([]byte(volumeBucketName)); err != nil { 81 return errors.Wrap(err, "error while setting up volume store metadata database") 82 } 83 84 return nil 85 }); err != nil { 86 return nil, err 87 } 88 } 89 90 return vs, nil 91 } 92 93 func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) { 94 s.globalLock.Lock() 95 v, exists := s.names[name] 96 s.globalLock.Unlock() 97 return v, exists 98 } 99 100 func (s *VolumeStore) setNamed(v volume.Volume, ref string) { 101 s.globalLock.Lock() 102 s.names[v.Name()] = v 103 if len(ref) > 0 { 104 s.refs[v.Name()] = append(s.refs[v.Name()], ref) 105 } 106 s.globalLock.Unlock() 107 } 108 109 // Purge allows the cleanup of internal data on docker in case 110 // the internal data is out of sync with volumes driver plugins. 111 func (s *VolumeStore) Purge(name string) { 112 s.globalLock.Lock() 113 delete(s.names, name) 114 delete(s.refs, name) 115 delete(s.labels, name) 116 s.globalLock.Unlock() 117 } 118 119 // VolumeStore is a struct that stores the list of volumes available and keeps track of their usage counts 120 type VolumeStore struct { 121 locks *locker.Locker 122 globalLock sync.Mutex 123 // names stores the volume name -> driver name relationship. 124 // This is used for making lookups faster so we don't have to probe all drivers 125 names map[string]volume.Volume 126 // refs stores the volume name and the list of things referencing it 127 refs map[string][]string 128 // labels stores volume labels for each volume 129 labels map[string]map[string]string 130 db *bolt.DB 131 } 132 133 // List proxies to all registered volume drivers to get the full list of volumes 134 // If a driver returns a volume that has name which conflicts with another volume from a different driver, 135 // the first volume is chosen and the conflicting volume is dropped. 136 func (s *VolumeStore) List() ([]volume.Volume, []string, error) { 137 vols, warnings, err := s.list() 138 if err != nil { 139 return nil, nil, &OpErr{Err: err, Op: "list"} 140 } 141 var out []volume.Volume 142 143 for _, v := range vols { 144 name := normaliseVolumeName(v.Name()) 145 146 s.locks.Lock(name) 147 storedV, exists := s.getNamed(name) 148 // Note: it's not safe to populate the cache here because the volume may have been 149 // deleted before we acquire a lock on its name 150 if exists && storedV.DriverName() != v.DriverName() { 151 logrus.Warnf("Volume name %s already exists for driver %s, not including volume returned by %s", v.Name(), storedV.DriverName(), v.DriverName()) 152 s.locks.Unlock(v.Name()) 153 continue 154 } 155 156 out = append(out, v) 157 s.locks.Unlock(v.Name()) 158 } 159 return out, warnings, nil 160 } 161 162 // list goes through each volume driver and asks for its list of volumes. 163 func (s *VolumeStore) list() ([]volume.Volume, []string, error) { 164 var ( 165 ls []volume.Volume 166 warnings []string 167 ) 168 169 drivers, err := volumedrivers.GetAllDrivers() 170 if err != nil { 171 return nil, nil, err 172 } 173 174 type vols struct { 175 vols []volume.Volume 176 err error 177 driverName string 178 } 179 chVols := make(chan vols, len(drivers)) 180 181 for _, vd := range drivers { 182 go func(d volume.Driver) { 183 vs, err := d.List() 184 if err != nil { 185 chVols <- vols{driverName: d.Name(), err: &OpErr{Err: err, Name: d.Name(), Op: "list"}} 186 return 187 } 188 for i, v := range vs { 189 vs[i] = volumeWrapper{v, s.labels[v.Name()], d.Scope()} 190 } 191 192 chVols <- vols{vols: vs} 193 }(vd) 194 } 195 196 badDrivers := make(map[string]struct{}) 197 for i := 0; i < len(drivers); i++ { 198 vs := <-chVols 199 200 if vs.err != nil { 201 warnings = append(warnings, vs.err.Error()) 202 badDrivers[vs.driverName] = struct{}{} 203 logrus.Warn(vs.err) 204 } 205 ls = append(ls, vs.vols...) 206 } 207 208 if len(badDrivers) > 0 { 209 for _, v := range s.names { 210 if _, exists := badDrivers[v.DriverName()]; exists { 211 ls = append(ls, v) 212 } 213 } 214 } 215 return ls, warnings, nil 216 } 217 218 // CreateWithRef creates a volume with the given name and driver and stores the ref 219 // This ensures there's no race between creating a volume and then storing a reference. 220 func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts, labels map[string]string) (volume.Volume, error) { 221 name = normaliseVolumeName(name) 222 s.locks.Lock(name) 223 defer s.locks.Unlock(name) 224 225 v, err := s.create(name, driverName, opts, labels) 226 if err != nil { 227 return nil, &OpErr{Err: err, Name: name, Op: "create"} 228 } 229 230 s.setNamed(v, ref) 231 return v, nil 232 } 233 234 // Create creates a volume with the given name and driver. 235 // This is just like CreateWithRef() except we don't store a reference while holding the lock. 236 func (s *VolumeStore) Create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) { 237 return s.CreateWithRef(name, driverName, "", opts, labels) 238 } 239 240 // create asks the given driver to create a volume with the name/opts. 241 // If a volume with the name is already known, it will ask the stored driver for the volume. 242 // If the passed in driver name does not match the driver name which is stored for the given volume name, an error is returned. 243 // It is expected that callers of this function hold any necessary locks. 244 func (s *VolumeStore) create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) { 245 // Validate the name in a platform-specific manner 246 valid, err := volume.IsVolumeNameValid(name) 247 if err != nil { 248 return nil, err 249 } 250 if !valid { 251 return nil, &OpErr{Err: errInvalidName, Name: name, Op: "create"} 252 } 253 254 if v, exists := s.getNamed(name); exists { 255 if v.DriverName() != driverName && driverName != "" && driverName != volume.DefaultDriverName { 256 return nil, errNameConflict 257 } 258 return v, nil 259 } 260 261 // Since there isn't a specified driver name, let's see if any of the existing drivers have this volume name 262 if driverName == "" { 263 v, _ := s.getVolume(name) 264 if v != nil { 265 return v, nil 266 } 267 } 268 269 vd, err := volumedrivers.CreateDriver(driverName) 270 271 if err != nil { 272 return nil, &OpErr{Op: "create", Name: name, Err: err} 273 } 274 275 logrus.Debugf("Registering new volume reference: driver %q, name %q", vd.Name(), name) 276 277 if v, _ := vd.Get(name); v != nil { 278 return v, nil 279 } 280 v, err := vd.Create(name, opts) 281 if err != nil { 282 return nil, err 283 } 284 s.globalLock.Lock() 285 s.labels[name] = labels 286 s.globalLock.Unlock() 287 288 if s.db != nil { 289 metadata := &volumeMetadata{ 290 Name: name, 291 Labels: labels, 292 } 293 294 volData, err := json.Marshal(metadata) 295 if err != nil { 296 return nil, err 297 } 298 299 if err := s.db.Update(func(tx *bolt.Tx) error { 300 b := tx.Bucket([]byte(volumeBucketName)) 301 err := b.Put([]byte(name), volData) 302 return err 303 }); err != nil { 304 return nil, errors.Wrap(err, "error while persisting volume metadata") 305 } 306 } 307 308 return volumeWrapper{v, labels, vd.Scope()}, nil 309 } 310 311 // GetWithRef gets a volume with the given name from the passed in driver and stores the ref 312 // This is just like Get(), but we store the reference while holding the lock. 313 // This makes sure there are no races between checking for the existence of a volume and adding a reference for it 314 func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, error) { 315 name = normaliseVolumeName(name) 316 s.locks.Lock(name) 317 defer s.locks.Unlock(name) 318 319 vd, err := volumedrivers.GetDriver(driverName) 320 if err != nil { 321 return nil, &OpErr{Err: err, Name: name, Op: "get"} 322 } 323 324 v, err := vd.Get(name) 325 if err != nil { 326 return nil, &OpErr{Err: err, Name: name, Op: "get"} 327 } 328 329 s.setNamed(v, ref) 330 331 return volumeWrapper{v, s.labels[name], vd.Scope()}, nil 332 } 333 334 // Get looks if a volume with the given name exists and returns it if so 335 func (s *VolumeStore) Get(name string) (volume.Volume, error) { 336 name = normaliseVolumeName(name) 337 s.locks.Lock(name) 338 defer s.locks.Unlock(name) 339 340 v, err := s.getVolume(name) 341 if err != nil { 342 return nil, &OpErr{Err: err, Name: name, Op: "get"} 343 } 344 s.setNamed(v, "") 345 return v, nil 346 } 347 348 // getVolume requests the volume, if the driver info is stored it just accesses that driver, 349 // if the driver is unknown it probes all drivers until it finds the first volume with that name. 350 // it is expected that callers of this function hold any necessary locks 351 func (s *VolumeStore) getVolume(name string) (volume.Volume, error) { 352 labels := map[string]string{} 353 354 if s.db != nil { 355 // get meta 356 if err := s.db.Update(func(tx *bolt.Tx) error { 357 b := tx.Bucket([]byte(volumeBucketName)) 358 data := b.Get([]byte(name)) 359 360 if string(data) == "" { 361 return nil 362 } 363 364 var meta volumeMetadata 365 buf := bytes.NewBuffer(data) 366 367 if err := json.NewDecoder(buf).Decode(&meta); err != nil { 368 return err 369 } 370 labels = meta.Labels 371 372 return nil 373 }); err != nil { 374 return nil, err 375 } 376 } 377 378 logrus.Debugf("Getting volume reference for name: %s", name) 379 s.globalLock.Lock() 380 v, exists := s.names[name] 381 s.globalLock.Unlock() 382 if exists { 383 vd, err := volumedrivers.GetDriver(v.DriverName()) 384 if err != nil { 385 return nil, err 386 } 387 vol, err := vd.Get(name) 388 if err != nil { 389 return nil, err 390 } 391 return volumeWrapper{vol, labels, vd.Scope()}, nil 392 } 393 394 logrus.Debugf("Probing all drivers for volume with name: %s", name) 395 drivers, err := volumedrivers.GetAllDrivers() 396 if err != nil { 397 return nil, err 398 } 399 400 for _, d := range drivers { 401 v, err := d.Get(name) 402 if err != nil { 403 continue 404 } 405 406 return volumeWrapper{v, labels, d.Scope()}, nil 407 } 408 return nil, errNoSuchVolume 409 } 410 411 // Remove removes the requested volume. A volume is not removed if it has any refs 412 func (s *VolumeStore) Remove(v volume.Volume) error { 413 name := normaliseVolumeName(v.Name()) 414 s.locks.Lock(name) 415 defer s.locks.Unlock(name) 416 417 if refs, exists := s.refs[name]; exists && len(refs) > 0 { 418 return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: refs} 419 } 420 421 vd, err := volumedrivers.RemoveDriver(v.DriverName()) 422 if err != nil { 423 return &OpErr{Err: err, Name: vd.Name(), Op: "remove"} 424 } 425 426 logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name) 427 vol := unwrapVolume(v) 428 if err := vd.Remove(vol); err != nil { 429 return &OpErr{Err: err, Name: name, Op: "remove"} 430 } 431 432 s.Purge(name) 433 return nil 434 } 435 436 // Dereference removes the specified reference to the volume 437 func (s *VolumeStore) Dereference(v volume.Volume, ref string) { 438 s.locks.Lock(v.Name()) 439 defer s.locks.Unlock(v.Name()) 440 441 s.globalLock.Lock() 442 defer s.globalLock.Unlock() 443 var refs []string 444 445 for _, r := range s.refs[v.Name()] { 446 if r != ref { 447 refs = append(refs, r) 448 } 449 } 450 s.refs[v.Name()] = refs 451 } 452 453 // Refs gets the current list of refs for the given volume 454 func (s *VolumeStore) Refs(v volume.Volume) []string { 455 s.locks.Lock(v.Name()) 456 defer s.locks.Unlock(v.Name()) 457 458 s.globalLock.Lock() 459 defer s.globalLock.Unlock() 460 refs, exists := s.refs[v.Name()] 461 if !exists { 462 return nil 463 } 464 465 refsOut := make([]string, len(refs)) 466 copy(refsOut, refs) 467 return refsOut 468 } 469 470 // FilterByDriver returns the available volumes filtered by driver name 471 func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) { 472 vd, err := volumedrivers.GetDriver(name) 473 if err != nil { 474 return nil, &OpErr{Err: err, Name: name, Op: "list"} 475 } 476 ls, err := vd.List() 477 if err != nil { 478 return nil, &OpErr{Err: err, Name: name, Op: "list"} 479 } 480 for i, v := range ls { 481 ls[i] = volumeWrapper{v, s.labels[v.Name()], vd.Scope()} 482 } 483 return ls, nil 484 } 485 486 // FilterByUsed returns the available volumes filtered by if they are in use or not. 487 // `used=true` returns only volumes that are being used, while `used=false` returns 488 // only volumes that are not being used. 489 func (s *VolumeStore) FilterByUsed(vols []volume.Volume, used bool) []volume.Volume { 490 return s.filter(vols, func(v volume.Volume) bool { 491 s.locks.Lock(v.Name()) 492 l := len(s.refs[v.Name()]) 493 s.locks.Unlock(v.Name()) 494 if (used && l > 0) || (!used && l == 0) { 495 return true 496 } 497 return false 498 }) 499 } 500 501 // filterFunc defines a function to allow filter volumes in the store 502 type filterFunc func(vol volume.Volume) bool 503 504 // filter returns the available volumes filtered by a filterFunc function 505 func (s *VolumeStore) filter(vols []volume.Volume, f filterFunc) []volume.Volume { 506 var ls []volume.Volume 507 for _, v := range vols { 508 if f(v) { 509 ls = append(ls, v) 510 } 511 } 512 return ls 513 } 514 515 func unwrapVolume(v volume.Volume) volume.Volume { 516 if vol, ok := v.(volumeWrapper); ok { 517 return vol.Volume 518 } 519 520 return v 521 }