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