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  }