github.com/docker/Engine@v17.12.1-ce-rc2+incompatible/volume/drivers/extpoint.go (about)

     1  //go:generate pluginrpc-gen -i $GOFILE -o proxy.go -type volumeDriver -name VolumeDriver
     2  
     3  package volumedrivers
     4  
     5  import (
     6  	"fmt"
     7  	"sort"
     8  	"sync"
     9  
    10  	"github.com/docker/docker/pkg/locker"
    11  	getter "github.com/docker/docker/pkg/plugingetter"
    12  	"github.com/docker/docker/volume"
    13  	"github.com/pkg/errors"
    14  	"github.com/sirupsen/logrus"
    15  )
    16  
    17  // currently created by hand. generation tool would generate this like:
    18  // $ extpoint-gen Driver > volume/extpoint.go
    19  
    20  var drivers = &driverExtpoint{
    21  	extensions: make(map[string]volume.Driver),
    22  	driverLock: &locker.Locker{},
    23  }
    24  
    25  const extName = "VolumeDriver"
    26  
    27  // NewVolumeDriver returns a driver has the given name mapped on the given client.
    28  func NewVolumeDriver(name string, baseHostPath string, c client) volume.Driver {
    29  	proxy := &volumeDriverProxy{c}
    30  	return &volumeDriverAdapter{name: name, baseHostPath: baseHostPath, proxy: proxy}
    31  }
    32  
    33  // volumeDriver defines the available functions that volume plugins must implement.
    34  // This interface is only defined to generate the proxy objects.
    35  // It's not intended to be public or reused.
    36  // nolint: deadcode
    37  type volumeDriver interface {
    38  	// Create a volume with the given name
    39  	Create(name string, opts map[string]string) (err error)
    40  	// Remove the volume with the given name
    41  	Remove(name string) (err error)
    42  	// Get the mountpoint of the given volume
    43  	Path(name string) (mountpoint string, err error)
    44  	// Mount the given volume and return the mountpoint
    45  	Mount(name, id string) (mountpoint string, err error)
    46  	// Unmount the given volume
    47  	Unmount(name, id string) (err error)
    48  	// List lists all the volumes known to the driver
    49  	List() (volumes []*proxyVolume, err error)
    50  	// Get retrieves the volume with the requested name
    51  	Get(name string) (volume *proxyVolume, err error)
    52  	// Capabilities gets the list of capabilities of the driver
    53  	Capabilities() (capabilities volume.Capability, err error)
    54  }
    55  
    56  type driverExtpoint struct {
    57  	extensions map[string]volume.Driver
    58  	sync.Mutex
    59  	driverLock   *locker.Locker
    60  	plugingetter getter.PluginGetter
    61  }
    62  
    63  // RegisterPluginGetter sets the plugingetter
    64  func RegisterPluginGetter(plugingetter getter.PluginGetter) {
    65  	drivers.plugingetter = plugingetter
    66  }
    67  
    68  // Register associates the given driver to the given name, checking if
    69  // the name is already associated
    70  func Register(extension volume.Driver, name string) bool {
    71  	if name == "" {
    72  		return false
    73  	}
    74  
    75  	drivers.Lock()
    76  	defer drivers.Unlock()
    77  
    78  	_, exists := drivers.extensions[name]
    79  	if exists {
    80  		return false
    81  	}
    82  
    83  	if err := validateDriver(extension); err != nil {
    84  		return false
    85  	}
    86  
    87  	drivers.extensions[name] = extension
    88  
    89  	return true
    90  }
    91  
    92  // Unregister dissociates the name from its driver, if the association exists.
    93  func Unregister(name string) bool {
    94  	drivers.Lock()
    95  	defer drivers.Unlock()
    96  
    97  	_, exists := drivers.extensions[name]
    98  	if !exists {
    99  		return false
   100  	}
   101  	delete(drivers.extensions, name)
   102  	return true
   103  }
   104  
   105  type driverNotFoundError string
   106  
   107  func (e driverNotFoundError) Error() string {
   108  	return "volume driver not found: " + string(e)
   109  }
   110  
   111  func (driverNotFoundError) NotFound() {}
   112  
   113  // lookup returns the driver associated with the given name. If a
   114  // driver with the given name has not been registered it checks if
   115  // there is a VolumeDriver plugin available with the given name.
   116  func lookup(name string, mode int) (volume.Driver, error) {
   117  	drivers.driverLock.Lock(name)
   118  	defer drivers.driverLock.Unlock(name)
   119  
   120  	drivers.Lock()
   121  	ext, ok := drivers.extensions[name]
   122  	drivers.Unlock()
   123  	if ok {
   124  		return ext, nil
   125  	}
   126  	if drivers.plugingetter != nil {
   127  		p, err := drivers.plugingetter.Get(name, extName, mode)
   128  		if err != nil {
   129  			return nil, errors.Wrap(err, "error looking up volume plugin "+name)
   130  		}
   131  
   132  		d := NewVolumeDriver(p.Name(), p.BasePath(), p.Client())
   133  		if err := validateDriver(d); err != nil {
   134  			if mode > 0 {
   135  				// Undo any reference count changes from the initial `Get`
   136  				if _, err := drivers.plugingetter.Get(name, extName, mode*-1); err != nil {
   137  					logrus.WithError(err).WithField("action", "validate-driver").WithField("plugin", name).Error("error releasing reference to plugin")
   138  				}
   139  			}
   140  			return nil, err
   141  		}
   142  
   143  		if p.IsV1() {
   144  			drivers.Lock()
   145  			drivers.extensions[name] = d
   146  			drivers.Unlock()
   147  		}
   148  		return d, nil
   149  	}
   150  	return nil, driverNotFoundError(name)
   151  }
   152  
   153  func validateDriver(vd volume.Driver) error {
   154  	scope := vd.Scope()
   155  	if scope != volume.LocalScope && scope != volume.GlobalScope {
   156  		return fmt.Errorf("Driver %q provided an invalid capability scope: %s", vd.Name(), scope)
   157  	}
   158  	return nil
   159  }
   160  
   161  // GetDriver returns a volume driver by its name.
   162  // If the driver is empty, it looks for the local driver.
   163  func GetDriver(name string) (volume.Driver, error) {
   164  	if name == "" {
   165  		name = volume.DefaultDriverName
   166  	}
   167  	return lookup(name, getter.Lookup)
   168  }
   169  
   170  // CreateDriver returns a volume driver by its name and increments RefCount.
   171  // If the driver is empty, it looks for the local driver.
   172  func CreateDriver(name string) (volume.Driver, error) {
   173  	if name == "" {
   174  		name = volume.DefaultDriverName
   175  	}
   176  	return lookup(name, getter.Acquire)
   177  }
   178  
   179  // ReleaseDriver returns a volume driver by its name and decrements RefCount..
   180  // If the driver is empty, it looks for the local driver.
   181  func ReleaseDriver(name string) (volume.Driver, error) {
   182  	if name == "" {
   183  		name = volume.DefaultDriverName
   184  	}
   185  	return lookup(name, getter.Release)
   186  }
   187  
   188  // GetDriverList returns list of volume drivers registered.
   189  // If no driver is registered, empty string list will be returned.
   190  func GetDriverList() []string {
   191  	var driverList []string
   192  	drivers.Lock()
   193  	for driverName := range drivers.extensions {
   194  		driverList = append(driverList, driverName)
   195  	}
   196  	drivers.Unlock()
   197  	sort.Strings(driverList)
   198  	return driverList
   199  }
   200  
   201  // GetAllDrivers lists all the registered drivers
   202  func GetAllDrivers() ([]volume.Driver, error) {
   203  	var plugins []getter.CompatPlugin
   204  	if drivers.plugingetter != nil {
   205  		var err error
   206  		plugins, err = drivers.plugingetter.GetAllByCap(extName)
   207  		if err != nil {
   208  			return nil, fmt.Errorf("error listing plugins: %v", err)
   209  		}
   210  	}
   211  	var ds []volume.Driver
   212  
   213  	drivers.Lock()
   214  	defer drivers.Unlock()
   215  
   216  	for _, d := range drivers.extensions {
   217  		ds = append(ds, d)
   218  	}
   219  
   220  	for _, p := range plugins {
   221  		name := p.Name()
   222  
   223  		if _, ok := drivers.extensions[name]; ok {
   224  			continue
   225  		}
   226  
   227  		ext := NewVolumeDriver(name, p.BasePath(), p.Client())
   228  		if p.IsV1() {
   229  			drivers.extensions[name] = ext
   230  		}
   231  		ds = append(ds, ext)
   232  	}
   233  	return ds, nil
   234  }