diff --git a/hack/make/validate-lint b/hack/make/validate-lint index d358cb8255..1f43c532fc 100644 --- a/hack/make/validate-lint +++ b/hack/make/validate-lint @@ -63,6 +63,9 @@ packages=( registry runconfig utils + volume + volume/local + volume/drivers ) errors=() diff --git a/volume/drivers/api.go b/volume/drivers/api.go index 3c685ae18d..ced82e08e0 100644 --- a/volume/drivers/api.go +++ b/volume/drivers/api.go @@ -4,11 +4,13 @@ package volumedrivers import "github.com/docker/docker/volume" +// NewVolumeDriver returns a driver has the given name mapped on the given client. func NewVolumeDriver(name string, c client) volume.Driver { proxy := &volumeDriverProxy{c} return &volumeDriverAdapter{name, proxy} } +// VolumeDriver defines the available functions that volume plugins must implement. type VolumeDriver interface { // Create a volume with the given name Create(name string) (err error) diff --git a/volume/drivers/extpoint.go b/volume/drivers/extpoint.go index b002a0ffda..09bb7d433e 100644 --- a/volume/drivers/extpoint.go +++ b/volume/drivers/extpoint.go @@ -18,6 +18,8 @@ type driverExtpoint struct { sync.Mutex } +// Register associates the given driver to the given name, checking if +// the name is already associated func Register(extension volume.Driver, name string) bool { drivers.Lock() defer drivers.Unlock() @@ -32,6 +34,7 @@ func Register(extension volume.Driver, name string) bool { return true } +// Unregister dissociates the name from it's driver, if the association exists. func Unregister(name string) bool { drivers.Lock() defer drivers.Unlock() @@ -43,6 +46,9 @@ func Unregister(name string) bool { 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) (volume.Driver, error) { drivers.Lock() defer drivers.Unlock() diff --git a/volume/local/local.go b/volume/local/local.go index 688ea6c7ec..0507f07e4e 100644 --- a/volume/local/local.go +++ b/volume/local/local.go @@ -1,3 +1,6 @@ +// Package local provides the default implementation for volumes. It +// is used to mount data volume containers and directories local to +// the host server. package local import ( @@ -13,7 +16,7 @@ import ( ) // VolumeDataPathName is the name of the directory where the volume data is stored. -// It uses a very distintive name to avoid colissions migrating data between +// It uses a very distintive name to avoid collisions migrating data between // Docker versions. const ( VolumeDataPathName = "_data" @@ -22,6 +25,9 @@ const ( var oldVfsDir = filepath.Join("vfs", "dir") +// New instantiates a new Root instance with the provided scope. Scope +// is the base path that the Root instance uses to store its +// volumes. The base path is created here if it does not exist. func New(scope string) (*Root, error) { rootDirectory := filepath.Join(scope, volumesPathName) @@ -32,7 +38,7 @@ func New(scope string) (*Root, error) { r := &Root{ scope: scope, path: rootDirectory, - volumes: make(map[string]*Volume), + volumes: make(map[string]*localVolume), } dirs, err := ioutil.ReadDir(rootDirectory) @@ -42,7 +48,7 @@ func New(scope string) (*Root, error) { for _, d := range dirs { name := filepath.Base(d.Name()) - r.volumes[name] = &Volume{ + r.volumes[name] = &localVolume{ driverName: r.Name(), name: name, path: r.DataPath(name), @@ -51,21 +57,29 @@ func New(scope string) (*Root, error) { return r, nil } +// Root implements the Driver interface for the volume package and +// manages the creation/removal of volumes. It uses only standard vfs +// commands to create/remove dirs within its provided scope. type Root struct { m sync.Mutex scope string path string - volumes map[string]*Volume + volumes map[string]*localVolume } +// DataPath returns the constructed path of this volume. func (r *Root) DataPath(volumeName string) string { return filepath.Join(r.path, volumeName, VolumeDataPathName) } +// Name returns the name of Root, defined in the volume package in the DefaultDriverName constant. func (r *Root) Name() string { - return "local" + return volume.DefaultDriverName } +// Create creates a new volume.Volume with the provided name, creating +// the underlying directory tree required for this volume in the +// process. func (r *Root) Create(name string) (volume.Volume, error) { r.m.Lock() defer r.m.Unlock() @@ -79,7 +93,7 @@ func (r *Root) Create(name string) (volume.Volume, error) { } return nil, err } - v = &Volume{ + v = &localVolume{ driverName: r.Name(), name: name, path: path, @@ -90,10 +104,14 @@ func (r *Root) Create(name string) (volume.Volume, error) { return v, nil } +// Remove removes the specified volume and all underlying data. If the +// given volume does not belong to this driver and an error is +// returned. The volume is reference counted, if all references are +// not released then the volume is not removed. func (r *Root) Remove(v volume.Volume) error { r.m.Lock() defer r.m.Unlock() - lv, ok := v.(*Volume) + lv, ok := v.(*localVolume) if !ok { return errors.New("unknown volume type") } @@ -133,7 +151,9 @@ func (r *Root) scopedPath(realPath string) bool { return false } -type Volume struct { +// localVolume implements the Volume interface from the volume package and +// represents the volumes created by Root. +type localVolume struct { m sync.Mutex usedCount int // unique name of the volume @@ -144,33 +164,38 @@ type Volume struct { driverName string } -func (v *Volume) Name() string { +// Name returns the name of the given Volume. +func (v *localVolume) Name() string { return v.name } -func (v *Volume) DriverName() string { +// DriverName returns the driver that created the given Volume. +func (v *localVolume) DriverName() string { return v.driverName } -func (v *Volume) Path() string { +// Path returns the data location. +func (v *localVolume) Path() string { return v.path } -func (v *Volume) Mount() (string, error) { +// Mount implements the localVolume interface, returning the data location. +func (v *localVolume) Mount() (string, error) { return v.path, nil } -func (v *Volume) Unmount() error { +// Umount is for satisfying the localVolume interface and does not do anything in this driver. +func (v *localVolume) Unmount() error { return nil } -func (v *Volume) use() { +func (v *localVolume) use() { v.m.Lock() v.usedCount++ v.m.Unlock() } -func (v *Volume) release() { +func (v *localVolume) release() { v.m.Lock() v.usedCount-- v.m.Unlock() diff --git a/volume/volume.go b/volume/volume.go index 2d5ee35aeb..19c9d77ad9 100644 --- a/volume/volume.go +++ b/volume/volume.go @@ -1,7 +1,10 @@ package volume -const DefaultDriverName = "local" +// DefaultDriverName is the driver name used for the driver +// implemented in the local package. +const DefaultDriverName string = "local" +// Driver is for creating and removing volumes. type Driver interface { // Name returns the name of the volume driver. Name() string @@ -11,6 +14,7 @@ type Driver interface { Remove(Volume) error } +// Volume is a place to store data. It is backed by a specific driver, and can be mounted. type Volume interface { // Name returns the name of the volume Name() string @@ -51,7 +55,7 @@ func ValidateMountMode(mode string) (bool, bool) { return roModes[mode] || rwModes[mode], rwModes[mode] } -// ReadOnly tells you if a mode string is a valid read-only mode or not. +// ReadWrite tells you if a mode string is a valid read-only mode or not. func ReadWrite(mode string) bool { return rwModes[mode] }