1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00
moby--moby/volume/drivers/extpoint.go
Brian Goff 8b31f217ff Refcount graphdriver plugins properly
Adds 2 new methods to v2 plugin `Acquire` and `Release` which allow
refcounting directly at the plugin level instead of just the store.
Since a graphdriver is initialized exactly once, and is really managed
by a separate object, it didn't really seem right to call
`getter.Get()` to refcount graphdriver plugins.
On shutdown it was particularly weird where we'd either need to keep a
driver reference in daemon, or keep a reference to the pluggin getter in
the layer store, and even then still store extra details on if the
graphdriver is a plugin or not.

Instead the plugin proxy itself will handle calling the neccessary
refcounting methods directly on the plugin object.

Also adds a new interface in `plugingetter` to account for these new
functions which are not going to be implemented by v1 plugins.

Changes terms `plugingetter.CREATE` and `plugingetter.REMOVE` to
`ACQUIRE` and `RELEASE` respectively, which seems to be better
adjectives for what we're doing.

Signed-off-by: Brian Goff <cpuguy83@gmail.com>
(cherry picked from commit f29bbd16f5)
Signed-off-by: Victor Vieux <vieux@docker.com>
2016-12-13 19:56:51 -08:00

209 lines
5.5 KiB
Go

//go:generate pluginrpc-gen -i $GOFILE -o proxy.go -type volumeDriver -name VolumeDriver
package volumedrivers
import (
"fmt"
"sync"
"github.com/docker/docker/pkg/locker"
getter "github.com/docker/docker/pkg/plugingetter"
"github.com/docker/docker/volume"
)
// currently created by hand. generation tool would generate this like:
// $ extpoint-gen Driver > volume/extpoint.go
var drivers = &driverExtpoint{
extensions: make(map[string]volume.Driver),
driverLock: &locker.Locker{},
}
const extName = "VolumeDriver"
// NewVolumeDriver returns a driver has the given name mapped on the given client.
func NewVolumeDriver(name string, baseHostPath string, c client) volume.Driver {
proxy := &volumeDriverProxy{c}
return &volumeDriverAdapter{name: name, baseHostPath: baseHostPath, proxy: proxy}
}
// 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.
type volumeDriver interface {
// Create a volume with the given name
Create(name string, opts map[string]string) (err error)
// Remove the volume with the given name
Remove(name string) (err error)
// Get the mountpoint of the given volume
Path(name string) (mountpoint string, err error)
// Mount the given volume and return the mountpoint
Mount(name, id string) (mountpoint string, err error)
// Unmount the given volume
Unmount(name, id string) (err error)
// List lists all the volumes known to the driver
List() (volumes []*proxyVolume, err error)
// Get retrieves the volume with the requested name
Get(name string) (volume *proxyVolume, err error)
// Capabilities gets the list of capabilities of the driver
Capabilities() (capabilities volume.Capability, err error)
}
type driverExtpoint struct {
extensions map[string]volume.Driver
sync.Mutex
driverLock *locker.Locker
plugingetter getter.PluginGetter
}
// RegisterPluginGetter sets the plugingetter
func RegisterPluginGetter(plugingetter getter.PluginGetter) {
drivers.plugingetter = plugingetter
}
// Register associates the given driver to the given name, checking if
// the name is already associated
func Register(extension volume.Driver, name string) bool {
if name == "" {
return false
}
drivers.Lock()
defer drivers.Unlock()
_, exists := drivers.extensions[name]
if exists {
return false
}
if err := validateDriver(extension); err != nil {
return false
}
drivers.extensions[name] = extension
return true
}
// Unregister dissociates the name from its driver, if the association exists.
func Unregister(name string) bool {
drivers.Lock()
defer drivers.Unlock()
_, exists := drivers.extensions[name]
if !exists {
return false
}
delete(drivers.extensions, name)
return true
}
// lookup returns the driver associated with the given name. If a
// driver with the given name has not been registered it checks if
// there is a VolumeDriver plugin available with the given name.
func lookup(name string, mode int) (volume.Driver, error) {
drivers.driverLock.Lock(name)
defer drivers.driverLock.Unlock(name)
drivers.Lock()
ext, ok := drivers.extensions[name]
drivers.Unlock()
if ok {
return ext, nil
}
p, err := drivers.plugingetter.Get(name, extName, mode)
if err != nil {
return nil, fmt.Errorf("Error looking up volume plugin %s: %v", name, err)
}
d := NewVolumeDriver(p.Name(), p.BasePath(), p.Client())
if err := validateDriver(d); err != nil {
return nil, err
}
if p.IsV1() {
drivers.Lock()
drivers.extensions[name] = d
drivers.Unlock()
}
return d, nil
}
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
}
// GetDriver returns a volume driver by its name.
// If the driver is empty, it looks for the local driver.
func GetDriver(name string) (volume.Driver, error) {
if name == "" {
name = volume.DefaultDriverName
}
return lookup(name, getter.LOOKUP)
}
// CreateDriver returns a volume driver by its name and increments RefCount.
// If the driver is empty, it looks for the local driver.
func CreateDriver(name string) (volume.Driver, error) {
if name == "" {
name = volume.DefaultDriverName
}
return lookup(name, getter.ACQUIRE)
}
// RemoveDriver returns a volume driver by its name and decrements RefCount..
// If the driver is empty, it looks for the local driver.
func RemoveDriver(name string) (volume.Driver, error) {
if name == "" {
name = volume.DefaultDriverName
}
return lookup(name, getter.RELEASE)
}
// GetDriverList returns list of volume drivers registered.
// If no driver is registered, empty string list will be returned.
func GetDriverList() []string {
var driverList []string
drivers.Lock()
for driverName := range drivers.extensions {
driverList = append(driverList, driverName)
}
drivers.Unlock()
return driverList
}
// GetAllDrivers lists all the registered drivers
func GetAllDrivers() ([]volume.Driver, error) {
plugins, err := drivers.plugingetter.GetAllByCap(extName)
if err != nil {
return nil, fmt.Errorf("error listing plugins: %v", err)
}
var ds []volume.Driver
drivers.Lock()
defer drivers.Unlock()
for _, d := range drivers.extensions {
ds = append(ds, d)
}
for _, p := range plugins {
name := p.Name()
ext, ok := drivers.extensions[name]
if ok {
continue
}
ext = NewVolumeDriver(name, p.BasePath(), p.Client())
if p.IsV1() {
drivers.extensions[name] = ext
}
ds = append(ds, ext)
}
return ds, nil
}