github.com/Heebron/moby@v0.0.0-20221111184709-6eab4f55faf7/volume/drivers/extpoint.go (about)

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