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