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:
parent
23e8dff9e7
commit
81fa9feb0c
43 changed files with 1538 additions and 1191 deletions
51
volume/drivers/adapter.go
Normal file
51
volume/drivers/adapter.go
Normal 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
20
volume/drivers/api.go
Normal 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)
|
||||
}
|
||||
61
volume/drivers/extpoint.go
Normal file
61
volume/drivers/extpoint.go
Normal 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
65
volume/drivers/proxy.go
Normal 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
126
volume/local/local.go
Normal 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
26
volume/volume.go
Normal 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
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue