2015-09-18 19:58:05 -04:00
package store
import (
2016-03-16 17:52:34 -04:00
"bytes"
"encoding/json"
2016-10-05 14:39:45 -04:00
"net"
2016-03-16 17:52:34 -04:00
"os"
"path/filepath"
2015-09-18 19:58:05 -04:00
"sync"
2016-03-16 17:52:34 -04:00
"time"
2015-09-18 19:58:05 -04:00
2016-09-23 10:38:19 -04:00
"github.com/pkg/errors"
2015-09-18 19:58:05 -04:00
"github.com/Sirupsen/logrus"
2016-03-16 17:52:34 -04:00
"github.com/boltdb/bolt"
2015-10-19 16:43:56 -04:00
"github.com/docker/docker/pkg/locker"
2015-09-18 19:58:05 -04:00
"github.com/docker/docker/volume"
"github.com/docker/docker/volume/drivers"
)
2016-03-16 17:52:34 -04:00
const (
volumeDataDir = "volumes"
volumeBucketName = "volumes"
)
type volumeMetadata struct {
2016-09-17 15:32:31 -04:00
Name string
Labels map [ string ] string
Options map [ string ] string
2016-03-16 17:52:34 -04:00
}
2016-04-11 11:17:52 -04:00
type volumeWrapper struct {
2016-03-16 17:52:34 -04:00
volume . Volume
2016-09-17 15:32:31 -04:00
labels map [ string ] string
scope string
options map [ string ] string
}
func ( v volumeWrapper ) Options ( ) map [ string ] string {
options := map [ string ] string { }
for key , value := range v . options {
options [ key ] = value
}
return options
2016-03-16 17:52:34 -04:00
}
2016-04-11 11:17:52 -04:00
func ( v volumeWrapper ) Labels ( ) map [ string ] string {
2016-03-16 17:52:34 -04:00
return v . labels
}
2016-04-11 11:17:52 -04:00
func ( v volumeWrapper ) Scope ( ) string {
return v . scope
}
func ( v volumeWrapper ) CachedPath ( ) string {
if vv , ok := v . Volume . ( interface {
CachedPath ( ) string
} ) ; ok {
return vv . CachedPath ( )
}
return v . Volume . Path ( )
}
2015-09-18 19:58:05 -04:00
// New initializes a VolumeStore to keep
// reference counting of volumes in the system.
2016-03-16 17:52:34 -04:00
func New ( rootPath string ) ( * VolumeStore , error ) {
vs := & VolumeStore {
2016-09-17 15:32:31 -04:00
locks : & locker . Locker { } ,
names : make ( map [ string ] volume . Volume ) ,
refs : make ( map [ string ] [ ] string ) ,
labels : make ( map [ string ] map [ string ] string ) ,
options : make ( map [ string ] map [ string ] string ) ,
2015-09-18 19:58:05 -04:00
}
2016-03-16 17:52:34 -04:00
if rootPath != "" {
// initialize metadata store
volPath := filepath . Join ( rootPath , volumeDataDir )
if err := os . MkdirAll ( volPath , 750 ) ; err != nil {
return nil , err
}
dbPath := filepath . Join ( volPath , "metadata.db" )
var err error
vs . db , err = bolt . Open ( dbPath , 0600 , & bolt . Options { Timeout : 1 * time . Second } )
if err != nil {
2016-09-23 10:38:19 -04:00
return nil , errors . Wrap ( err , "error while opening volume store metadata database" )
2016-03-16 17:52:34 -04:00
}
// initialize volumes bucket
if err := vs . db . Update ( func ( tx * bolt . Tx ) error {
if _ , err := tx . CreateBucketIfNotExists ( [ ] byte ( volumeBucketName ) ) ; err != nil {
2016-09-23 10:38:19 -04:00
return errors . Wrap ( err , "error while setting up volume store metadata database" )
2016-03-16 17:52:34 -04:00
}
return nil
} ) ; err != nil {
return nil , err
}
}
return vs , nil
2015-09-18 19:58:05 -04:00
}
2016-01-20 22:31:46 -05:00
func ( s * VolumeStore ) getNamed ( name string ) ( volume . Volume , bool ) {
2015-10-19 16:43:56 -04:00
s . globalLock . Lock ( )
2016-01-20 22:31:46 -05:00
v , exists := s . names [ name ]
2015-10-19 16:43:56 -04:00
s . globalLock . Unlock ( )
2016-01-20 22:31:46 -05:00
return v , exists
2015-10-19 16:43:56 -04:00
}
2016-01-20 22:31:46 -05:00
func ( s * VolumeStore ) setNamed ( v volume . Volume , ref string ) {
2015-10-19 16:43:56 -04:00
s . globalLock . Lock ( )
2016-01-20 22:31:46 -05:00
s . names [ v . Name ( ) ] = v
2015-09-23 16:29:14 -04:00
if len ( ref ) > 0 {
2016-01-20 22:31:46 -05:00
s . refs [ v . Name ( ) ] = append ( s . refs [ v . Name ( ) ] , ref )
2015-09-23 16:29:14 -04:00
}
2015-10-19 16:43:56 -04:00
s . globalLock . Unlock ( )
}
2016-10-05 14:39:45 -04:00
// getRefs gets the list of refs for a given name
// Callers of this function are expected to hold the name lock.
func ( s * VolumeStore ) getRefs ( name string ) [ ] string {
s . globalLock . Lock ( )
refs := s . refs [ name ]
s . globalLock . Unlock ( )
return refs
}
2016-06-10 10:40:09 -04:00
// Purge allows the cleanup of internal data on docker in case
// the internal data is out of sync with volumes driver plugins.
func ( s * VolumeStore ) Purge ( name string ) {
2015-10-19 16:43:56 -04:00
s . globalLock . Lock ( )
2015-09-23 16:29:14 -04:00
delete ( s . names , name )
delete ( s . refs , name )
2016-03-16 17:52:34 -04:00
delete ( s . labels , name )
2016-09-17 15:32:31 -04:00
delete ( s . options , name )
2015-10-19 16:43:56 -04:00
s . globalLock . Unlock ( )
}
2015-09-18 19:58:05 -04:00
// VolumeStore is a struct that stores the list of volumes available and keeps track of their usage counts
type VolumeStore struct {
2015-10-19 16:43:56 -04:00
locks * locker . Locker
globalLock sync . Mutex
2016-11-13 20:55:27 -05:00
// names stores the volume name -> volume relationship.
2015-09-23 16:29:14 -04:00
// This is used for making lookups faster so we don't have to probe all drivers
2016-01-20 22:31:46 -05:00
names map [ string ] volume . Volume
2015-09-23 16:29:14 -04:00
// refs stores the volume name and the list of things referencing it
refs map [ string ] [ ] string
2016-03-16 17:52:34 -04:00
// labels stores volume labels for each volume
labels map [ string ] map [ string ] string
2016-09-17 15:32:31 -04:00
// options stores volume options for each volume
options map [ string ] map [ string ] string
db * bolt . DB
2015-09-18 19:58:05 -04:00
}
2015-09-23 16:29:14 -04:00
// List proxies to all registered volume drivers to get the full list of volumes
2016-03-09 11:17:57 -05:00
// If a driver returns a volume that has name which conflicts with another volume from a different driver,
2015-09-23 16:29:14 -04:00
// the first volume is chosen and the conflicting volume is dropped.
func ( s * VolumeStore ) List ( ) ( [ ] volume . Volume , [ ] string , error ) {
vols , warnings , err := s . list ( )
if err != nil {
return nil , nil , & OpErr { Err : err , Op : "list" }
}
var out [ ] volume . Volume
2015-09-18 19:58:05 -04:00
for _ , v := range vols {
2015-09-23 16:29:14 -04:00
name := normaliseVolumeName ( v . Name ( ) )
s . locks . Lock ( name )
2016-01-20 22:31:46 -05:00
storedV , exists := s . getNamed ( name )
2016-03-22 16:24:09 -04:00
// Note: it's not safe to populate the cache here because the volume may have been
// deleted before we acquire a lock on its name
2016-01-20 22:31:46 -05:00
if exists && storedV . DriverName ( ) != v . DriverName ( ) {
logrus . Warnf ( "Volume name %s already exists for driver %s, not including volume returned by %s" , v . Name ( ) , storedV . DriverName ( ) , v . DriverName ( ) )
2015-09-23 16:29:14 -04:00
s . locks . Unlock ( v . Name ( ) )
continue
}
out = append ( out , v )
s . locks . Unlock ( v . Name ( ) )
2015-09-18 19:58:05 -04:00
}
2015-09-23 16:29:14 -04:00
return out , warnings , nil
2015-09-18 19:58:05 -04:00
}
2015-09-23 16:29:14 -04:00
// list goes through each volume driver and asks for its list of volumes.
func ( s * VolumeStore ) list ( ) ( [ ] volume . Volume , [ ] string , error ) {
var (
ls [ ] volume . Volume
warnings [ ] string
)
2016-05-16 11:50:55 -04:00
drivers , err := volumedrivers . GetAllDrivers ( )
if err != nil {
return nil , nil , err
}
2015-09-23 16:29:14 -04:00
type vols struct {
2016-01-20 22:31:46 -05:00
vols [ ] volume . Volume
err error
driverName string
2015-09-23 16:29:14 -04:00
}
chVols := make ( chan vols , len ( drivers ) )
for _ , vd := range drivers {
go func ( d volume . Driver ) {
vs , err := d . List ( )
if err != nil {
2016-01-20 22:31:46 -05:00
chVols <- vols { driverName : d . Name ( ) , err : & OpErr { Err : err , Name : d . Name ( ) , Op : "list" } }
2015-09-23 16:29:14 -04:00
return
}
2016-04-11 11:17:52 -04:00
for i , v := range vs {
2016-09-17 15:32:31 -04:00
vs [ i ] = volumeWrapper { v , s . labels [ v . Name ( ) ] , d . Scope ( ) , s . options [ v . Name ( ) ] }
2016-04-11 11:17:52 -04:00
}
2015-09-23 16:29:14 -04:00
chVols <- vols { vols : vs }
} ( vd )
}
2016-01-20 22:31:46 -05:00
badDrivers := make ( map [ string ] struct { } )
2015-09-23 16:29:14 -04:00
for i := 0 ; i < len ( drivers ) ; i ++ {
vs := <- chVols
if vs . err != nil {
warnings = append ( warnings , vs . err . Error ( ) )
2016-01-20 22:31:46 -05:00
badDrivers [ vs . driverName ] = struct { } { }
2015-09-23 16:29:14 -04:00
logrus . Warn ( vs . err )
}
ls = append ( ls , vs . vols ... )
}
2016-01-20 22:31:46 -05:00
if len ( badDrivers ) > 0 {
for _ , v := range s . names {
if _ , exists := badDrivers [ v . DriverName ( ) ] ; exists {
ls = append ( ls , v )
}
}
}
2015-09-23 16:29:14 -04:00
return ls , warnings , nil
}
// CreateWithRef creates a volume with the given name and driver and stores the ref
// This ensures there's no race between creating a volume and then storing a reference.
2016-03-16 17:52:34 -04:00
func ( s * VolumeStore ) CreateWithRef ( name , driverName , ref string , opts , labels map [ string ] string ) ( volume . Volume , error ) {
2015-09-09 22:23:06 -04:00
name = normaliseVolumeName ( name )
2015-10-19 16:43:56 -04:00
s . locks . Lock ( name )
defer s . locks . Unlock ( name )
2016-03-16 17:52:34 -04:00
v , err := s . create ( name , driverName , opts , labels )
2015-09-23 16:29:14 -04:00
if err != nil {
return nil , & OpErr { Err : err , Name : name , Op : "create" }
2015-09-18 19:58:05 -04:00
}
2016-01-20 22:31:46 -05:00
s . setNamed ( v , ref )
2015-09-23 16:29:14 -04:00
return v , nil
}
// Create creates a volume with the given name and driver.
2016-07-06 18:09:47 -04:00
// This is just like CreateWithRef() except we don't store a reference while holding the lock.
2016-03-16 17:52:34 -04:00
func ( s * VolumeStore ) Create ( name , driverName string , opts , labels map [ string ] string ) ( volume . Volume , error ) {
2016-07-06 18:09:47 -04:00
return s . CreateWithRef ( name , driverName , "" , opts , labels )
2015-09-23 16:29:14 -04:00
}
2015-09-18 19:58:05 -04:00
2016-10-05 14:39:45 -04:00
// checkConflict checks the local cache for name collisions with the passed in name,
// for existing volumes with the same name but in a different driver.
// This is used by `Create` as a best effort to prevent name collisions for volumes.
// If a matching volume is found that is not a conflict that is returned so the caller
// does not need to perform an additional lookup.
// When no matching volume is found, both returns will be nil
//
// Note: This does not probe all the drivers for name collisions because v1 plugins
// are very slow, particularly if the plugin is down, and cause other issues,
// particularly around locking the store.
// TODO(cpuguy83): With v2 plugins this shouldn't be a problem. Could also potentially
// use a connect timeout for this kind of check to ensure we aren't blocking for a
// long time.
func ( s * VolumeStore ) checkConflict ( name , driverName string ) ( volume . Volume , error ) {
// check the local cache
v , _ := s . getNamed ( name )
if v != nil {
vDriverName := v . DriverName ( )
if driverName != "" && vDriverName != driverName {
// we have what looks like a conflict
// let's see if there are existing refs to this volume, if so we don't need
// to go any further since we can assume the volume is legit.
if len ( s . getRefs ( name ) ) > 0 {
return nil , errors . Wrapf ( errNameConflict , "driver '%s' already has volume '%s'" , vDriverName , name )
}
// looks like there is a conflict, but nothing is referencing it...
// let's check if the found volume ref
// is stale by checking with the driver if it still exists
vd , err := volumedrivers . GetDriver ( vDriverName )
if err != nil {
// play it safe and return the error
// TODO(cpuguy83): maybe when when v2 plugins are ubiquitous, we should
// just purge this from the cache
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 )
}
// now check if it still exists in the driver
v2 , err := vd . Get ( name )
err = errors . Cause ( err )
if err != nil {
if _ , ok := err . ( net . Error ) ; ok {
// got some error related to the driver connectivity
// play it safe and return the error
// TODO(cpuguy83): When when v2 plugins are ubiquitous, maybe we should
// just purge this from the cache
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 )
}
// a driver can return whatever it wants, so let's make sure this is nil
if v2 == nil {
// purge this reference from the cache
s . Purge ( name )
return nil , nil
}
}
if v2 != nil {
return nil , errors . Wrapf ( errNameConflict , "driver '%s' already has volume '%s'" , vDriverName , name )
}
}
return v , nil
}
return nil , nil
}
2015-09-23 16:29:14 -04:00
// create asks the given driver to create a volume with the name/opts.
// If a volume with the name is already known, it will ask the stored driver for the volume.
2016-10-05 14:39:45 -04:00
// If the passed in driver name does not match the driver name which is stored
// for the given volume name, an error is returned after checking if the reference is stale.
// If the reference is stale, it will be purged and this create can continue.
2016-02-11 18:21:52 -05:00
// It is expected that callers of this function hold any necessary locks.
2016-03-16 17:52:34 -04:00
func ( s * VolumeStore ) create ( name , driverName string , opts , labels map [ string ] string ) ( volume . Volume , error ) {
2015-09-09 22:23:06 -04:00
// Validate the name in a platform-specific manner
valid , err := volume . IsVolumeNameValid ( name )
if err != nil {
return nil , err
}
if ! valid {
2015-10-19 20:41:22 -04:00
return nil , & OpErr { Err : errInvalidName , Name : name , Op : "create" }
2015-09-09 22:23:06 -04:00
}
2016-10-05 14:39:45 -04:00
v , err := s . checkConflict ( name , driverName )
if err != nil {
return nil , err
}
if v != nil {
return v , nil
2015-09-23 16:29:14 -04:00
}
2016-02-10 12:02:52 -05:00
// Since there isn't a specified driver name, let's see if any of the existing drivers have this volume name
if driverName == "" {
v , _ := s . getVolume ( name )
if v != nil {
return v , nil
}
}
2016-09-07 09:59:15 -04:00
vd , err := volumedrivers . CreateDriver ( driverName )
2016-03-03 02:23:49 -05:00
2015-09-18 19:58:05 -04:00
if err != nil {
2015-10-19 20:41:22 -04:00
return nil , & OpErr { Op : "create" , Name : name , Err : err }
2015-09-18 19:58:05 -04:00
}
2016-03-03 02:23:49 -05:00
logrus . Debugf ( "Registering new volume reference: driver %q, name %q" , vd . Name ( ) , name )
2016-02-10 12:02:52 -05:00
if v , _ := vd . Get ( name ) ; v != nil {
return v , nil
}
2016-10-05 14:39:45 -04:00
v , err = vd . Create ( name , opts )
2016-03-16 17:52:34 -04:00
if err != nil {
return nil , err
}
2016-03-29 13:46:29 -04:00
s . globalLock . Lock ( )
2016-03-16 17:52:34 -04:00
s . labels [ name ] = labels
2016-09-17 15:32:31 -04:00
s . options [ name ] = opts
2016-03-29 13:46:29 -04:00
s . globalLock . Unlock ( )
2016-03-16 17:52:34 -04:00
if s . db != nil {
metadata := & volumeMetadata {
2016-09-17 15:32:31 -04:00
Name : name ,
Labels : labels ,
Options : opts ,
2016-03-16 17:52:34 -04:00
}
volData , err := json . Marshal ( metadata )
if err != nil {
return nil , err
}
if err := s . db . Update ( func ( tx * bolt . Tx ) error {
b := tx . Bucket ( [ ] byte ( volumeBucketName ) )
err := b . Put ( [ ] byte ( name ) , volData )
return err
} ) ; err != nil {
2016-09-23 10:38:19 -04:00
return nil , errors . Wrap ( err , "error while persisting volume metadata" )
2016-03-16 17:52:34 -04:00
}
}
2016-09-17 15:32:31 -04:00
return volumeWrapper { v , labels , vd . Scope ( ) , opts } , nil
2015-09-18 19:58:05 -04:00
}
2015-09-23 16:29:14 -04:00
// GetWithRef gets a volume with the given name from the passed in driver and stores the ref
// This is just like Get(), but we store the reference while holding the lock.
2016-02-11 18:21:52 -05:00
// This makes sure there are no races between checking for the existence of a volume and adding a reference for it
2015-09-23 16:29:14 -04:00
func ( s * VolumeStore ) GetWithRef ( name , driverName , ref string ) ( volume . Volume , error ) {
2015-09-09 22:23:06 -04:00
name = normaliseVolumeName ( name )
2015-10-19 16:43:56 -04:00
s . locks . Lock ( name )
defer s . locks . Unlock ( name )
2015-09-23 16:29:14 -04:00
vd , err := volumedrivers . GetDriver ( driverName )
if err != nil {
return nil , & OpErr { Err : err , Name : name , Op : "get" }
}
v , err := vd . Get ( name )
if err != nil {
return nil , & OpErr { Err : err , Name : name , Op : "get" }
2015-09-18 19:58:05 -04:00
}
2015-09-23 16:29:14 -04:00
2016-01-20 22:31:46 -05:00
s . setNamed ( v , ref )
2016-04-11 11:17:52 -04:00
2016-09-17 15:32:31 -04:00
return volumeWrapper { v , s . labels [ name ] , vd . Scope ( ) , s . options [ name ] } , nil
2015-09-18 19:58:05 -04:00
}
2015-09-23 16:29:14 -04:00
// Get looks if a volume with the given name exists and returns it if so
func ( s * VolumeStore ) Get ( name string ) ( volume . Volume , error ) {
name = normaliseVolumeName ( name )
2015-10-19 16:43:56 -04:00
s . locks . Lock ( name )
defer s . locks . Unlock ( name )
2015-09-23 16:29:14 -04:00
v , err := s . getVolume ( name )
if err != nil {
return nil , & OpErr { Err : err , Name : name , Op : "get" }
2015-09-18 19:58:05 -04:00
}
2016-01-20 22:31:46 -05:00
s . setNamed ( v , "" )
2015-09-23 16:29:14 -04:00
return v , nil
}
2015-09-18 19:58:05 -04:00
2016-03-09 11:17:57 -05:00
// getVolume requests the volume, if the driver info is stored it just accesses that driver,
2015-09-23 16:29:14 -04:00
// if the driver is unknown it probes all drivers until it finds the first volume with that name.
2016-02-11 18:21:52 -05:00
// it is expected that callers of this function hold any necessary locks
2015-09-23 16:29:14 -04:00
func ( s * VolumeStore ) getVolume ( name string ) ( volume . Volume , error ) {
2016-03-16 17:52:34 -04:00
labels := map [ string ] string { }
2016-09-17 15:32:31 -04:00
options := map [ string ] string { }
2016-03-16 17:52:34 -04:00
if s . db != nil {
// get meta
if err := s . db . Update ( func ( tx * bolt . Tx ) error {
b := tx . Bucket ( [ ] byte ( volumeBucketName ) )
data := b . Get ( [ ] byte ( name ) )
if string ( data ) == "" {
return nil
}
var meta volumeMetadata
buf := bytes . NewBuffer ( data )
if err := json . NewDecoder ( buf ) . Decode ( & meta ) ; err != nil {
return err
}
labels = meta . Labels
2016-09-17 15:32:31 -04:00
options = meta . Options
2016-03-16 17:52:34 -04:00
return nil
} ) ; err != nil {
return nil , err
}
}
2015-09-23 16:29:14 -04:00
logrus . Debugf ( "Getting volume reference for name: %s" , name )
2016-03-29 13:46:29 -04:00
s . globalLock . Lock ( )
v , exists := s . names [ name ]
s . globalLock . Unlock ( )
if exists {
2016-01-20 22:31:46 -05:00
vd , err := volumedrivers . GetDriver ( v . DriverName ( ) )
2015-09-23 16:29:14 -04:00
if err != nil {
return nil , err
}
2016-03-16 17:52:34 -04:00
vol , err := vd . Get ( name )
if err != nil {
return nil , err
}
2016-09-17 15:32:31 -04:00
return volumeWrapper { vol , labels , vd . Scope ( ) , options } , nil
2015-09-18 19:58:05 -04:00
}
2015-09-23 16:29:14 -04:00
logrus . Debugf ( "Probing all drivers for volume with name: %s" , name )
drivers , err := volumedrivers . GetAllDrivers ( )
2015-09-18 19:58:05 -04:00
if err != nil {
2015-09-23 16:29:14 -04:00
return nil , err
2015-09-18 19:58:05 -04:00
}
2015-10-19 16:43:56 -04:00
2015-09-23 16:29:14 -04:00
for _ , d := range drivers {
v , err := d . Get ( name )
if err != nil {
continue
}
2016-03-16 17:52:34 -04:00
2016-09-17 15:32:31 -04:00
return volumeWrapper { v , labels , d . Scope ( ) , options } , nil
2015-09-23 16:29:14 -04:00
}
return nil , errNoSuchVolume
2015-09-18 19:58:05 -04:00
}
2015-09-23 16:29:14 -04:00
// Remove removes the requested volume. A volume is not removed if it has any refs
func ( s * VolumeStore ) Remove ( v volume . Volume ) error {
2015-09-09 22:23:06 -04:00
name := normaliseVolumeName ( v . Name ( ) )
2015-10-19 16:43:56 -04:00
s . locks . Lock ( name )
defer s . locks . Unlock ( name )
2015-09-18 19:58:05 -04:00
2016-10-05 14:39:45 -04:00
refs := s . getRefs ( name )
if len ( refs ) > 0 {
2015-09-23 16:29:14 -04:00
return & OpErr { Err : errVolumeInUse , Name : v . Name ( ) , Op : "remove" , Refs : refs }
2015-09-18 19:58:05 -04:00
}
2016-09-07 09:59:15 -04:00
vd , err := volumedrivers . RemoveDriver ( v . DriverName ( ) )
2015-09-23 16:29:14 -04:00
if err != nil {
return & OpErr { Err : err , Name : vd . Name ( ) , Op : "remove" }
2015-09-18 19:58:05 -04:00
}
2015-09-23 16:29:14 -04:00
logrus . Debugf ( "Removing volume reference: driver %s, name %s" , v . DriverName ( ) , name )
2016-04-11 11:17:52 -04:00
vol := unwrapVolume ( v )
2016-03-16 17:52:34 -04:00
if err := vd . Remove ( vol ) ; err != nil {
2015-09-23 16:29:14 -04:00
return & OpErr { Err : err , Name : name , Op : "remove" }
2015-09-18 19:58:05 -04:00
}
2015-09-23 16:29:14 -04:00
2016-06-10 10:40:09 -04:00
s . Purge ( name )
2015-09-23 16:29:14 -04:00
return nil
2015-09-18 19:58:05 -04:00
}
2015-09-23 16:29:14 -04:00
// Dereference removes the specified reference to the volume
func ( s * VolumeStore ) Dereference ( v volume . Volume , ref string ) {
s . locks . Lock ( v . Name ( ) )
defer s . locks . Unlock ( v . Name ( ) )
2015-10-19 16:43:56 -04:00
2015-09-23 16:29:14 -04:00
s . globalLock . Lock ( )
2016-01-27 03:34:10 -05:00
defer s . globalLock . Unlock ( )
2016-02-16 21:10:45 -05:00
var refs [ ] string
2015-09-18 19:58:05 -04:00
2016-02-16 21:10:45 -05:00
for _ , r := range s . refs [ v . Name ( ) ] {
if r != ref {
refs = append ( refs , r )
2015-09-23 16:29:14 -04:00
}
2015-09-18 19:58:05 -04:00
}
2016-02-16 21:10:45 -05:00
s . refs [ v . Name ( ) ] = refs
2015-09-18 19:58:05 -04:00
}
2016-01-07 21:38:38 -05:00
// Refs gets the current list of refs for the given volume
func ( s * VolumeStore ) Refs ( v volume . Volume ) [ ] string {
s . locks . Lock ( v . Name ( ) )
defer s . locks . Unlock ( v . Name ( ) )
2016-10-05 14:39:45 -04:00
refs := s . getRefs ( v . Name ( ) )
2016-01-07 21:38:38 -05:00
refsOut := make ( [ ] string , len ( refs ) )
copy ( refsOut , refs )
return refsOut
}
2015-09-18 19:58:05 -04:00
// FilterByDriver returns the available volumes filtered by driver name
2015-09-23 16:29:14 -04:00
func ( s * VolumeStore ) FilterByDriver ( name string ) ( [ ] volume . Volume , error ) {
vd , err := volumedrivers . GetDriver ( name )
if err != nil {
return nil , & OpErr { Err : err , Name : name , Op : "list" }
}
ls , err := vd . List ( )
if err != nil {
return nil , & OpErr { Err : err , Name : name , Op : "list" }
}
2016-04-11 11:17:52 -04:00
for i , v := range ls {
2016-09-17 15:32:31 -04:00
options := map [ string ] string { }
for key , value := range s . options [ v . Name ( ) ] {
options [ key ] = value
}
ls [ i ] = volumeWrapper { v , s . labels [ v . Name ( ) ] , vd . Scope ( ) , options }
2016-04-11 11:17:52 -04:00
}
2015-09-23 16:29:14 -04:00
return ls , nil
}
2016-01-25 14:39:41 -05:00
// FilterByUsed returns the available volumes filtered by if they are in use or not.
// `used=true` returns only volumes that are being used, while `used=false` returns
// only volumes that are not being used.
func ( s * VolumeStore ) FilterByUsed ( vols [ ] volume . Volume , used bool ) [ ] volume . Volume {
2015-09-23 16:29:14 -04:00
return s . filter ( vols , func ( v volume . Volume ) bool {
s . locks . Lock ( v . Name ( ) )
2016-10-05 14:39:45 -04:00
l := len ( s . getRefs ( v . Name ( ) ) )
2016-01-25 14:39:41 -05:00
s . locks . Unlock ( v . Name ( ) )
if ( used && l > 0 ) || ( ! used && l == 0 ) {
return true
}
return false
2015-09-23 16:29:14 -04:00
} )
2015-09-18 19:58:05 -04:00
}
// filterFunc defines a function to allow filter volumes in the store
type filterFunc func ( vol volume . Volume ) bool
// filter returns the available volumes filtered by a filterFunc function
2015-09-23 16:29:14 -04:00
func ( s * VolumeStore ) filter ( vols [ ] volume . Volume , f filterFunc ) [ ] volume . Volume {
2015-09-18 19:58:05 -04:00
var ls [ ] volume . Volume
2015-09-23 16:29:14 -04:00
for _ , v := range vols {
if f ( v ) {
ls = append ( ls , v )
2015-09-18 19:58:05 -04:00
}
}
return ls
}
2016-03-16 17:52:34 -04:00
2016-04-11 11:17:52 -04:00
func unwrapVolume ( v volume . Volume ) volume . Volume {
if vol , ok := v . ( volumeWrapper ) ; ok {
2016-03-16 17:52:34 -04:00
return vol . Volume
}
return v
}