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