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