github.com/vieux/docker@v0.6.3-0.20161004191708-e097c2a938c7/volume/store/store.go (about)

     1  package store
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"os"
     7  	"path/filepath"
     8  	"sync"
     9  	"time"
    10  
    11  	"github.com/pkg/errors"
    12  
    13  	"github.com/Sirupsen/logrus"
    14  	"github.com/boltdb/bolt"
    15  	"github.com/docker/docker/pkg/locker"
    16  	"github.com/docker/docker/volume"
    17  	"github.com/docker/docker/volume/drivers"
    18  )
    19  
    20  const (
    21  	volumeDataDir    = "volumes"
    22  	volumeBucketName = "volumes"
    23  )
    24  
    25  type volumeMetadata struct {
    26  	Name   string
    27  	Labels map[string]string
    28  }
    29  
    30  type volumeWrapper struct {
    31  	volume.Volume
    32  	labels map[string]string
    33  	scope  string
    34  }
    35  
    36  func (v volumeWrapper) Labels() map[string]string {
    37  	return v.labels
    38  }
    39  
    40  func (v volumeWrapper) Scope() string {
    41  	return v.scope
    42  }
    43  
    44  func (v volumeWrapper) CachedPath() string {
    45  	if vv, ok := v.Volume.(interface {
    46  		CachedPath() string
    47  	}); ok {
    48  		return vv.CachedPath()
    49  	}
    50  	return v.Volume.Path()
    51  }
    52  
    53  // New initializes a VolumeStore to keep
    54  // reference counting of volumes in the system.
    55  func New(rootPath string) (*VolumeStore, error) {
    56  	vs := &VolumeStore{
    57  		locks:  &locker.Locker{},
    58  		names:  make(map[string]volume.Volume),
    59  		refs:   make(map[string][]string),
    60  		labels: make(map[string]map[string]string),
    61  	}
    62  
    63  	if rootPath != "" {
    64  		// initialize metadata store
    65  		volPath := filepath.Join(rootPath, volumeDataDir)
    66  		if err := os.MkdirAll(volPath, 750); err != nil {
    67  			return nil, err
    68  		}
    69  
    70  		dbPath := filepath.Join(volPath, "metadata.db")
    71  
    72  		var err error
    73  		vs.db, err = bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
    74  		if err != nil {
    75  			return nil, errors.Wrap(err, "error while opening volume store metadata database")
    76  		}
    77  
    78  		// initialize volumes bucket
    79  		if err := vs.db.Update(func(tx *bolt.Tx) error {
    80  			if _, err := tx.CreateBucketIfNotExists([]byte(volumeBucketName)); err != nil {
    81  				return errors.Wrap(err, "error while setting up volume store metadata database")
    82  			}
    83  
    84  			return nil
    85  		}); err != nil {
    86  			return nil, err
    87  		}
    88  	}
    89  
    90  	return vs, nil
    91  }
    92  
    93  func (s *VolumeStore) getNamed(name string) (volume.Volume, bool) {
    94  	s.globalLock.Lock()
    95  	v, exists := s.names[name]
    96  	s.globalLock.Unlock()
    97  	return v, exists
    98  }
    99  
   100  func (s *VolumeStore) setNamed(v volume.Volume, ref string) {
   101  	s.globalLock.Lock()
   102  	s.names[v.Name()] = v
   103  	if len(ref) > 0 {
   104  		s.refs[v.Name()] = append(s.refs[v.Name()], ref)
   105  	}
   106  	s.globalLock.Unlock()
   107  }
   108  
   109  // Purge allows the cleanup of internal data on docker in case
   110  // the internal data is out of sync with volumes driver plugins.
   111  func (s *VolumeStore) Purge(name string) {
   112  	s.globalLock.Lock()
   113  	delete(s.names, name)
   114  	delete(s.refs, name)
   115  	delete(s.labels, name)
   116  	s.globalLock.Unlock()
   117  }
   118  
   119  // VolumeStore is a struct that stores the list of volumes available and keeps track of their usage counts
   120  type VolumeStore struct {
   121  	locks      *locker.Locker
   122  	globalLock sync.Mutex
   123  	// names stores the volume name -> driver name relationship.
   124  	// This is used for making lookups faster so we don't have to probe all drivers
   125  	names map[string]volume.Volume
   126  	// refs stores the volume name and the list of things referencing it
   127  	refs map[string][]string
   128  	// labels stores volume labels for each volume
   129  	labels map[string]map[string]string
   130  	db     *bolt.DB
   131  }
   132  
   133  // List proxies to all registered volume drivers to get the full list of volumes
   134  // If a driver returns a volume that has name which conflicts with another volume from a different driver,
   135  // the first volume is chosen and the conflicting volume is dropped.
   136  func (s *VolumeStore) List() ([]volume.Volume, []string, error) {
   137  	vols, warnings, err := s.list()
   138  	if err != nil {
   139  		return nil, nil, &OpErr{Err: err, Op: "list"}
   140  	}
   141  	var out []volume.Volume
   142  
   143  	for _, v := range vols {
   144  		name := normaliseVolumeName(v.Name())
   145  
   146  		s.locks.Lock(name)
   147  		storedV, exists := s.getNamed(name)
   148  		// Note: it's not safe to populate the cache here because the volume may have been
   149  		// deleted before we acquire a lock on its name
   150  		if exists && storedV.DriverName() != v.DriverName() {
   151  			logrus.Warnf("Volume name %s already exists for driver %s, not including volume returned by %s", v.Name(), storedV.DriverName(), v.DriverName())
   152  			s.locks.Unlock(v.Name())
   153  			continue
   154  		}
   155  
   156  		out = append(out, v)
   157  		s.locks.Unlock(v.Name())
   158  	}
   159  	return out, warnings, nil
   160  }
   161  
   162  // list goes through each volume driver and asks for its list of volumes.
   163  func (s *VolumeStore) list() ([]volume.Volume, []string, error) {
   164  	var (
   165  		ls       []volume.Volume
   166  		warnings []string
   167  	)
   168  
   169  	drivers, err := volumedrivers.GetAllDrivers()
   170  	if err != nil {
   171  		return nil, nil, err
   172  	}
   173  
   174  	type vols struct {
   175  		vols       []volume.Volume
   176  		err        error
   177  		driverName string
   178  	}
   179  	chVols := make(chan vols, len(drivers))
   180  
   181  	for _, vd := range drivers {
   182  		go func(d volume.Driver) {
   183  			vs, err := d.List()
   184  			if err != nil {
   185  				chVols <- vols{driverName: d.Name(), err: &OpErr{Err: err, Name: d.Name(), Op: "list"}}
   186  				return
   187  			}
   188  			for i, v := range vs {
   189  				vs[i] = volumeWrapper{v, s.labels[v.Name()], d.Scope()}
   190  			}
   191  
   192  			chVols <- vols{vols: vs}
   193  		}(vd)
   194  	}
   195  
   196  	badDrivers := make(map[string]struct{})
   197  	for i := 0; i < len(drivers); i++ {
   198  		vs := <-chVols
   199  
   200  		if vs.err != nil {
   201  			warnings = append(warnings, vs.err.Error())
   202  			badDrivers[vs.driverName] = struct{}{}
   203  			logrus.Warn(vs.err)
   204  		}
   205  		ls = append(ls, vs.vols...)
   206  	}
   207  
   208  	if len(badDrivers) > 0 {
   209  		for _, v := range s.names {
   210  			if _, exists := badDrivers[v.DriverName()]; exists {
   211  				ls = append(ls, v)
   212  			}
   213  		}
   214  	}
   215  	return ls, warnings, nil
   216  }
   217  
   218  // CreateWithRef creates a volume with the given name and driver and stores the ref
   219  // This ensures there's no race between creating a volume and then storing a reference.
   220  func (s *VolumeStore) CreateWithRef(name, driverName, ref string, opts, labels map[string]string) (volume.Volume, error) {
   221  	name = normaliseVolumeName(name)
   222  	s.locks.Lock(name)
   223  	defer s.locks.Unlock(name)
   224  
   225  	v, err := s.create(name, driverName, opts, labels)
   226  	if err != nil {
   227  		return nil, &OpErr{Err: err, Name: name, Op: "create"}
   228  	}
   229  
   230  	s.setNamed(v, ref)
   231  	return v, nil
   232  }
   233  
   234  // Create creates a volume with the given name and driver.
   235  // This is just like CreateWithRef() except we don't store a reference while holding the lock.
   236  func (s *VolumeStore) Create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) {
   237  	return s.CreateWithRef(name, driverName, "", opts, labels)
   238  }
   239  
   240  // create asks the given driver to create a volume with the name/opts.
   241  // If a volume with the name is already known, it will ask the stored driver for the volume.
   242  // If the passed in driver name does not match the driver name which is stored for the given volume name, an error is returned.
   243  // It is expected that callers of this function hold any necessary locks.
   244  func (s *VolumeStore) create(name, driverName string, opts, labels map[string]string) (volume.Volume, error) {
   245  	// Validate the name in a platform-specific manner
   246  	valid, err := volume.IsVolumeNameValid(name)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  	if !valid {
   251  		return nil, &OpErr{Err: errInvalidName, Name: name, Op: "create"}
   252  	}
   253  
   254  	if v, exists := s.getNamed(name); exists {
   255  		if v.DriverName() != driverName && driverName != "" && driverName != volume.DefaultDriverName {
   256  			return nil, errNameConflict
   257  		}
   258  		return v, nil
   259  	}
   260  
   261  	// Since there isn't a specified driver name, let's see if any of the existing drivers have this volume name
   262  	if driverName == "" {
   263  		v, _ := s.getVolume(name)
   264  		if v != nil {
   265  			return v, nil
   266  		}
   267  	}
   268  
   269  	vd, err := volumedrivers.CreateDriver(driverName)
   270  
   271  	if err != nil {
   272  		return nil, &OpErr{Op: "create", Name: name, Err: err}
   273  	}
   274  
   275  	logrus.Debugf("Registering new volume reference: driver %q, name %q", vd.Name(), name)
   276  
   277  	if v, _ := vd.Get(name); v != nil {
   278  		return v, nil
   279  	}
   280  	v, err := vd.Create(name, opts)
   281  	if err != nil {
   282  		return nil, err
   283  	}
   284  	s.globalLock.Lock()
   285  	s.labels[name] = labels
   286  	s.globalLock.Unlock()
   287  
   288  	if s.db != nil {
   289  		metadata := &volumeMetadata{
   290  			Name:   name,
   291  			Labels: labels,
   292  		}
   293  
   294  		volData, err := json.Marshal(metadata)
   295  		if err != nil {
   296  			return nil, err
   297  		}
   298  
   299  		if err := s.db.Update(func(tx *bolt.Tx) error {
   300  			b := tx.Bucket([]byte(volumeBucketName))
   301  			err := b.Put([]byte(name), volData)
   302  			return err
   303  		}); err != nil {
   304  			return nil, errors.Wrap(err, "error while persisting volume metadata")
   305  		}
   306  	}
   307  
   308  	return volumeWrapper{v, labels, vd.Scope()}, nil
   309  }
   310  
   311  // GetWithRef gets a volume with the given name from the passed in driver and stores the ref
   312  // This is just like Get(), but we store the reference while holding the lock.
   313  // This makes sure there are no races between checking for the existence of a volume and adding a reference for it
   314  func (s *VolumeStore) GetWithRef(name, driverName, ref string) (volume.Volume, error) {
   315  	name = normaliseVolumeName(name)
   316  	s.locks.Lock(name)
   317  	defer s.locks.Unlock(name)
   318  
   319  	vd, err := volumedrivers.GetDriver(driverName)
   320  	if err != nil {
   321  		return nil, &OpErr{Err: err, Name: name, Op: "get"}
   322  	}
   323  
   324  	v, err := vd.Get(name)
   325  	if err != nil {
   326  		return nil, &OpErr{Err: err, Name: name, Op: "get"}
   327  	}
   328  
   329  	s.setNamed(v, ref)
   330  
   331  	return volumeWrapper{v, s.labels[name], vd.Scope()}, nil
   332  }
   333  
   334  // Get looks if a volume with the given name exists and returns it if so
   335  func (s *VolumeStore) Get(name string) (volume.Volume, error) {
   336  	name = normaliseVolumeName(name)
   337  	s.locks.Lock(name)
   338  	defer s.locks.Unlock(name)
   339  
   340  	v, err := s.getVolume(name)
   341  	if err != nil {
   342  		return nil, &OpErr{Err: err, Name: name, Op: "get"}
   343  	}
   344  	s.setNamed(v, "")
   345  	return v, nil
   346  }
   347  
   348  // getVolume requests the volume, if the driver info is stored it just accesses that driver,
   349  // if the driver is unknown it probes all drivers until it finds the first volume with that name.
   350  // it is expected that callers of this function hold any necessary locks
   351  func (s *VolumeStore) getVolume(name string) (volume.Volume, error) {
   352  	labels := map[string]string{}
   353  
   354  	if s.db != nil {
   355  		// get meta
   356  		if err := s.db.Update(func(tx *bolt.Tx) error {
   357  			b := tx.Bucket([]byte(volumeBucketName))
   358  			data := b.Get([]byte(name))
   359  
   360  			if string(data) == "" {
   361  				return nil
   362  			}
   363  
   364  			var meta volumeMetadata
   365  			buf := bytes.NewBuffer(data)
   366  
   367  			if err := json.NewDecoder(buf).Decode(&meta); err != nil {
   368  				return err
   369  			}
   370  			labels = meta.Labels
   371  
   372  			return nil
   373  		}); err != nil {
   374  			return nil, err
   375  		}
   376  	}
   377  
   378  	logrus.Debugf("Getting volume reference for name: %s", name)
   379  	s.globalLock.Lock()
   380  	v, exists := s.names[name]
   381  	s.globalLock.Unlock()
   382  	if exists {
   383  		vd, err := volumedrivers.GetDriver(v.DriverName())
   384  		if err != nil {
   385  			return nil, err
   386  		}
   387  		vol, err := vd.Get(name)
   388  		if err != nil {
   389  			return nil, err
   390  		}
   391  		return volumeWrapper{vol, labels, vd.Scope()}, nil
   392  	}
   393  
   394  	logrus.Debugf("Probing all drivers for volume with name: %s", name)
   395  	drivers, err := volumedrivers.GetAllDrivers()
   396  	if err != nil {
   397  		return nil, err
   398  	}
   399  
   400  	for _, d := range drivers {
   401  		v, err := d.Get(name)
   402  		if err != nil {
   403  			continue
   404  		}
   405  
   406  		return volumeWrapper{v, labels, d.Scope()}, nil
   407  	}
   408  	return nil, errNoSuchVolume
   409  }
   410  
   411  // Remove removes the requested volume. A volume is not removed if it has any refs
   412  func (s *VolumeStore) Remove(v volume.Volume) error {
   413  	name := normaliseVolumeName(v.Name())
   414  	s.locks.Lock(name)
   415  	defer s.locks.Unlock(name)
   416  
   417  	if refs, exists := s.refs[name]; exists && len(refs) > 0 {
   418  		return &OpErr{Err: errVolumeInUse, Name: v.Name(), Op: "remove", Refs: refs}
   419  	}
   420  
   421  	vd, err := volumedrivers.RemoveDriver(v.DriverName())
   422  	if err != nil {
   423  		return &OpErr{Err: err, Name: vd.Name(), Op: "remove"}
   424  	}
   425  
   426  	logrus.Debugf("Removing volume reference: driver %s, name %s", v.DriverName(), name)
   427  	vol := unwrapVolume(v)
   428  	if err := vd.Remove(vol); err != nil {
   429  		return &OpErr{Err: err, Name: name, Op: "remove"}
   430  	}
   431  
   432  	s.Purge(name)
   433  	return nil
   434  }
   435  
   436  // Dereference removes the specified reference to the volume
   437  func (s *VolumeStore) Dereference(v volume.Volume, ref string) {
   438  	s.locks.Lock(v.Name())
   439  	defer s.locks.Unlock(v.Name())
   440  
   441  	s.globalLock.Lock()
   442  	defer s.globalLock.Unlock()
   443  	var refs []string
   444  
   445  	for _, r := range s.refs[v.Name()] {
   446  		if r != ref {
   447  			refs = append(refs, r)
   448  		}
   449  	}
   450  	s.refs[v.Name()] = refs
   451  }
   452  
   453  // Refs gets the current list of refs for the given volume
   454  func (s *VolumeStore) Refs(v volume.Volume) []string {
   455  	s.locks.Lock(v.Name())
   456  	defer s.locks.Unlock(v.Name())
   457  
   458  	s.globalLock.Lock()
   459  	defer s.globalLock.Unlock()
   460  	refs, exists := s.refs[v.Name()]
   461  	if !exists {
   462  		return nil
   463  	}
   464  
   465  	refsOut := make([]string, len(refs))
   466  	copy(refsOut, refs)
   467  	return refsOut
   468  }
   469  
   470  // FilterByDriver returns the available volumes filtered by driver name
   471  func (s *VolumeStore) FilterByDriver(name string) ([]volume.Volume, error) {
   472  	vd, err := volumedrivers.GetDriver(name)
   473  	if err != nil {
   474  		return nil, &OpErr{Err: err, Name: name, Op: "list"}
   475  	}
   476  	ls, err := vd.List()
   477  	if err != nil {
   478  		return nil, &OpErr{Err: err, Name: name, Op: "list"}
   479  	}
   480  	for i, v := range ls {
   481  		ls[i] = volumeWrapper{v, s.labels[v.Name()], vd.Scope()}
   482  	}
   483  	return ls, nil
   484  }
   485  
   486  // FilterByUsed returns the available volumes filtered by if they are in use or not.
   487  // `used=true` returns only volumes that are being used, while `used=false` returns
   488  // only volumes that are not being used.
   489  func (s *VolumeStore) FilterByUsed(vols []volume.Volume, used bool) []volume.Volume {
   490  	return s.filter(vols, func(v volume.Volume) bool {
   491  		s.locks.Lock(v.Name())
   492  		l := len(s.refs[v.Name()])
   493  		s.locks.Unlock(v.Name())
   494  		if (used && l > 0) || (!used && l == 0) {
   495  			return true
   496  		}
   497  		return false
   498  	})
   499  }
   500  
   501  // filterFunc defines a function to allow filter volumes in the store
   502  type filterFunc func(vol volume.Volume) bool
   503  
   504  // filter returns the available volumes filtered by a filterFunc function
   505  func (s *VolumeStore) filter(vols []volume.Volume, f filterFunc) []volume.Volume {
   506  	var ls []volume.Volume
   507  	for _, v := range vols {
   508  		if f(v) {
   509  			ls = append(ls, v)
   510  		}
   511  	}
   512  	return ls
   513  }
   514  
   515  func unwrapVolume(v volume.Volume) volume.Volume {
   516  	if vol, ok := v.(volumeWrapper); ok {
   517  		return vol.Volume
   518  	}
   519  
   520  	return v
   521  }