github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/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 dbPath := filepath.Join(volPath, "metadata.db") 99 vs.db, err = bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 1 * time.Second}) 100 if err != nil { 101 return nil, errors.Wrapf(err, "error while opening volume store metadata database (%s)", dbPath) 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 parser := volumemounts.NewParser() 582 err := parser.ValidateVolumeName(name) 583 if err != nil { 584 return nil, false, err 585 } 586 587 v, err := s.checkConflict(ctx, name, driverName) 588 if err != nil { 589 return nil, false, err 590 } 591 592 if v != nil { 593 // there is an existing volume, if we already have this stored locally, return it. 594 // TODO: there could be some inconsistent details such as labels here 595 if vv, _ := s.getNamed(v.Name()); vv != nil { 596 return vv, false, nil 597 } 598 } 599 600 // Since there isn't a specified driver name, let's see if any of the existing drivers have this volume name 601 if driverName == "" { 602 v, _ = s.getVolume(ctx, name, "") 603 if v != nil { 604 return v, false, nil 605 } 606 } 607 608 if driverName == "" { 609 driverName = volume.DefaultDriverName 610 } 611 vd, err := s.drivers.CreateDriver(driverName) 612 if err != nil { 613 return nil, false, &OpErr{Op: "create", Name: name, Err: err} 614 } 615 616 logrus.Debugf("Registering new volume reference: driver %q, name %q", vd.Name(), name) 617 if v, _ = vd.Get(name); v == nil { 618 v, err = vd.Create(name, opts) 619 if err != nil { 620 if _, err := s.drivers.ReleaseDriver(driverName); err != nil { 621 logrus.WithError(err).WithField("driver", driverName).Error("Error releasing reference to volume driver") 622 } 623 return nil, false, err 624 } 625 } 626 627 s.globalLock.Lock() 628 s.labels[name] = labels 629 s.options[name] = opts 630 s.refs[name] = make(map[string]struct{}) 631 s.globalLock.Unlock() 632 633 metadata := volumeMetadata{ 634 Name: name, 635 Driver: vd.Name(), 636 Labels: labels, 637 Options: opts, 638 } 639 640 if err := s.setMeta(name, metadata); err != nil { 641 return nil, true, err 642 } 643 return volumeWrapper{v, labels, vd.Scope(), opts}, true, nil 644 } 645 646 // Get looks if a volume with the given name exists and returns it if so 647 func (s *VolumeStore) Get(ctx context.Context, name string, getOptions ...opts.GetOption) (volume.Volume, error) { 648 var cfg opts.GetConfig 649 for _, o := range getOptions { 650 o(&cfg) 651 } 652 name = normalizeVolumeName(name) 653 s.locks.Lock(name) 654 defer s.locks.Unlock(name) 655 656 v, err := s.getVolume(ctx, name, cfg.Driver) 657 if err != nil { 658 return nil, &OpErr{Err: err, Name: name, Op: "get"} 659 } 660 if cfg.Driver != "" && v.DriverName() != cfg.Driver { 661 return nil, &OpErr{Name: name, Op: "get", Err: errdefs.Conflict(errors.New("found volume driver does not match passed in driver"))} 662 } 663 s.setNamed(v, cfg.Reference) 664 return v, nil 665 } 666 667 // getVolume requests the volume, if the driver info is stored it just accesses that driver, 668 // if the driver is unknown it probes all drivers until it finds the first volume with that name. 669 // it is expected that callers of this function hold any necessary locks 670 func (s *VolumeStore) getVolume(ctx context.Context, name, driverName string) (volume.Volume, error) { 671 var meta volumeMetadata 672 meta, err := s.getMeta(name) 673 if err != nil { 674 return nil, err 675 } 676 677 if driverName != "" { 678 if meta.Driver == "" { 679 meta.Driver = driverName 680 } 681 if driverName != meta.Driver { 682 return nil, errdefs.Conflict(errors.New("provided volume driver does not match stored driver")) 683 } 684 } 685 686 if driverName == "" { 687 driverName = meta.Driver 688 } 689 if driverName == "" { 690 s.globalLock.RLock() 691 select { 692 case <-ctx.Done(): 693 s.globalLock.RUnlock() 694 return nil, ctx.Err() 695 default: 696 } 697 v, exists := s.names[name] 698 s.globalLock.RUnlock() 699 if exists { 700 meta.Driver = v.DriverName() 701 if err := s.setMeta(name, meta); err != nil { 702 return nil, err 703 } 704 } 705 } 706 707 if meta.Driver != "" { 708 vol, err := lookupVolume(ctx, s.drivers, meta.Driver, name) 709 if err != nil { 710 return nil, err 711 } 712 if vol == nil { 713 s.purge(ctx, name) 714 return nil, errNoSuchVolume 715 } 716 717 var scope string 718 vd, err := s.drivers.GetDriver(meta.Driver) 719 if err == nil { 720 scope = vd.Scope() 721 } 722 return volumeWrapper{vol, meta.Labels, scope, meta.Options}, nil 723 } 724 725 logrus.Debugf("Probing all drivers for volume with name: %s", name) 726 drivers, err := s.drivers.GetAllDrivers() 727 if err != nil { 728 return nil, err 729 } 730 731 for _, d := range drivers { 732 select { 733 case <-ctx.Done(): 734 return nil, ctx.Err() 735 default: 736 } 737 v, err := d.Get(name) 738 if err != nil || v == nil { 739 continue 740 } 741 meta.Driver = v.DriverName() 742 if err := s.setMeta(name, meta); err != nil { 743 return nil, err 744 } 745 return volumeWrapper{v, meta.Labels, d.Scope(), meta.Options}, nil 746 } 747 return nil, errNoSuchVolume 748 } 749 750 // lookupVolume gets the specified volume from the specified driver. 751 // This will only return errors related to communications with the driver. 752 // If the driver returns an error that is not communication related, the error 753 // is logged but not returned. 754 // If the volume is not found it will return `nil, nil` 755 // TODO(@cpuguy83): plumb through the context to lower level components 756 func lookupVolume(ctx context.Context, store *drivers.Store, driverName, volumeName string) (volume.Volume, error) { 757 if driverName == "" { 758 driverName = volume.DefaultDriverName 759 } 760 vd, err := store.GetDriver(driverName) 761 if err != nil { 762 return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", volumeName, driverName) 763 } 764 v, err := vd.Get(volumeName) 765 if err != nil { 766 var nErr net.Error 767 if errors.As(err, &nErr) { 768 if v != nil { 769 volumeName = v.Name() 770 driverName = v.DriverName() 771 } 772 return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", volumeName, driverName) 773 } 774 775 // At this point, the error could be anything from the driver, such as "no such volume" 776 // Let's not check an error here, and instead check if the driver returned a volume 777 logrus.WithError(err).WithField("driver", driverName).WithField("volume", volumeName).Debug("Error while looking up volume") 778 } 779 return v, nil 780 } 781 782 // Remove removes the requested volume. A volume is not removed if it has any refs 783 func (s *VolumeStore) Remove(ctx context.Context, v volume.Volume, rmOpts ...opts.RemoveOption) error { 784 var cfg opts.RemoveConfig 785 for _, o := range rmOpts { 786 o(&cfg) 787 } 788 789 name := v.Name() 790 s.locks.Lock(name) 791 defer s.locks.Unlock(name) 792 793 select { 794 case <-ctx.Done(): 795 return ctx.Err() 796 default: 797 } 798 799 if s.hasRef(name) { 800 return &OpErr{Err: errVolumeInUse, Name: name, Op: "remove", Refs: s.getRefs(name)} 801 } 802 803 v, err := s.getVolume(ctx, name, v.DriverName()) 804 if err != nil { 805 return err 806 } 807 808 vd, err := s.drivers.GetDriver(v.DriverName()) 809 if err != nil { 810 return &OpErr{Err: err, Name: v.DriverName(), Op: "remove"} 811 } 812 813 logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name) 814 vol := unwrapVolume(v) 815 816 err = vd.Remove(vol) 817 if err != nil { 818 err = &OpErr{Err: err, Name: name, Op: "remove"} 819 } 820 821 if err == nil || cfg.PurgeOnError { 822 if e := s.purge(ctx, name); e != nil && err == nil { 823 err = e 824 } 825 } 826 if err == nil && s.eventLogger != nil { 827 s.eventLogger.LogVolumeEvent(v.Name(), "destroy", map[string]string{"driver": v.DriverName()}) 828 } 829 return err 830 } 831 832 // Release releases the specified reference to the volume 833 func (s *VolumeStore) Release(ctx context.Context, name string, ref string) error { 834 s.locks.Lock(name) 835 defer s.locks.Unlock(name) 836 select { 837 case <-ctx.Done(): 838 return ctx.Err() 839 default: 840 } 841 842 s.globalLock.Lock() 843 defer s.globalLock.Unlock() 844 845 select { 846 case <-ctx.Done(): 847 return ctx.Err() 848 default: 849 } 850 851 if s.refs[name] != nil { 852 delete(s.refs[name], ref) 853 } 854 return nil 855 } 856 857 // CountReferences gives a count of all references for a given volume. 858 func (s *VolumeStore) CountReferences(v volume.Volume) int { 859 name := normalizeVolumeName(v.Name()) 860 861 s.locks.Lock(name) 862 defer s.locks.Unlock(name) 863 s.globalLock.Lock() 864 defer s.globalLock.Unlock() 865 866 return len(s.refs[name]) 867 } 868 869 func unwrapVolume(v volume.Volume) volume.Volume { 870 if vol, ok := v.(volumeWrapper); ok { 871 return vol.Volume 872 } 873 874 return v 875 } 876 877 // Shutdown releases all resources used by the volume store 878 // It does not make any changes to volumes, drivers, etc. 879 func (s *VolumeStore) Shutdown() error { 880 return s.db.Close() 881 }