1
0
Fork 0
mirror of https://github.com/moby/moby.git synced 2022-11-09 12:21:53 -05:00

Volumes refactor and external plugin implementation.

Signed by all authors:

Signed-off-by: Michael Crosby <crosbymichael@gmail.com>
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>
Signed-off-by: David Calavera <david.calavera@gmail.com>
Signed-off-by: Jeff Lindsay <progrium@gmail.com>
Signed-off-by: Alexander Morozov <lk4d4@docker.com>
Signed-off-by: Luke Marsden <luke@clusterhq.com>
Signed-off-by: David Calavera <david.calavera@gmail.com>
This commit is contained in:
David Calavera 2015-05-19 13:05:25 -07:00
parent 23e8dff9e7
commit 81fa9feb0c
43 changed files with 1538 additions and 1191 deletions

51
volume/drivers/adapter.go Normal file
View file

@ -0,0 +1,51 @@
package volumedrivers
import "github.com/docker/docker/volume"
type volumeDriverAdapter struct {
name string
proxy *volumeDriverProxy
}
func (a *volumeDriverAdapter) Name() string {
return a.name
}
func (a *volumeDriverAdapter) Create(name string) (volume.Volume, error) {
err := a.proxy.Create(name)
if err != nil {
return nil, err
}
return &volumeAdapter{a.proxy, name, a.name}, nil
}
func (a *volumeDriverAdapter) Remove(v volume.Volume) error {
return a.proxy.Remove(v.Name())
}
type volumeAdapter struct {
proxy *volumeDriverProxy
name string
driverName string
}
func (a *volumeAdapter) Name() string {
return a.name
}
func (a *volumeAdapter) DriverName() string {
return a.driverName
}
func (a *volumeAdapter) Path() string {
m, _ := a.proxy.Path(a.name)
return m
}
func (a *volumeAdapter) Mount() (string, error) {
return a.proxy.Mount(a.name)
}
func (a *volumeAdapter) Unmount() error {
return a.proxy.Unmount(a.name)
}

20
volume/drivers/api.go Normal file
View file

@ -0,0 +1,20 @@
package volumedrivers
import "github.com/docker/docker/volume"
type client interface {
Call(string, interface{}, interface{}) error
}
func NewVolumeDriver(name string, c client) volume.Driver {
proxy := &volumeDriverProxy{c}
return &volumeDriverAdapter{name, proxy}
}
type VolumeDriver interface {
Create(name string) (err error)
Remove(name string) (err error)
Path(name string) (mountpoint string, err error)
Mount(name string) (mountpoint string, err error)
Unmount(name string) (err error)
}

View file

