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