b0ac69b67e
This allows a user to specify explicitly to enable automatic copying of data from the container path to the volume path. This does not change the default behavior of automatically copying, but does allow a user to disable it at runtime. Signed-off-by: Brian Goff <cpuguy83@gmail.com>
137 lines
4.2 KiB
Go
137 lines
4.2 KiB
Go
package volume
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
"strings"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/docker/docker/pkg/system"
|
|
)
|
|
|
|
// 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
|
|
// Create makes a new volume with the given id.
|
|
Create(name string, opts map[string]string) (Volume, error)
|
|
// Remove deletes the volume.
|
|
Remove(vol Volume) (err error)
|
|
// List lists all the volumes the driver has
|
|
List() ([]Volume, error)
|
|
// Get retrieves the volume with the requested name
|
|
Get(name string) (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
|
|
// 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
|
|
}
|
|
|
|
// MountPoint is the intersection point between a volume and a container. It
|
|
// specifies which volume is to be used and where inside a container it should
|
|
// be mounted.
|
|
type MountPoint struct {
|
|
Source string // Container host directory
|
|
Destination string // Inside the container
|
|
RW bool // True if writable
|
|
Name string // Name set by user
|
|
Driver string // Volume driver to use
|
|
Volume Volume `json:"-"`
|
|
|
|
// Note Mode is not used on Windows
|
|
Mode string `json:"Relabel"` // Originally field was `Relabel`"
|
|
|
|
// Note Propagation is not used on Windows
|
|
Propagation string // Mount propagation string
|
|
Named bool // specifies if the mountpoint was specified by name
|
|
|
|
// Specifies if data should be copied from the container before the first mount
|
|
// Use a pointer here so we can tell if the user set this value explicitly
|
|
// This allows us to error out when the user explicitly enabled copy but we can't copy due to the volume being populated
|
|
CopyData bool `json:"-"`
|
|
}
|
|
|
|
// Setup sets up a mount point by either mounting the volume if it is
|
|
// configured, or creating the source directory if supplied.
|
|
func (m *MountPoint) Setup() (string, error) {
|
|
if m.Volume != nil {
|
|
return m.Volume.Mount()
|
|
}
|
|
if len(m.Source) > 0 {
|
|
if _, err := os.Stat(m.Source); err != nil {
|
|
if !os.IsNotExist(err) {
|
|
return "", err
|
|
}
|
|
if runtime.GOOS != "windows" { // Windows does not have deprecation issues here
|
|
logrus.Warnf("Auto-creating non-existent volume host path %s, this is deprecated and will be removed soon", m.Source)
|
|
if err := system.MkdirAll(m.Source, 0755); err != nil {
|
|
return "", err
|
|
}
|
|
}
|
|
}
|
|
return m.Source, nil
|
|
}
|
|
return "", fmt.Errorf("Unable to setup mount point, neither source nor volume defined")
|
|
}
|
|
|
|
// Path returns the path of a volume in a mount point.
|
|
func (m *MountPoint) Path() string {
|
|
if m.Volume != nil {
|
|
return m.Volume.Path()
|
|
}
|
|
return m.Source
|
|
}
|
|
|
|
// ParseVolumesFrom ensures that the supplied volumes-from is valid.
|
|
func ParseVolumesFrom(spec string) (string, string, error) {
|
|
if len(spec) == 0 {
|
|
return "", "", fmt.Errorf("malformed volumes-from specification: %s", spec)
|
|
}
|
|
|
|
specParts := strings.SplitN(spec, ":", 2)
|
|
id := specParts[0]
|
|
mode := "rw"
|
|
|
|
if len(specParts) == 2 {
|
|
mode = specParts[1]
|
|
if !ValidMountMode(mode) {
|
|
return "", "", errInvalidMode(mode)
|
|
}
|
|
// For now don't allow propagation properties while importing
|
|
// volumes from data container. These volumes will inherit
|
|
// the same propagation property as of the original volume
|
|
// in data container. This probably can be relaxed in future.
|
|
if HasPropagation(mode) {
|
|
return "", "", errInvalidMode(mode)
|
|
}
|
|
// Do not allow copy modes on volumes-from
|
|
if _, isSet := getCopyMode(mode); isSet {
|
|
return "", "", errInvalidMode(mode)
|
|
}
|
|
}
|
|
return id, mode, nil
|
|
}
|
|
|
|
func errInvalidMode(mode string) error {
|
|
return fmt.Errorf("invalid mode: %v", mode)
|
|
}
|
|
|
|
func errInvalidSpec(spec string) error {
|
|
return fmt.Errorf("Invalid volume specification: '%s'", spec)
|
|
}
|