@ -0,0 +1,61 @@
package volumedrivers
import (
"sync"
"github.com/Sirupsen/logrus"
"github.com/docker/docker/pkg/plugins"
"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)}
type driverExtpoint struct {
extensions map[string]volume.Driver
sync.Mutex
}
func Register(extension volume.Driver, name string) bool {
drivers.Lock()
defer drivers.Unlock()
if name == "" {
return false
}
_, exists := drivers.extensions[name]
if exists {
return false
}
drivers.extensions[name] = extension
return true
}
func Unregister(name string) bool {
drivers.Lock()
defer drivers.Unlock()
_, exists := drivers.extensions[name]
if !exists {
return false
}
delete(drivers.extensions, name)
return true
}
func Lookup(name string) volume.Driver {
drivers.Lock()
defer drivers.Unlock()
ext, ok := drivers.extensions[name]
if ok {
return ext
}
pl, err := plugins.Get(name, "VolumeDriver")
if err != nil {
logrus.Errorf("Error: %v", err)
return nil
}
d := NewVolumeDriver(name, pl.Client)
drivers.extensions[name] = d
return d
}

65
volume/drivers/proxy.go Normal file
View file

@ -0,0 +1,65 @@
package volumedrivers
// currently created by hand. generation tool would generate this like:
// $ rpc-gen volume/drivers/api.go VolumeDriver > volume/drivers/proxy.go
type volumeDriverRequest struct {
Name string
}
type volumeDriverResponse struct {
Mountpoint string `json:",ommitempty"`
Err error `json:",ommitempty"`
}
type volumeDriverProxy struct {
c client
}
func (pp *volumeDriverProxy) Create(name string) error {
args := volumeDriverRequest{name}
var ret volumeDriverResponse
err := pp.c.Call("VolumeDriver.Create", args, &ret)
if err != nil {
return err
}
return ret.Err
}
func (pp *volumeDriverProxy) Remove(name string) error {
args := volumeDriverRequest{name}
var ret volumeDriverResponse
err := pp.c.Call("VolumeDriver.Remove", args, &ret)
if err != nil {
return err
}
return ret.Err
}
func (pp *volumeDriverProxy) Path(name string) (string, error) {
args := volumeDriverRequest{name}
var ret volumeDriverResponse
if err := pp.c.Call("VolumeDriver.Path", args, &ret); err != nil {
return "", err
}
return ret.Mountpoint, ret.Err
}
func (pp *volumeDriverProxy) Mount(name string) (string, error) {
args := volumeDriverRequest{name}
var ret volumeDriverResponse
if err := pp.c.Call("VolumeDriver.Mount", args, &ret); err != nil {
return "", err
}
return ret.Mountpoint, ret.Err
}
func (pp *volumeDriverProxy) Unmount(name string) error {
args := volumeDriverRequest{name}
var ret volumeDriverResponse
err := pp.c.Call("VolumeDriver.Unmount", args, &ret)
if err != nil {
return err
}
return ret.Err
}

126
volume/local/local.go Normal file
View file

@ -0,0 +1,126 @@
package local
import (
"errors"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"sync"
"github.com/docker/docker/volume"
)
func New(rootDirectory string) (*Root, error) {
if err := os.MkdirAll(rootDirectory, 0700); err != nil {
return nil, err
}
r := &Root{
path: rootDirectory,
volumes: make(map[string]*Volume),
}
dirs, err := ioutil.ReadDir(rootDirectory)
if err != nil {
return nil, err
}
for _, d := range dirs {
name := filepath.Base(d.Name())
r.volumes[name] = &Volume{
driverName: r.Name(),
name: name,
path: filepath.Join(rootDirectory, name),
}
}
return r, nil
}
type Root struct {
m sync.Mutex
path string
volumes map[string]*Volume
}
func (r *Root) Name() string {
return "local"
}
func (r *Root) Create(name string) (volume.Volume, error) {
r.m.Lock()
defer r.m.Unlock()
v, exists := r.volumes[name]
if !exists {
path := filepath.Join(r.path, name)
if err := os.Mkdir(path, 0755); err != nil {
if os.IsExist(err) {
return nil, fmt.Errorf("volume already exists under %s", path)
}
return nil, err
}
v = &Volume{
driverName: r.Name(),
name: name,
path: path,
}
r.volumes[name] = v
}
v.use()
return v, nil
}
func (r *Root) Remove(v volume.Volume) error {
r.m.Lock()
defer r.m.Unlock()
lv, ok := v.(*Volume)
if !ok {
return errors.New("unknown volume type")
}
lv.release()
if lv.usedCount == 0 {
delete(r.volumes, lv.name)
return os.RemoveAll(lv.path)
}
return nil
}
type Volume struct {
m sync.Mutex
usedCount int
// unique name of the volume
name string
// path is the path on the host where the data lives
path string
// driverName is the name of the driver that created the volume.
driverName string
}
func (v *Volume) Name() string {
return v.name
}
func (v *Volume) DriverName() string {
return v.driverName
}
func (v *Volume) Path() string {
return v.path
}
func (v *Volume) Mount() (string, error) {
return v.path, nil
}
func (v *Volume) Unmount() error {
return nil
}
func (v *Volume) use() {
v.m.Lock()
v.usedCount++
v.m.Unlock()
}
func (v *Volume) release() {
v.m.Lock()
v.usedCount--
v.m.Unlock()
}

26
volume/volume.go Normal file
View file

@ -0,0 +1,26 @@
package volume
const DefaultDriverName = "local"
type Driver interface {
// Name returns the name of the volume driver.
Name() string
// Create makes a new volume with the given id.
Create(string) (Volume, error)
// Remove deletes the volume.
Remove(Volume) error
}
type Volume interface {
// Name returns the name of the volume
Name() string
// DriverName returns the name of the driver which owns this volume.
DriverName() string
// Path returns the absolute path to the volume.
Path() string
// Mount mounts the volume and returns the absolute path to
// where it can be consumed.
Mount() (string, error)
// Unmount unmounts the volume when it is no longer in use.
Unmount() error
}