github.com/portworx/docker@v1.12.1/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  	"sync"
     8  
     9  	"github.com/docker/docker/pkg/locker"
    10  	"github.com/docker/docker/plugin"
    11  	"github.com/docker/docker/volume"
    12  )
    13  
    14  // currently created by hand. generation tool would generate this like:
    15  // $ extpoint-gen Driver > volume/extpoint.go
    16  
    17  var drivers = &driverExtpoint{extensions: make(map[string]volume.Driver), driverLock: &locker.Locker{}}
    18  
    19  const extName = "VolumeDriver"
    20  
    21  // NewVolumeDriver returns a driver has the given name mapped on the given client.
    22  func NewVolumeDriver(name string, c client) volume.Driver {
    23  	proxy := &volumeDriverProxy{c}
    24  	return &volumeDriverAdapter{name: name, proxy: proxy}
    25  }
    26  
    27  // volumeDriver defines the available functions that volume plugins must implement.
    28  // This interface is only defined to generate the proxy objects.
    29  // It's not intended to be public or reused.
    30  type volumeDriver interface {
    31  	// Create a volume with the given name
    32  	Create(name string, opts map[string]string) (err error)
    33  	// Remove the volume with the given name
    34  	Remove(name string) (err error)
    35  	// Get the mountpoint of the given volume
    36  	Path(name string) (mountpoint string, err error)
    37  	// Mount the given volume and return the mountpoint
    38  	Mount(name, id string) (mountpoint string, err error)
    39  	// Unmount the given volume
    40  	Unmount(name, id string) (err error)
    41  	// List lists all the volumes known to the driver
    42  	List() (volumes []*proxyVolume, err error)
    43  	// Get retrieves the volume with the requested name
    44  	Get(name string) (volume *proxyVolume, err error)
    45  	// Capabilities gets the list of capabilities of the driver
    46  	Capabilities() (capabilities volume.Capability, err error)
    47  }
    48  
    49  type driverExtpoint struct {
    50  	extensions map[string]volume.Driver
    51  	sync.Mutex
    52  	driverLock *locker.Locker
    53  }
    54  
    55  // Register associates the given driver to the given name, checking if
    56  // the name is already associated
    57  func Register(extension volume.Driver, name string) bool {
    58  	if name == "" {
    59  		return false
    60  	}
    61  
    62  	drivers.Lock()
    63  	defer drivers.Unlock()
    64  
    65  	_, exists := drivers.extensions[name]
    66  	if exists {
    67  		return false
    68  	}
    69  
    70  	if err := validateDriver(extension); err != nil {
    71  		return false
    72  	}
    73  
    74  	drivers.extensions[name] = extension
    75  	return true
    76  }
    77  
    78  // Unregister dissociates the name from its driver, if the association exists.
    79  func Unregister(name string) bool {
    80  	drivers.Lock()
    81  	defer drivers.Unlock()
    82  
    83  	_, exists := drivers.extensions[name]
    84  	if !exists {
    85  		return false
    86  	}
    87  	delete(drivers.extensions, name)
    88  	return true
    89  }
    90  
    91  // lookup returns the driver associated with the given name. If a
    92  // driver with the given name has not been registered it checks if
    93  // there is a VolumeDriver plugin available with the given name.
    94  func lookup(name string) (volume.Driver, error) {
    95  	drivers.driverLock.Lock(name)
    96  	defer drivers.driverLock.Unlock(name)
    97  
    98  	drivers.Lock()
    99  	ext, ok := drivers.extensions[name]
   100  	drivers.Unlock()
   101  	if ok {
   102  		return ext, nil
   103  	}
   104  
   105  	p, err := plugin.LookupWithCapability(name, extName)
   106  	if err != nil {
   107  		return nil, fmt.Errorf("Error looking up volume plugin %s: %v", name, err)
   108  	}
   109  
   110  	d := NewVolumeDriver(name, p.Client())
   111  	if err := validateDriver(d); err != nil {
   112  		return nil, err
   113  	}
   114  
   115  	if p.IsLegacy() {
   116  		drivers.Lock()
   117  		drivers.extensions[name] = d
   118  		drivers.Unlock()
   119  	}
   120  	return d, nil
   121  }
   122  
   123  func validateDriver(vd volume.Driver) error {
   124  	scope := vd.Scope()
   125  	if scope != volume.LocalScope && scope != volume.GlobalScope {
   126  		return fmt.Errorf("Driver %q provided an invalid capability scope: %s", vd.Name(), scope)
   127  	}
   128  	return nil
   129  }
   130  
   131  // GetDriver returns a volume driver by its name.
   132  // If the driver is empty, it looks for the local driver.
   133  func GetDriver(name string) (volume.Driver, error) {
   134  	if name == "" {
   135  		name = volume.DefaultDriverName
   136  	}
   137  	return lookup(name)
   138  }
   139  
   140  // GetDriverList returns list of volume drivers registered.
   141  // If no driver is registered, empty string list will be returned.
   142  func GetDriverList() []string {
   143  	var driverList []string
   144  	drivers.Lock()
   145  	for driverName := range drivers.extensions {
   146  		driverList = append(driverList, driverName)
   147  	}
   148  	drivers.Unlock()
   149  	return driverList
   150  }
   151  
   152  // GetAllDrivers lists all the registered drivers
   153  func GetAllDrivers() ([]volume.Driver, error) {
   154  	plugins, err := plugin.FindWithCapability(extName)
   155  	if err != nil {
   156  		return nil, fmt.Errorf("error listing plugins: %v", err)
   157  	}
   158  	var ds []volume.Driver
   159  
   160  	drivers.Lock()
   161  	defer drivers.Unlock()
   162  
   163  	for _, d := range drivers.extensions {
   164  		ds = append(ds, d)
   165  	}
   166  
   167  	for _, p := range plugins {
   168  		name := p.Name()
   169  		ext, ok := drivers.extensions[name]
   170  		if ok {
   171  			continue
   172  		}
   173  
   174  		ext = NewVolumeDriver(name, p.Client())
   175  		if p.IsLegacy() {
   176  			drivers.extensions[name] = ext
   177  		}
   178  		ds = append(ds, ext)
   179  	}
   180  	return ds, nil
   181  }