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