github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/volume/store/store.go (about) 1 package store 2 3 import ( 4 "net" 5 "os" 6 "path/filepath" 7 "runtime" 8 "sync" 9 "time" 10 11 "github.com/pkg/errors" 12 13 "github.com/boltdb/bolt" 14 "github.com/docker/docker/pkg/locker" 15 "github.com/docker/docker/volume" 16 "github.com/docker/docker/volume/drivers" 17 "github.com/sirupsen/logrus" 18 ) 19 20 const ( 21 volumeDataDir = "volumes" 22 ) 23 24 type volumeWrapper struct { 25 volume.Volume 26 labels map[string]string 27 scope string 28 options map[string]string 29 } 30 31 func (v volumeWrapper) Options() map[string]string { 32 options := map[string]string{} 33 for key, value := range v.options { 34 options[key] = value 35 } 36 return options 37 } 38 39 func (v volumeWrapper) Labels() map[string]string { 40 return v.labels 41 } 42 43 func (v volumeWrapper) Scope() string { 44 return v.scope 45 } 46 47 func (v volumeWrapper) CachedPath() string { 48 if vv, ok := v.Volume.(interface { 49 CachedPath() string 50 }); ok { 51 return vv.CachedPath() 52 } 53 return v.Volume.Path() 54 } 55 56 // New initializes a VolumeStore to keep 57 // reference counting of volumes in the system. 58 func New(rootPath string) (*VolumeStore, error) { 59 vs := &VolumeStore{ 60 locks: &locker.Locker{}, 61 names: make(map[string]volume.Volume), 62 refs: make(map[string]map[string]struct{}), 63 labels: make(map[string]map[string]string), 64 options: make(map[string]map[string]string), 65 } 66 67 if rootPath != "" { 68 // initialize metadata store 69 volPath := filepath.Join(rootPath, volumeDataDir) 70 if err := os.MkdirAll(volPath, 750); err != nil { 71 return nil, err 72 } 73 74 dbPath := filepath.Join(volPath, "metadata.db") 75 76 var err error 77 vs.db, err = bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 1 * time.Second}) 78 if err != nil { 79 return nil, errors.Wrap(err, "error while opening volume store metadata database") 80 } 81 82 // initialize volumes bucket 83 if err := vs.db.Update(func(tx *bolt.Tx) error { 84 if _, err := tx.CreateBucketIfNotExists(volumeBucketName); err != nil { 85 return errors.Wrap(err, "error while setting up volume store metadata database") 86 } 87 return nil 88 }); err != nil { 89 return nil, err 90 } 91 } 92 93 vs.restore() 94 95 return vs, nil 96 } 97 98 func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) { 99 s.globalLock.RLock() 100 v, exists := s.names[name] 101 s.globalLock.RUnlock() 102 return v, exists 103 } 104 105 func (s *VolumeStore) setNamed(v volume.Volume, ref string) { 106 name := v.Name() 107 108 s.globalLock.Lock() 109 s.names[name] = v 110 if len(ref) > 0 { 111 if s.refs[name] == nil { 112 s.refs[name] = make(map[string]struct{}) 113 } 114 s.refs[name][ref] = struct{}{} 115 } 116 s.globalLock.Unlock() 117 } 118 119 // hasRef returns true if the given name has at least one ref. 120 // Callers of this function are expected to hold the name lock. 121 func (s *VolumeStore) hasRef(name string) bool { 122 s.globalLock.RLock() 123 l := len(s.refs[name]) 124 s.globalLock.RUnlock() 125 return l > 0 126 } 127 128 // getRefs gets the list of refs for a given name 129 // Callers of this function are expected to hold the name lock. 130 func (s *VolumeStore) getRefs(name string) []string { 131 s.globalLock.RLock() 132 defer s.globalLock.RUnlock() 133 134 refs := make([]string, 0, len(s.refs[name])) 135 for r := range s.refs[name] { 136 refs = append(refs, r) 137 } 138 139 return refs 140 } 141 142 // Purge allows the cleanup of internal data on docker in case 143 // the internal data is out of sync with volumes driver plugins. 144 func (s *VolumeStore) Purge(name string) { 145 s.globalLock.Lock() 146 v, exists := s.names[name] 147 if exists { 148 if _, err := volumedrivers.ReleaseDriver(v.DriverName()); err != nil { 149 logrus.Errorf("Error dereferencing volume driver: %v", err) 150 } 151 } 152 if err := s.removeMeta(name); err != nil { 153 logrus.Errorf("Error removing volume metadata for volume %q: %v", name, err) 154 } 155 delete(s.names, name) 156 delete(s.refs, name) 157 delete(s.labels, name) 158 delete(s.options, name) 159 s.globalLock.Unlock() 160 } 161 162 // VolumeStore is a struct that stores the list of volumes available and keeps track of their usage counts 163 type VolumeStore struct { 164 // locks ensures that only one action is being performed on a particular volume at a time without locking the entire store 165 // since actions on volumes can be quite slow, this ensures the store is free to handle requests for other volumes. 166 locks *locker.Locker 167 // globalLock is used to protect access to mutable structures used by the store object 168 globalLock sync.RWMutex 169 // names stores the volume name -> volume relationship. 170 // This is used for making lookups faster so we don't have to probe all drivers 171 names map[string]volume.Volume 172 // refs stores the volume name and the list of things referencing it 173 refs map[string]map[string]struct{} 174 // labels stores volume labels for each volume 175 labels map[string]map[string]string 176 // options stores volume options for each volume 177 options map[string]map[string]string 178 db *bolt.DB 179 } 180 181 // List proxies to all registered volume drivers to get the full list of volumes 182 // If a driver returns a volume that has name which conflicts with another volume from a different driver, 183 // the first volume is chosen and the conflicting volume is dropped. 184 func (s *VolumeStore) List() ([]volume.Volume, []string, error) { 185 vols, warnings, err := s.list() 186 if err != nil { 187 return nil, nil, &OpErr{Err: err, Op: "list"} 188 } 189 var out []volume.Volume 190 191 for _, v := range vols { 192 name := normalizeVolumeName(v.Name()) 193 194 s.locks.Lock(name) 195 storedV, exists := s.getNamed(name) 196 // Note: it's not safe to populate the cache here because the volume may have been 197 // deleted before we acquire a lock on its name 198 if exists && storedV.DriverName() != v.DriverName() { 199 logrus.Warnf("Volume name %s already exists for driver %s, not including volume returned by %s", v.Name(), storedV.DriverName(), v.DriverName()) 200 s.locks.Unlock(v.Name()) 201 continue 202 } 203 204 out = append(out, v) 205 s.locks.Unlock(v.Name()) 206 } 207 return out, warnings, nil 208 } 209 210 // list goes through each volume driver and asks for its list of volumes. 211 func (s *VolumeStore) list() ([]volume.Volume, []string, error) { 212 var ( 213 ls []volume.Volume 214 warnings []string 215 ) 216 217 drivers, err := volumedrivers.GetAllDrivers() 218 if err != nil { 219 return nil, nil, err 220 } 221 222 type vols struct { 223 vols []volume.Volume 224 err error 225 driverName string 226 } 227 chVols := make(chan vols, len(drivers)) 228 229 for _, vd := range drivers { 230 go func(d volume.Driver) { 231 vs, err := d.List() 232 if err != nil { 233 chVols <- vols{driverName: d.Name(), err: &OpErr{Err: err, Name: d.Name(), Op: "list"}} 234 return 235 } 236 for i, v := range vs { 237 s.globalLock.RLock() 238 vs[i] = volumeWrapper{v, s.labels[v.Name()], d.Scope(), s.options[v.Name()]} 239 s.globalLock.RUnlock() 240 } 241 242 chVols <- vols{vols: vs} 243 }(vd) 244 } 245 246 badDrivers := make(map[string]struct{}) 247 for i := 0; i < len(drivers); i++ { 248 vs := <-chVols 249 250 if vs.err != nil { 251 warnings = append(warnings, vs.err.Error()) 252 badDrivers[vs.driverName] = struct{}{} 253 logrus.Warn(vs.err) 254 } 255 ls = append(ls, vs.vols...) 256 } 257 258 if len(badDrivers) > 0 { 259 s.globalLock.RLock() 260 for _, v := range s.names { 261 if _, exists := badDrivers[v.DriverName()]; exists { 262 ls = append(ls, v) 263 } 264 } 265 s.globalLock.RUnlock() 266 } 267 return ls, warnings, nil 268 } 269 270 // CreateWithRef creates a volume with the given name and driver and stores the ref 271 // This ensures there's no race between creating a volume and then storing a reference. 272 func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts, labels map[string]string) (volume.Volume, error) { 273 name = normalizeVolumeName(name) 274 s.locks.Lock(name) 275 defer s.locks.Unlock(name) 276 277 v, err := s.create(name, driverName, opts, labels) 278 if err != nil { 279 if _, ok := err.(*OpErr); ok { 280 return nil, err 281 } 282 return nil, &OpErr{Err: err, Name: name, Op: "create"} 283 } 284 285 s.setNamed(v, ref) 286 return v, nil 287 } 288 289 // Create creates a volume with the given name and driver. 290 // This is just like CreateWithRef() except we don't store a reference while holding the lock. 291 func (s *VolumeStore) Create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) { 292 return s.CreateWithRef(name, driverName, "", opts, labels) 293 } 294 295 // checkConflict checks the local cache for name collisions with the passed in name, 296 // for existing volumes with the same name but in a different driver. 297 // This is used by `Create` as a best effort to prevent name collisions for volumes. 298 // If a matching volume is found that is not a conflict that is returned so the caller 299 // does not need to perform an additional lookup. 300 // When no matching volume is found, both returns will be nil 301 // 302 // Note: This does not probe all the drivers for name collisions because v1 plugins 303 // are very slow, particularly if the plugin is down, and cause other issues, 304 // particularly around locking the store. 305 // TODO(cpuguy83): With v2 plugins this shouldn't be a problem. Could also potentially 306 // use a connect timeout for this kind of check to ensure we aren't blocking for a 307 // long time. 308 func (s *VolumeStore) checkConflict(name, driverName string) (volume.Volume, error) { 309 // check the local cache 310 v, _ := s.getNamed(name) 311 if v == nil { 312 return nil, nil 313 } 314 315 vDriverName := v.DriverName() 316 var conflict bool 317 if driverName != "" { 318 // Retrieve canonical driver name to avoid inconsistencies (for example 319 // "plugin" vs. "plugin:latest") 320 vd, err := volumedrivers.GetDriver(driverName) 321 if err != nil { 322 return nil, err 323 } 324 325 if vDriverName != vd.Name() { 326 conflict = true 327 } 328 } 329 330 // let's check if the found volume ref 331 // is stale by checking with the driver if it still exists 332 exists, err := volumeExists(v) 333 if err != nil { 334 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) 335 } 336 337 if exists { 338 if conflict { 339 return nil, errors.Wrapf(errNameConflict, "driver '%s' already has volume '%s'", vDriverName, name) 340 } 341 return v, nil 342 } 343 344 if s.hasRef(v.Name()) { 345 // Containers are referencing this volume but it doesn't seem to exist anywhere. 346 // Return a conflict error here, the user can fix this with `docker volume rm -f` 347 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) 348 } 349 350 // doesn't exist, so purge it from the cache 351 s.Purge(name) 352 return nil, nil 353 } 354 355 // volumeExists returns if the volume is still present in the driver. 356 // An error is returned if there was an issue communicating with the driver. 357 func volumeExists(v volume.Volume) (bool, error) { 358 exists, err := lookupVolume(v.DriverName(), v.Name()) 359 if err != nil { 360 return false, err 361 } 362 return exists != nil, nil 363 } 364 365 // create asks the given driver to create a volume with the name/opts. 366 // If a volume with the name is already known, it will ask the stored driver for the volume. 367 // If the passed in driver name does not match the driver name which is stored 368 // for the given volume name, an error is returned after checking if the reference is stale. 369 // If the reference is stale, it will be purged and this create can continue. 370 // It is expected that callers of this function hold any necessary locks. 371 func (s *VolumeStore) create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) { 372 // Validate the name in a platform-specific manner 373 374 // volume name validation is specific to the host os and not on container image 375 // windows/lcow should have an equivalent volumename validation logic so we create a parser for current host OS 376 parser := volume.NewParser(runtime.GOOS) 377 err := parser.ValidateVolumeName(name) 378 if err != nil { 379 return nil, err 380 } 381 382 v, err := s.checkConflict(name, driverName) 383 if err != nil { 384 return nil, err 385 } 386 387 if v != nil { 388 // there is an existing volume, if we already have this stored locally, return it. 389 // TODO: there could be some inconsistent details such as labels here 390 if vv, _ := s.getNamed(v.Name()); vv != nil { 391 return vv, nil 392 } 393 } 394 395 // Since there isn't a specified driver name, let's see if any of the existing drivers have this volume name 396 if driverName == "" { 397 v, _ = s.getVolume(name) 398 if v != nil { 399 return v, nil 400 } 401 } 402 403 vd, err := volumedrivers.CreateDriver(driverName) 404 if err != nil { 405 return nil, &OpErr{Op: "create", Name: name, Err: err} 406 } 407 408 logrus.Debugf("Registering new volume reference: driver %q, name %q", vd.Name(), name) 409 if v, _ = vd.Get(name); v == nil { 410 v, err = vd.Create(name, opts) 411 if err != nil { 412 if _, err := volumedrivers.ReleaseDriver(driverName); err != nil { 413 logrus.WithError(err).WithField("driver", driverName).Error("Error releasing reference to volume driver") 414 } 415 return nil, err 416 } 417 } 418 419 s.globalLock.Lock() 420 s.labels[name] = labels 421 s.options[name] = opts 422 s.refs[name] = make(map[string]struct{}) 423 s.globalLock.Unlock() 424 425 metadata := volumeMetadata{ 426 Name: name, 427 Driver: vd.Name(), 428 Labels: labels, 429 Options: opts, 430 } 431 432 if err := s.setMeta(name, metadata); err != nil { 433 return nil, err 434 } 435 return volumeWrapper{v, labels, vd.Scope(), opts}, nil 436 } 437 438 // GetWithRef gets a volume with the given name from the passed in driver and stores the ref 439 // This is just like Get(), but we store the reference while holding the lock. 440 // This makes sure there are no races between checking for the existence of a volume and adding a reference for it 441 func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, error) { 442 name = normalizeVolumeName(name) 443 s.locks.Lock(name) 444 defer s.locks.Unlock(name) 445 446 vd, err := volumedrivers.GetDriver(driverName) 447 if err != nil { 448 return nil, &OpErr{Err: err, Name: name, Op: "get"} 449 } 450 451 v, err := vd.Get(name) 452 if err != nil { 453 return nil, &OpErr{Err: err, Name: name, Op: "get"} 454 } 455 456 s.setNamed(v, ref) 457 458 s.globalLock.RLock() 459 defer s.globalLock.RUnlock() 460 return volumeWrapper{v, s.labels[name], vd.Scope(), s.options[name]}, nil 461 } 462 463 // Get looks if a volume with the given name exists and returns it if so 464 func (s *VolumeStore) Get(name string) (volume.Volume, error) { 465 name = normalizeVolumeName(name) 466 s.locks.Lock(name) 467 defer s.locks.Unlock(name) 468 469 v, err := s.getVolume(name) 470 if err != nil { 471 return nil, &OpErr{Err: err, Name: name, Op: "get"} 472 } 473 s.setNamed(v, "") 474 return v, nil 475 } 476 477 // getVolume requests the volume, if the driver info is stored it just accesses that driver, 478 // if the driver is unknown it probes all drivers until it finds the first volume with that name. 479 // it is expected that callers of this function hold any necessary locks 480 func (s *VolumeStore) getVolume(name string) (volume.Volume, error) { 481 var meta volumeMetadata 482 meta, err := s.getMeta(name) 483 if err != nil { 484 return nil, err 485 } 486 487 driverName := meta.Driver 488 if driverName == "" { 489 s.globalLock.RLock() 490 v, exists := s.names[name] 491 s.globalLock.RUnlock() 492 if exists { 493 meta.Driver = v.DriverName() 494 if err := s.setMeta(name, meta); err != nil { 495 return nil, err 496 } 497 } 498 } 499 500 if meta.Driver != "" { 501 vol, err := lookupVolume(meta.Driver, name) 502 if err != nil { 503 return nil, err 504 } 505 if vol == nil { 506 s.Purge(name) 507 return nil, errNoSuchVolume 508 } 509 510 var scope string 511 vd, err := volumedrivers.GetDriver(meta.Driver) 512 if err == nil { 513 scope = vd.Scope() 514 } 515 return volumeWrapper{vol, meta.Labels, scope, meta.Options}, nil 516 } 517 518 logrus.Debugf("Probing all drivers for volume with name: %s", name) 519 drivers, err := volumedrivers.GetAllDrivers() 520 if err != nil { 521 return nil, err 522 } 523 524 for _, d := range drivers { 525 v, err := d.Get(name) 526 if err != nil || v == nil { 527 continue 528 } 529 meta.Driver = v.DriverName() 530 if err := s.setMeta(name, meta); err != nil { 531 return nil, err 532 } 533 return volumeWrapper{v, meta.Labels, d.Scope(), meta.Options}, nil 534 } 535 return nil, errNoSuchVolume 536 } 537 538 // lookupVolume gets the specified volume from the specified driver. 539 // This will only return errors related to communications with the driver. 540 // If the driver returns an error that is not communication related the 541 // error is logged but not returned. 542 // If the volume is not found it will return `nil, nil`` 543 func lookupVolume(driverName, volumeName string) (volume.Volume, error) { 544 vd, err := volumedrivers.GetDriver(driverName) 545 if err != nil { 546 return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", volumeName, driverName) 547 } 548 v, err := vd.Get(volumeName) 549 if err != nil { 550 err = errors.Cause(err) 551 if _, ok := err.(net.Error); ok { 552 if v != nil { 553 volumeName = v.Name() 554 driverName = v.DriverName() 555 } 556 return nil, errors.Wrapf(err, "error while checking if volume %q exists in driver %q", volumeName, driverName) 557 } 558 559 // At this point, the error could be anything from the driver, such as "no such volume" 560 // Let's not check an error here, and instead check if the driver returned a volume 561 logrus.WithError(err).WithField("driver", driverName).WithField("volume", volumeName).Warnf("Error while looking up volume") 562 } 563 return v, nil 564 } 565 566 // Remove removes the requested volume. A volume is not removed if it has any refs 567 func (s *VolumeStore) Remove(v volume.Volume) error { 568 name := normalizeVolumeName(v.Name()) 569 s.locks.Lock(name) 570 defer s.locks.Unlock(name) 571 572 if s.hasRef(name) { 573 return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: s.getRefs(name)} 574 } 575 576 vd, err := volumedrivers.GetDriver(v.DriverName()) 577 if err != nil { 578 return &OpErr{Err: err, Name: v.DriverName(), Op: "remove"} 579 } 580 581 logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name) 582 vol := unwrapVolume(v) 583 if err := vd.Remove(vol); err != nil { 584 return &OpErr{Err: err, Name: name, Op: "remove"} 585 } 586 587 s.Purge(name) 588 return nil 589 } 590 591 // Dereference removes the specified reference to the volume 592 func (s *VolumeStore) Dereference(v volume.Volume, ref string) { 593 name := v.Name() 594 595 s.locks.Lock(name) 596 defer s.locks.Unlock(name) 597 598 s.globalLock.Lock() 599 defer s.globalLock.Unlock() 600 601 if s.refs[name] != nil { 602 delete(s.refs[name], ref) 603 } 604 } 605 606 // Refs gets the current list of refs for the given volume 607 func (s *VolumeStore) Refs(v volume.Volume) []string { 608 name := v.Name() 609 610 s.locks.Lock(name) 611 defer s.locks.Unlock(name) 612 613 return s.getRefs(name) 614 } 615 616 // FilterByDriver returns the available volumes filtered by driver name 617 func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) { 618 vd, err := volumedrivers.GetDriver(name) 619 if err != nil { 620 return nil, &OpErr{Err: err, Name: name, Op: "list"} 621 } 622 ls, err := vd.List() 623 if err != nil { 624 return nil, &OpErr{Err: err, Name: name, Op: "list"} 625 } 626 for i, v := range ls { 627 options := map[string]string{} 628 s.globalLock.RLock() 629 for key, value := range s.options[v.Name()] { 630 options[key] = value 631 } 632 ls[i] = volumeWrapper{v, s.labels[v.Name()], vd.Scope(), options} 633 s.globalLock.RUnlock() 634 } 635 return ls, nil 636 } 637 638 // FilterByUsed returns the available volumes filtered by if they are in use or not. 639 // `used=true` returns only volumes that are being used, while `used=false` returns 640 // only volumes that are not being used. 641 func (s *VolumeStore) FilterByUsed(vols []volume.Volume, used bool) []volume.Volume { 642 return s.filter(vols, func(v volume.Volume) bool { 643 s.locks.Lock(v.Name()) 644 hasRef := s.hasRef(v.Name()) 645 s.locks.Unlock(v.Name()) 646 return used == hasRef 647 }) 648 } 649 650 // filterFunc defines a function to allow filter volumes in the store 651 type filterFunc func(vol volume.Volume) bool 652 653 // filter returns the available volumes filtered by a filterFunc function 654 func (s *VolumeStore) filter(vols []volume.Volume, f filterFunc) []volume.Volume { 655 var ls []volume.Volume 656 for _, v := range vols { 657 if f(v) { 658 ls = append(ls, v) 659 } 660 } 661 return ls 662 } 663 664 func unwrapVolume(v volume.Volume) volume.Volume { 665 if vol, ok := v.(volumeWrapper); ok { 666 return vol.Volume 667 } 668 669 return v 670 } 671 672 // Shutdown releases all resources used by the volume store 673 // It does not make any changes to volumes, drivers, etc. 674 func (s *VolumeStore) Shutdown() error { 675 return s.db.Close() 676 }