| 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) |
| } |