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