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