github.com/demonoid81/moby@v0.0.0-20200517203328-62dd8e17c460/volume/service/store.go (about) 1 package service // import "github.com/demonoid81/moby/volume/service" 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "os" 8 "path/filepath" 9 "runtime" 10 "sync" 11 "time" 12 13 "github.com/pkg/errors" 14 15 "github.com/demonoid81/moby/errdefs" 16 "github.com/demonoid81/moby/pkg/locker" 17 "github.com/demonoid81/moby/volume" 18 "github.com/demonoid81/moby/volume/drivers" 19 volumemounts "github.com/demonoid81/moby/volume/mounts" 20 "github.com/demonoid81/moby/volume/service/opts" 21 "github.com/sirupsen/logrus" 22 bolt "go.etcd.io/bbolt" 23 ) 24 25 const ( 26 volumeDataDir = "volumes" 27 ) 28 29 type volumeWrapper struct { 30 volume.Volume 31 labels map[string]string 32 scope string 33 options map[string]string 34 } 35 36 func (v volumeWrapper) Options() map[string]string { 37 if v.options == nil { 38 return nil 39 } 40 options := make(map[string]string, len(v.options)) 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 if v.labels == nil { 49 return nil 50 } 51 52 labels := make(map[string]string, len(v.labels)) 53 for key, value := range v.labels { 54 labels[key] = value 55 } 56 return labels 57 } 58 59 func (v volumeWrapper) Scope() string { 60 return v.scope 61 } 62 63 func (v volumeWrapper) CachedPath() string { 64 if vv, ok := v.Volume.(interface { 65 CachedPath() string 66 }); ok { 67 return vv.CachedPath() 68 } 69 return v.Volume.Path() 70 } 71 72 // NewStore creates a new volume store at the given path 73 func NewStore(rootPath string, drivers *drivers.Store) (*VolumeStore, error) { 74 vs := &VolumeStore{ 75 locks: &locker.Locker{}, 76 names: make(map[string]volume.Volume), 77 refs: make(map[string]map[string]struct{}), 78 labels: make(map[string]map[string]string), 79 options: make(map[string]map[string]string), 80 drivers: drivers, 81 } 82 83 if rootPath != "" { 84 // initialize metadata store 85 volPath := filepath.Join(rootPath, volumeDataDir) 86 if err := os.MkdirAll(volPath, 0750); err != nil { 87 return nil, err 88 } 89 90 var err error 91 vs.db, err = bolt.Open(filepath.Join(volPath, "metadata.db"), 0600, &bolt.Options{Timeout: 1 * time.Second}) 92 if err != nil { 93 return nil, errors.Wrap(err, "error while opening volume store metadata database") 94 } 95 96 // initialize volumes bucket 97 if err := vs.db.Update(func(tx *bolt.Tx) error { 98 if _, err := tx.CreateBucketIfNotExists(volumeBucketName); err != nil { 99 return errors.Wrap(err, "error while setting up volume store metadata database") 100 } 101 return nil 102 }); err != nil { 103 return nil, err 104 } 105 } 106 107 vs.restore() 108 109 return vs, nil 110 } 111 112 func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) { 113 s.globalLock.RLock() 114 v, exists := s.names[name] 115 s.globalLock.RUnlock() 116 return v, exists 117 } 118 119 func (s *VolumeStore) setNamed(v volume.Volume, ref string) { 120 name := v.Name() 121 122 s.globalLock.Lock() 123 s.names[name] = v 124 if len(ref) > 0 { 125 if s.refs[name] == nil { 126 s.refs[name] = make(map[string]struct{}) 127 } 128 s.refs[name][ref] = struct{}{} 129 } 130 s.globalLock.Unlock() 131 } 132 133 // hasRef returns true if the given name has at least one ref. 134 // Callers of this function are expected to hold the name lock. 135 func (s *VolumeStore) hasRef(name string) bool { 136 s.globalLock.RLock() 137 l := len(s.refs[name]) 138 s.globalLock.RUnlock() 139 return l > 0 140 } 141 142 // getRefs gets the list of refs for a given name 143 // Callers of this function are expected to hold the name lock. 144 func (s *VolumeStore) getRefs(name string) []string { 145 s.globalLock.RLock() 146 defer s.globalLock.RUnlock() 147 148 refs := make([]string, 0, len(s.refs[name])) 149 for r := range s.refs[name] { 150 refs = append(refs, r) 151 } 152 153 return refs 154 } 155 156 // purge allows the cleanup of internal data on docker in case 157 // the internal data is out of sync with volumes driver plugins. 158 func (s *VolumeStore) purge(ctx context.Context, name string) error { 159 s.globalLock.Lock() 160 defer s.globalLock.Unlock() 161 162 select { 163 case <-ctx.Done(): 164 return ctx.Err() 165 default: 166 } 167 168 v, exists := s.names[name] 169 if exists { 170 driverName := v.DriverName() 171 if _, err := s.drivers.ReleaseDriver(driverName); err != nil { 172 logrus.WithError(err).WithField("driver", driverName).Error("Error releasing reference to volume driver") 173 } 174 } 175 if err := s.removeMeta(name); err != nil { 176 logrus.Errorf("Error removing volume metadata for volume %q: %v", name, err) 177 } 178 delete(s.names, name) 179 delete(s.refs, name) 180 delete(s.labels, name) 181 delete(s.options, name) 182 return nil 183 } 184 185 // VolumeStore is responsible for storing and reference counting volumes. 186 type VolumeStore struct { 187 // locks ensures that only one action is being performed on a particular volume at a time without locking the entire store 188 // since actions on volumes can be quite slow, this ensures the store is free to handle requests for other volumes. 189 locks *locker.Locker 190 drivers *drivers.Store 191 // globalLock is used to protect access to mutable structures used by the store object 192 globalLock sync.RWMutex 193 // names stores the volume name -> volume relationship. 194 // This is used for making lookups faster so we don't have to probe all drivers 195 names map[string]volume.Volume 196 // refs stores the volume name and the list of things referencing it 197 refs map[string]map[string]struct{} 198 // labels stores volume labels for each volume 199 labels map[string]map[string]string 200 // options stores volume options for each volume 201 options map[string]map[string]string 202 db *bolt.DB 203 } 204 205 func filterByDriver(names []string) filterFunc { 206 return func(v volume.Volume) bool { 207 for _, name := range names { 208 if name == v.DriverName() { 209 return true 210 } 211 } 212 return false 213 } 214 } 215 216 func (s *VolumeStore) byReferenced(referenced bool) filterFunc { 217 return func(v volume.Volume) bool { 218 return s.hasRef(v.Name()) == referenced 219 } 220 } 221 222 func (s *VolumeStore) filter(ctx context.Context, vols *[]volume.Volume, by By) (warnings []string, err error) { 223 // note that this specifically does not support the `FromList` By type. 224 switch f := by.(type) { 225 case nil: 226 if *vols == nil { 227 var ls []volume.Volume 228 ls, warnings, err = s.list(ctx) 229 if err != nil { 230 return warnings, err 231 } 232 *vols = ls 233 } 234 case byDriver: 235 if *vols != nil { 236 filter(vols, filterByDriver([]string(f))) 237 return nil, nil 238 } 239 var ls []volume.Volume 240 ls, warnings, err = s.list(ctx, []string(f)...) 241 if err != nil { 242 return nil, err 243 } 244 *vols = ls 245 case ByReferenced: 246 // TODO(@cpuguy83): It would be nice to optimize this by looking at the list 247 // of referenced volumes, however the locking strategy makes this difficult 248 // without either providing inconsistent data or deadlocks. 249 if *vols == nil { 250 var ls []volume.Volume 251 ls, warnings, err = s.list(ctx) 252 if err != nil { 253 return nil, err 254 } 255 *vols = ls 256 } 257 filter(vols, s.byReferenced(bool(f))) 258 case andCombinator: 259 for _, by := range f { 260 w, err := s.filter(ctx, vols, by) 261 if err != nil { 262 return warnings, err 263 } 264 warnings = append(warnings, w...) 265 } 266 case orCombinator: 267 for _, by := range f { 268 switch by.(type) { 269 case byDriver: 270 var ls []volume.Volume 271 w, err := s.filter(ctx, &ls, by) 272 if err != nil { 273 return warnings, err 274 } 275 warnings = append(warnings, w...) 276 default: 277 ls, w, err := s.list(ctx) 278 if err != nil { 279 return warnings, err 280 } 281 warnings = append(warnings, w...) 282 w, err = s.filter(ctx, &ls, by) 283 if err != nil { 284 return warnings, err 285 } 286 warnings = append(warnings, w...) 287 *vols = append(*vols, ls...) 288 } 289 } 290 unique(vols) 291 case CustomFilter: 292 if *vols == nil { 293 var ls []volume.Volume 294 ls, warnings, err = s.list(ctx) 295 if err != nil { 296 return nil, err 297 } 298 *vols = ls 299 } 300 filter(vols, filterFunc(f)) 301 default: 302 return nil, errdefs.InvalidParameter(errors.Errorf("unsupported filter: %T", f)) 303 } 304 return warnings, nil 305 } 306 307 func unique(ls *[]volume.Volume) { 308 names := make(map[string]bool, len(*ls)) 309 filter(ls, func(v volume.Volume) bool { 310 if names[v.Name()] { 311 return false 312 } 313 names[v.Name()] = true 314 return true 315 }) 316 } 317 318 // Find lists volumes filtered by the past in filter. 319 // If a driver returns a volume that has name which conflicts with another volume from a different driver, 320 // the first volume is chosen and the conflicting volume is dropped. 321 func (s *VolumeStore) Find(ctx context.Context, by By) (vols []volume.Volume, warnings []string, err error) { 322 logrus.WithField("ByType", fmt.Sprintf("%T", by)).WithField("ByValue", fmt.Sprintf("%+v", by)).Debug("VolumeStore.Find") 323 switch f := by.(type) { 324 case nil, orCombinator, andCombinator, byDriver, ByReferenced, CustomFilter: 325 warnings, err = s.filter(ctx, &vols, by) 326 case fromList: 327 warnings, err = s.filter(ctx, f.ls, f.by) 328 default: 329 // Really shouldn't be possible, but makes sure that any new By's are added to this check. 330 err = errdefs.InvalidParameter(errors.Errorf("unsupported filter type: %T", f)) 331 } 332 if err != nil { 333 return nil, nil, &OpErr{Err: err, Op: "list"} 334 } 335 336 var out []volume.Volume 337 338 for _, v := range vols { 339 name := normalizeVolumeName(v.Name()) 340 341 s.locks.Lock(name) 342 storedV, exists := s.getNamed(name) 343 // Note: it's not safe to populate the cache here because the volume may have been 344 // deleted before we acquire a lock on its name 345 if exists && storedV.DriverName() != v.DriverName() { 346 logrus.Warnf("Volume name %s already exists for driver %s, not including volume returned by %s", v.Name(), storedV.DriverName(), v.DriverName()) 347 s.locks.Unlock(v.Name()) 348 continue 349 } 350 351 out = append(out, v) 352 s.locks.Unlock(v.Name()) 353 } 354 return out, warnings, nil 355 } 356 357 type filterFunc func(volume.Volume) bool 358 359 func filter(vols *[]volume.Volume, fn filterFunc) { 360 var evict []int 361 for i, v := range *vols { 362 if !fn(v) { 363 evict = append(evict, i) 364 } 365 } 366 367 for n, i := range evict { 368 copy((*vols)[i-n:], (*vols)[i-n+1:]) 369 (*vols)[len(*vols)-1] = nil 370 *vols = (*vols)[:len(*vols)-1] 371 } 372 } 373 374 // list goes through each volume driver and asks for its list of volumes. 375 // TODO(@cpuguy83): plumb context through 376 func (s *VolumeStore) list(ctx context.Context, driverNames ...string) ([]volume.Volume, []string, error) { 377 var ( 378 ls = []volume.Volume{} // do not return a nil value as this affects filtering 379 warnings []string 380 ) 381 382 var dls []volume.Driver 383 384 all, err := s.drivers.GetAllDrivers() 385 if err != nil { 386 return nil, nil, err 387 } 388 if len(driverNames) == 0 { 389 dls = all 390 } else { 391 idx := make(map[string]bool, len(driverNames)) 392 for _, name := range driverNames { 393 idx[name] = true 394 } 395 for _, d := range all { 396 if idx[d.Name()] { 397 dls = append(dls, d) 398 } 399 } 400 } 401 402 type vols struct { 403 vols []volume.Volume 404 err error 405 driverName string 406 } 407 chVols := make(chan vols, len(dls)) 408 409 for _, vd := range dls { 410 go func(d volume.Driver) { 411 vs, err := d.List() 412 if err != nil { 413 chVols <- vols{driverName: d.Name(), err: &OpErr{Err: err, Name: d.Name(), Op: "list"}} 414 return 415 } 416 for i, v := range vs { 417 s.globalLock.RLock() 418 vs[i] = volumeWrapper{v, s.labels[v.Name()], d.Scope(), s.options[v.Name()]} 419 s.globalLock.RUnlock() 420 } 421 422 chVols <- vols{vols: vs} 423 }(vd) 424 } 425 426 badDrivers := make(map[string]struct{}) 427 for i := 0; i < len(dls); i++ { 428 vs := <-chVols 429 430 if vs.err != nil { 431 warnings = append(warnings, vs.err.Error()) 432 badDrivers[vs.driverName] = struct{}{} 433 } 434 ls = append(ls, vs.vols...) 435 } 436 437 if len(badDrivers) > 0 { 438 s.globalLock.RLock() 439 for _, v := range s.names { 440 if _, exists := badDrivers[v.DriverName()]; exists { 441 ls = append(ls, v) 442 } 443 } 444 s.globalLock.RUnlock() 445 } 446 return ls, warnings, nil 447 } 448 449 // Create creates a volume with the given name and driver 450 // If the volume needs to be created with a reference to prevent race conditions 451 // with volume cleanup, make sure to use the `CreateWithReference` option. 452 func (s *VolumeStore) Create(ctx context.Context, name, driverName string, createOpts ...opts.CreateOption) (volume.Volume, error) { 453 var cfg opts.CreateConfig 454 for _, o := range createOpts { 455 o(&cfg) 456 } 457 458 name = normalizeVolumeName(name) 459 s.locks.Lock(name) 460 defer s.locks.Unlock(name) 461 462 select { 463 case <-ctx.Done(): 464 return nil, ctx.Err() 465 default: 466 } 467 468 v, err := s.create(ctx, name, driverName, cfg.Options, cfg.Labels) 469 if err != nil { 470 if _, ok := err.(*OpErr); ok { 471 return nil, err 472 } 473 return nil, &OpErr{Err: err, Name: name, Op: "create"} 474 } 475 476 s.setNamed(v, cfg.Reference) 477 return v, nil 478 } 479 480 // checkConflict checks the local cache for name collisions with the passed in name, 481 // for existing volumes with the same name but in a different driver. 482 // This is used by `Create` as a best effort to prevent name collisions for volumes. 483 // If a matching volume is found that is not a conflict that is returned so the caller 484 // does not need to perform an additional lookup. 485 // When no matching volume is found, both returns will be nil 486 // 487 // Note: This does not probe all the drivers for name collisions because v1 plugins 488 // are very slow, particularly if the plugin is down, and cause other issues, 489 // particularly around locking the store. 490 // TODO(cpuguy83): With v2 plugins this shouldn't be a problem. Could also potentially 491 // use a connect timeout for this kind of check to ensure we aren't blocking for a 492 // long time. 493 func (s *VolumeStore) checkConflict(ctx context.Context, name, driverName string) (volume.Volume, error) { 494 // check the local cache 495 v, _ := s.getNamed(name) 496 if v == nil { 497 return nil, nil 498 } 499 500 vDriverName := v.DriverName() 501 var conflict bool 502 if driverName != "" { 503 // Retrieve canonical driver name to avoid inconsistencies (for example 504 // "plugin" vs. "plugin:latest") 505 vd, err := s.drivers.GetDriver(driverName) 506 if err != nil { 507 return nil, err 508 } 509 510 if vDriverName != vd.Name() { 511 conflict = true 512 } 513 } 514 515 // let's check if the found volume ref 516 // is stale by checking with the driver if it still exists 517 exists, err := volumeExists(ctx, s.drivers, v) 518 if err != nil { 519 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) 520 } 521 522 if exists { 523 if conflict { 524 return nil, errors.Wrapf(errNameConflict, "driver '%s' already has volume '%s'", vDriverName, name) 525 } 526 return v, nil 527 } 528 529 if s.hasRef(v.Name()) { 530 // Containers are referencing this volume but it doesn't seem to exist anywhere. 531 // Return a conflict error here, the user can fix this with `docker volume rm -f` 532 return nil, errors.Wrapf(errNameConflict, "found references to volume '%s' in driver '%s' but the volume was not found in the driver -- you may need to remove containers referencing this volume or force remove the volume to re-create it", name, vDriverName) 533 } 534 535 // doesn't exist, so purge it from the cache 536 s.purge(ctx, name) 537 return nil, nil 538 } 539 540 // volumeExists returns if the volume is still present in the driver. 541 // An error is returned if there was an issue communicating with the driver. 542 func volumeExists(ctx context.Context, store *drivers.Store, v volume.Volume) (bool, error) { 543 exists, err := lookupVolume(ctx, store, v.DriverName(), v.Name()) 544 if err != nil { 545 return false, err 546 } 547 return exists != nil, nil 548 } 549 550 // create asks the given driver to create a volume with the name/opts. 551 // If a volume with the name is already known, it will ask the stored driver for the volume. 552 // If the passed in driver name does not match the driver name which is stored 553 // for the given volume name, an error is returned after checking if the reference is stale. 554 // If the reference is stale, it will be purged and this create can continue. 555 // It is expected that callers of this function hold any necessary locks. 556 func (s *VolumeStore) create(ctx context.Context, name, driverName string, opts, labels map[string]string) (volume.Volume, error) { 557 // Validate the name in a platform-specific manner 558 559 // volume name validation is specific to the host os and not on container image 560 // windows/lcow should have an equivalent volumename validation logic so we create a parser for current host OS 561 parser := volumemounts.NewParser(runtime.GOOS) 562 err := parser.ValidateVolumeName(name) 563 if err != nil { 564 return nil, err 565 } 566 567 v, err := s.checkConflict(ctx, name, driverName) 568 if err != nil { 569 return nil, err 570 } 571 572 if v != nil { 573 // there is an existing volume, if we already have this stored locally, return it. 574 // TODO: there could be some inconsistent details such as labels here 575 if vv, _ := s.getNamed(v.Name()); vv != nil { 576 return vv, nil 577 } 578 } 579 580 // Since there isn't a specified driver name, let's see if any of the existing drivers have this volume name 581 if driverName == "" { 582 v, _ = s.getVolume(ctx, name, "") 583 if v != nil { 584 return v, nil 585 } 586 } 587 588 if driverName == "" { 589 driverName = volume.DefaultDriverName 590 } 591 vd, err := s.drivers.CreateDriver(driverName) 592 if err != nil { 593 return nil, &OpErr{Op: "create", Name: name, Err: err} 594 } 595 596 logrus.Debugf("Registering new volume reference: driver %q, name %q", vd.Name(), name) 597 if v, _ = vd.Get(name); v == nil { 598 v, err = vd.Create(name, opts) 599 if err != nil { 600 if _, err := s.drivers.ReleaseDriver(driverName); err != nil { 601 logrus.WithError(err).WithField("driver", driverName).Error("Error releasing reference to volume driver") 602 } 603 return nil, err 604 } 605 } 606 607 s.globalLock.Lock() 608 s.labels[name] = labels 609 s.options[name] = opts 610 s.refs[name] = make(map[string]struct{}) 611 s.globalLock.Unlock() 612 613 metadata := volumeMetadata{ 614 Name: name, 615 Driver: vd.Name(), 616 Labels: labels, 617 Options: opts, 618 } 619 620 if err := s.setMeta(name, metadata); err != nil { 621 return nil, err 622 } 623 return volumeWrapper{v, labels, vd.Scope(), opts}, nil 624 } 625 626 // Get looks if a volume with the given name exists and returns it if so 627 func (s *VolumeStore) Get(ctx context.Context, name string, getOptions ...opts.GetOption) (volume.Volume, error) { 628 var cfg opts.GetConfig 629 for _, o := range getOptions { 630 o(&cfg) 631 } 632 name = normalizeVolumeName(name) 633 s.locks.Lock(name) 634 defer s.locks.Unlock(name) 635 636 v, err := s.getVolume(ctx, name, cfg.Driver) 637 if err != nil { 638 return nil, &OpErr{Err: err, Name: name, Op: "get"} 639 } 640 if cfg.Driver != "" && v.DriverName() != cfg.Driver { 641 return nil, &OpErr{Name: name, Op: "get", Err: errdefs.Conflict(errors.New("found volume driver does not match passed in driver"))} 642 } 643 s.setNamed(v, cfg.Reference) 644 return v, nil 645 } 646 647 // getVolume requests the volume, if the driver info is stored it just accesses that driver, 648 // if the driver is unknown it probes all drivers until it finds the first volume with that name. 649 // it is expected that callers of this function hold any necessary locks 650 func (s *VolumeStore) getVolume(ctx context.Context, name, driverName string) (volume.Volume, error) { 651 var meta volumeMetadata 652 meta, err := s.getMeta(name) 653 if err != nil { 654 return nil, err 655 } 656 657 if driverName != "" { 658 if meta.Driver == "" { 659 meta.Driver = driverName 660 } 661 if driverName != meta.Driver { 662 return nil, errdefs.Conflict(errors.New("provided volume driver does not match stored driver")) 663 } 664 } 665 666 if driverName == "" { 667 driverName = meta.Driver 668 } 669 if driverName == "" { 670 s.globalLock.RLock() 671 select { 672 case <-ctx.Done(): 673 s.globalLock.RUnlock() 674 return nil, ctx.Err() 675 default: 676 } 677 v, exists := s.names[name] 678 s.globalLock.RUnlock() 679 if exists { 680 meta.Driver = v.DriverName() 681 if err := s.setMeta(name, meta); err != nil { 682 return nil, err 683 } 684 } 685 } 686 687 if meta.Driver != "" { 688 vol, err := lookupVolume(ctx, s.drivers, meta.Driver, name) 689 if err != nil { 690 return nil, err 691 } 692 if vol == nil { 693 s.purge(ctx, name) 694 return nil, errNoSuchVolume 695 } 696 697 var scope string 698 vd, err := s.drivers.GetDriver(meta.Driver) 699 if err == nil { 700 scope = vd.Scope() 701 } 702 return volumeWrapper{vol, meta.Labels, scope, meta.Options}, nil 703 } 704 705 logrus.Debugf("Probing all drivers for volume with name: %s", name) 706 drivers, err := s.drivers.GetAllDrivers() 707 if err != nil { 708 return nil, err 709 } 710 711 for _, d := range drivers { 712 select { 713 case <-ctx.Done(): 714 return nil, ctx.Err() 715 default: 716 } 717 v, err := d.Get(name) 718 if err != nil || v == nil { 719 continue 720 } 721 meta.Driver = v.DriverName() 722 if err := s.setMeta(name, meta); err != nil { 723 return nil, err 724 } 725 return volumeWrapper{v, meta.Labels, d.Scope(), meta.Options}, nil 726 } 727 return nil, errNoSuchVolume 728 } 729 730 // lookupVolume gets the specified volume from the specified driver. 731 // This will only return errors related to communications with the driver. 732 // If the driver returns an error that is not communication related the 733 // error is logged but not returned. 734 // If the volume is not found it will return `nil, nil`` 735 // TODO(@cpuguy83): plumb through the context to lower level components 736 func lookupVolume(ctx context.Context, store *drivers.Store, driverName, volumeName string) (volume.Volume, error) { 737 if driverName == "" { 738 driverName = volume.DefaultDriverName 739 } 740 vd, err := store.GetDriver(driverName) 741 if err != nil { 742 return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", volumeName, driverName) 743 } 744 v, err := vd.Get(volumeName) 745 if err != nil { 746 var nErr net.Error 747 if errors.As(err, &nErr) { 748 if v != nil { 749 volumeName = v.Name() 750 driverName = v.DriverName() 751 } 752 return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", volumeName, driverName) 753 } 754 755 // At this point, the error could be anything from the driver, such as "no such volume" 756 // Let's not check an error here, and instead check if the driver returned a volume 757 logrus.WithError(err).WithField("driver", driverName).WithField("volume", volumeName).Debug("Error while looking up volume") 758 } 759 return v, nil 760 } 761 762 // Remove removes the requested volume. A volume is not removed if it has any refs 763 func (s *VolumeStore) Remove(ctx context.Context, v volume.Volume, rmOpts ...opts.RemoveOption) error { 764 var cfg opts.RemoveConfig 765 for _, o := range rmOpts { 766 o(&cfg) 767 } 768 769 name := v.Name() 770 s.locks.Lock(name) 771 defer s.locks.Unlock(name) 772 773 select { 774 case <-ctx.Done(): 775 return ctx.Err() 776 default: 777 } 778 779 if s.hasRef(name) { 780 return &OpErr{Err: errVolumeInUse, Name: name, Op: "remove", Refs: s.getRefs(name)} 781 } 782 783 v, err := s.getVolume(ctx, name, v.DriverName()) 784 if err != nil { 785 return err 786 } 787 788 vd, err := s.drivers.GetDriver(v.DriverName()) 789 if err != nil { 790 return &OpErr{Err: err, Name: v.DriverName(), Op: "remove"} 791 } 792 793 logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name) 794 vol := unwrapVolume(v) 795 796 err = vd.Remove(vol) 797 if err != nil { 798 err = &OpErr{Err: err, Name: name, Op: "remove"} 799 } 800 801 if err == nil || cfg.PurgeOnError { 802 if e := s.purge(ctx, name); e != nil && err == nil { 803 err = e 804 } 805 } 806 return err 807 } 808 809 // Release releases the specified reference to the volume 810 func (s *VolumeStore) Release(ctx context.Context, name string, ref string) error { 811 s.locks.Lock(name) 812 defer s.locks.Unlock(name) 813 select { 814 case <-ctx.Done(): 815 return ctx.Err() 816 default: 817 } 818 819 s.globalLock.Lock() 820 defer s.globalLock.Unlock() 821 822 select { 823 case <-ctx.Done(): 824 return ctx.Err() 825 default: 826 } 827 828 if s.refs[name] != nil { 829 delete(s.refs[name], ref) 830 } 831 return nil 832 } 833 834 // CountReferences gives a count of all references for a given volume. 835 func (s *VolumeStore) CountReferences(v volume.Volume) int { 836 name := normalizeVolumeName(v.Name()) 837 838 s.locks.Lock(name) 839 defer s.locks.Unlock(name) 840 s.globalLock.Lock() 841 defer s.globalLock.Unlock() 842 843 return len(s.refs[name]) 844 } 845 846 func unwrapVolume(v volume.Volume) volume.Volume { 847 if vol, ok := v.(volumeWrapper); ok { 848 return vol.Volume 849 } 850 851 return v 852 } 853 854 // Shutdown releases all resources used by the volume store 855 // It does not make any changes to volumes, drivers, etc. 856 func (s *VolumeStore) Shutdown() error { 857 return s.db.Close() 858 }