2015-09-22 19:50:48 +00:00
|
|
|
//go:generate pluginrpc-gen -i $GOFILE -o proxy.go -type volumeDriver -name VolumeDriver
|
2015-06-12 13:25:32 +00:00
|
|
|
|
2018-03-19 21:16:26 +00:00
|
|
|
package drivers // import "github.com/docker/docker/volume/drivers"
|
2015-05-19 20:05:25 +00:00
|
|
|
|
|
|
|
import (
|
2023-06-23 00:33:17 +00:00
|
|
|
"context"
|
2015-05-22 17:37:00 +00:00
|
|
|
"fmt"
|
2017-01-22 06:59:29 +00:00
|
|
|
"sort"
|
2015-05-19 20:05:25 +00:00
|
|
|
"sync"
|
|
|
|
|
2023-09-13 15:41:45 +00:00
|
|
|
"github.com/containerd/log"
|
2018-03-19 21:18:52 +00:00
|
|
|
"github.com/docker/docker/errdefs"
|
2016-10-07 20:53:14 +00:00
|
|
|
getter "github.com/docker/docker/pkg/plugingetter"
|
2018-04-25 01:45:00 +00:00
|
|
|
"github.com/docker/docker/pkg/plugins"
|
2015-05-19 20:05:25 +00:00
|
|
|
"github.com/docker/docker/volume"
|
2020-09-10 20:15:40 +00:00
|
|
|
"github.com/moby/locker"
|
2017-07-19 14:20:13 +00:00
|
|
|
"github.com/pkg/errors"
|
2015-05-19 20:05:25 +00:00
|
|
|
)
|
|
|
|
|
2015-09-23 20:29:14 +00:00
|
|
|
const extName = "VolumeDriver"
|
|
|
|
|
2015-09-11 22:19:38 +00:00
|
|
|
// volumeDriver defines the available functions that volume plugins must implement.
|
|
|
|
// This interface is only defined to generate the proxy objects.
|
|
|
|
// It's not intended to be public or reused.
|
2022-07-13 20:30:47 +00:00
|
|
|
//
|
2022-09-03 21:20:23 +00:00
|
|
|
//nolint:unused
|
2015-09-11 22:19:38 +00:00
|
|
|
type volumeDriver interface {
|
2015-06-12 13:25:32 +00:00
|
|
|
// Create a volume with the given name
|
2016-04-09 21:42:24 +00:00
|
|
|
Create(name string, opts map[string]string) (err error)
|
2015-06-12 13:25:32 +00:00
|
|
|
// Remove the volume with the given name
|
|
|
|
Remove(name string) (err error)
|
2022-07-08 16:27:07 +00:00
|
|
|
// Path returns the mountpoint of the given volume.
|
2015-06-12 13:25:32 +00:00
|
|
|
Path(name string) (mountpoint string, err error)
|
|
|
|
// Mount the given volume and return the mountpoint
|
2016-03-08 02:41:44 +00:00
|
|
|
Mount(name, id string) (mountpoint string, err error)
|
2015-06-12 13:25:32 +00:00
|
|
|
// Unmount the given volume
|
2016-03-08 02:41:44 +00:00
|
|
|
Unmount(name, id string) (err error)
|
2015-09-23 20:29:14 +00:00
|
|
|
// List lists all the volumes known to the driver
|
2016-04-09 21:42:24 +00:00
|
|
|
List() (volumes []*proxyVolume, err error)
|
2016-02-11 23:21:52 +00:00
|
|
|
// Get retrieves the volume with the requested name
|
2015-09-23 20:29:14 +00:00
|
|
|
Get(name string) (volume *proxyVolume, err error)
|
2016-04-11 15:17:52 +00:00
|
|
|
// Capabilities gets the list of capabilities of the driver
|
|
|
|
Capabilities() (capabilities volume.Capability, err error)
|
2015-06-12 13:25:32 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 21:18:52 +00:00
|
|
|
// Store is an in-memory store for volume drivers
|
|
|
|
type Store struct {
|
|
|
|
extensions map[string]volume.Driver
|
|
|
|
mu sync.Mutex
|
2016-09-08 00:01:10 +00:00
|
|
|
driverLock *locker.Locker
|
2018-03-19 21:18:52 +00:00
|
|
|
pluginGetter getter.PluginGetter
|
2016-09-08 00:01:10 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 21:18:52 +00:00
|
|
|
// NewStore creates a new volume driver store
|
|
|
|
func NewStore(pg getter.PluginGetter) *Store {
|
|
|
|
return &Store{
|
|
|
|
extensions: make(map[string]volume.Driver),
|
|
|
|
driverLock: locker.New(),
|
|
|
|
pluginGetter: pg,
|
2015-05-19 20:05:25 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-19 14:20:13 +00:00
|
|
|
type driverNotFoundError string
|
|
|
|
|
|
|
|
func (e driverNotFoundError) Error() string {
|
|
|
|
return "volume driver not found: " + string(e)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (driverNotFoundError) NotFound() {}
|
|
|
|
|
2016-05-16 15:50:55 +00:00
|
|
|
// lookup returns the driver associated with the given name. If a
|
2015-07-21 17:50:10 +00:00
|
|
|
// driver with the given name has not been registered it checks if
|
|
|
|
// there is a VolumeDriver plugin available with the given name.
|
2018-03-19 21:18:52 +00:00
|
|
|
func (s *Store) lookup(name string, mode int) (volume.Driver, error) {
|
|
|
|
if name == "" {
|
|
|
|
return nil, errdefs.InvalidParameter(errors.New("driver name cannot be empty"))
|
|
|
|
}
|
|
|
|
s.driverLock.Lock(name)
|
|
|
|
defer s.driverLock.Unlock(name)
|
2016-01-20 17:12:51 +00:00
|
|
|
|
2018-03-19 21:18:52 +00:00
|
|
|
s.mu.Lock()
|
|
|
|
ext, ok := s.extensions[name]
|
|
|
|
s.mu.Unlock()
|
2015-05-19 20:05:25 +00:00
|
|
|
if ok {
|
2015-05-20 21:53:53 +00:00
|
|
|
return ext, nil
|
2015-05-19 20:05:25 +00:00
|
|
|
}
|
2018-03-19 21:18:52 +00:00
|
|
|
if s.pluginGetter != nil {
|
|
|
|
p, err := s.pluginGetter.Get(name, extName, mode)
|
2016-12-12 23:05:53 +00:00
|
|
|
if err != nil {
|
2017-07-19 14:20:13 +00:00
|
|
|
return nil, errors.Wrap(err, "error looking up volume plugin "+name)
|
2016-12-12 23:05:53 +00:00
|
|
|
}
|
2016-01-20 17:12:51 +00:00
|
|
|
|
2018-04-25 01:45:00 +00:00
|
|
|
d, err := makePluginAdapter(p)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "error making plugin client")
|
|
|
|
}
|
2016-12-12 23:05:53 +00:00
|
|
|
if err := validateDriver(d); err != nil {
|
2017-10-20 19:39:47 +00:00
|
|
|
if mode > 0 {
|
|
|
|
// Undo any reference count changes from the initial `Get`
|
2018-03-19 21:18:52 +00:00
|
|
|
if _, err := s.pluginGetter.Get(name, extName, mode*-1); err != nil {
|
2023-06-23 00:33:17 +00:00
|
|
|
log.G(context.TODO()).WithError(err).WithField("action", "validate-driver").WithField("plugin", name).Error("error releasing reference to plugin")
|
2017-10-20 19:39:47 +00:00
|
|
|
}
|
|
|
|
}
|
2016-12-12 23:05:53 +00:00
|
|
|
return nil, err
|
|
|
|
}
|
2016-04-11 15:17:52 +00:00
|
|
|
|
2016-12-12 23:05:53 +00:00
|
|
|
if p.IsV1() {
|
2018-03-19 21:18:52 +00:00
|
|
|
s.mu.Lock()
|
|
|
|
s.extensions[name] = d
|
|
|
|
s.mu.Unlock()
|
2016-12-12 23:05:53 +00:00
|
|
|
}
|
|
|
|
return d, nil
|
2016-07-18 22:39:27 +00:00
|
|
|
}
|
2017-07-19 14:20:13 +00:00
|
|
|
return nil, driverNotFoundError(name)
|
2015-05-19 20:05:25 +00:00
|
|
|
}
|
2015-09-18 23:58:05 +00:00
|
|
|
|
2016-04-11 15:17:52 +00:00
|
|
|
func validateDriver(vd volume.Driver) error {
|
|
|
|
scope := vd.Scope()
|
|
|
|
if scope != volume.LocalScope && scope != volume.GlobalScope {
|
|
|
|
return fmt.Errorf("Driver %q provided an invalid capability scope: %s", vd.Name(), scope)
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2018-03-19 21:18:52 +00:00
|
|
|
// Register associates the given driver to the given name, checking if
|
|
|
|
// the name is already associated
|
|
|
|
func (s *Store) Register(d volume.Driver, name string) bool {
|
2015-09-18 23:58:05 +00:00
|
|
|
if name == "" {
|
2018-03-19 21:18:52 +00:00
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
|
|
|
|
|
|
|
if _, exists := s.extensions[name]; exists {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := validateDriver(d); err != nil {
|
|
|
|
return false
|
2015-09-18 23:58:05 +00:00
|
|
|
}
|
2018-03-19 21:18:52 +00:00
|
|
|
|
|
|
|
s.extensions[name] = d
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetDriver returns a volume driver by its name.
|
|
|
|
// If the driver is empty, it looks for the local driver.
|
|
|
|
func (s *Store) GetDriver(name string) (volume.Driver, error) {
|
|
|
|
return s.lookup(name, getter.Lookup)
|
2016-09-07 13:59:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// CreateDriver returns a volume driver by its name and increments RefCount.
|
|
|
|
// If the driver is empty, it looks for the local driver.
|
2018-03-19 21:18:52 +00:00
|
|
|
func (s *Store) CreateDriver(name string) (volume.Driver, error) {
|
|
|
|
return s.lookup(name, getter.Acquire)
|
2016-09-07 13:59:15 +00:00
|
|
|
}
|
|
|
|
|
2017-10-20 19:39:47 +00:00
|
|
|
// ReleaseDriver returns a volume driver by its name and decrements RefCount..
|
2016-09-07 13:59:15 +00:00
|
|
|
// If the driver is empty, it looks for the local driver.
|
2018-03-19 21:18:52 +00:00
|
|
|
func (s *Store) ReleaseDriver(name string) (volume.Driver, error) {
|
|
|
|
return s.lookup(name, getter.Release)
|
2015-09-18 23:58:05 +00:00
|
|
|
}
|
2015-10-23 06:08:26 +00:00
|
|
|
|
|
|
|
// GetDriverList returns list of volume drivers registered.
|
|
|
|
// If no driver is registered, empty string list will be returned.
|
2018-03-19 21:18:52 +00:00
|
|
|
func (s *Store) GetDriverList() []string {
|
2015-10-23 06:08:26 +00:00
|
|
|
var driverList []string
|
2018-03-19 21:18:52 +00:00
|
|
|
s.mu.Lock()
|
2018-03-22 21:11:03 +00:00
|
|
|
defer s.mu.Unlock()
|
2018-03-19 21:18:52 +00:00
|
|
|
for driverName := range s.extensions {
|
2015-10-23 06:08:26 +00:00
|
|
|
driverList = append(driverList, driverName)
|
|
|
|
}
|
2017-01-22 06:59:29 +00:00
|
|
|
sort.Strings(driverList)
|
2015-10-23 06:08:26 +00:00
|
|
|
return driverList
|
|
|
|
}
|
2015-09-23 20:29:14 +00:00
|
|
|
|
|
|
|
// GetAllDrivers lists all the registered drivers
|
2018-03-19 21:18:52 +00:00
|
|
|
func (s *Store) GetAllDrivers() ([]volume.Driver, error) {
|
2016-12-12 23:05:53 +00:00
|
|
|
var plugins []getter.CompatPlugin
|
2018-03-19 21:18:52 +00:00
|
|
|
if s.pluginGetter != nil {
|
2016-12-12 23:05:53 +00:00
|
|
|
var err error
|
2018-03-19 21:18:52 +00:00
|
|
|
plugins, err = s.pluginGetter.GetAllByCap(extName)
|
2016-12-12 23:05:53 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("error listing plugins: %v", err)
|
|
|
|
}
|
2015-09-23 20:29:14 +00:00
|
|
|
}
|
|
|
|
var ds []volume.Driver
|
|
|
|
|
2018-03-19 21:18:52 +00:00
|
|
|
s.mu.Lock()
|
|
|
|
defer s.mu.Unlock()
|
2015-09-23 20:29:14 +00:00
|
|
|
|
2018-03-19 21:18:52 +00:00
|
|
|
for _, d := range s.extensions {
|
2015-09-23 20:29:14 +00:00
|
|
|
ds = append(ds, d)
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, p := range plugins {
|
2016-05-16 15:50:55 +00:00
|
|
|
name := p.Name()
|
2016-11-29 08:17:35 +00:00
|
|
|
|
2018-03-19 21:18:52 +00:00
|
|
|
if _, ok := s.extensions[name]; ok {
|
2015-09-23 20:29:14 +00:00
|
|
|
continue
|
|
|
|
}
|
2016-01-20 17:12:51 +00:00
|
|
|
|
2018-04-25 01:45:00 +00:00
|
|
|
ext, err := makePluginAdapter(p)
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "error making plugin client")
|
|
|
|
}
|
2016-09-08 00:01:10 +00:00
|
|
|
if p.IsV1() {
|
2018-03-19 21:18:52 +00:00
|
|
|
s.extensions[name] = ext
|
2016-07-18 22:39:27 +00:00
|
|
|
}
|
2015-09-23 20:29:14 +00:00
|
|
|
ds = append(ds, ext)
|
|
|
|
}
|
|
|
|
return ds, nil
|
|
|
|
}
|
2018-04-25 01:45:00 +00:00
|
|
|
|
|
|
|
func makePluginAdapter(p getter.CompatPlugin) (*volumeDriverAdapter, error) {
|
2018-05-30 19:00:42 +00:00
|
|
|
if pc, ok := p.(getter.PluginWithV1Client); ok {
|
|
|
|
return &volumeDriverAdapter{name: p.Name(), scopePath: p.ScopedPath, proxy: &volumeDriverProxy{pc.Client()}}, nil
|
|
|
|
}
|
|
|
|
|
2018-04-25 01:45:00 +00:00
|
|
|
pa, ok := p.(getter.PluginAddr)
|
|
|
|
if !ok {
|
2018-05-30 19:00:42 +00:00
|
|
|
return nil, errdefs.System(errors.Errorf("got unknown plugin instance %T", p))
|
2018-04-25 01:45:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if pa.Protocol() != plugins.ProtocolSchemeHTTPV1 {
|
|
|
|
return nil, errors.Errorf("plugin protocol not supported: %s", p)
|
|
|
|
}
|
|
|
|
|
|
|
|
addr := pa.Addr()
|
|
|
|
client, err := plugins.NewClientWithTimeout(addr.Network()+"://"+addr.String(), nil, pa.Timeout())
|
|
|
|
if err != nil {
|
|
|
|
return nil, errors.Wrap(err, "error creating plugin client")
|
|
|
|
}
|
|
|
|
|
|
|
|
return &volumeDriverAdapter{name: p.Name(), scopePath: p.ScopedPath, proxy: &volumeDriverProxy{client}}, nil
|
|
|
|
}
|