github.com/portworx/docker@v1.12.1/volume/volume.go (about) 1 package volume 2 3 import ( 4 "fmt" 5 "os" 6 "strings" 7 "syscall" 8 9 "github.com/docker/docker/pkg/stringid" 10 "github.com/docker/docker/pkg/system" 11 "github.com/opencontainers/runc/libcontainer/label" 12 ) 13 14 // DefaultDriverName is the driver name used for the driver 15 // implemented in the local package. 16 const DefaultDriverName = "local" 17 18 // Scopes define if a volume has is cluster-wide (global) or local only. 19 // Scopes are returned by the volume driver when it is queried for capabilities and then set on a volume 20 const ( 21 LocalScope = "local" 22 GlobalScope = "global" 23 ) 24 25 // Driver is for creating and removing volumes. 26 type Driver interface { 27 // Name returns the name of the volume driver. 28 Name() string 29 // Create makes a new volume with the given id. 30 Create(name string, opts map[string]string) (Volume, error) 31 // Remove deletes the volume. 32 Remove(vol Volume) (err error) 33 // List lists all the volumes the driver has 34 List() ([]Volume, error) 35 // Get retrieves the volume with the requested name 36 Get(name string) (Volume, error) 37 // Scope returns the scope of the driver (e.g. `golbal` or `local`). 38 // Scope determines how the driver is handled at a cluster level 39 Scope() string 40 } 41 42 // Capability defines a set of capabilities that a driver is able to handle. 43 type Capability struct { 44 // Scope is the scope of the driver, `global` or `local` 45 // A `global` scope indicates that the driver manages volumes across the cluster 46 // A `local` scope indicates that the driver only manages volumes resources local to the host 47 // Scope is declared by the driver 48 Scope string 49 } 50 51 // Volume is a place to store data. It is backed by a specific driver, and can be mounted. 52 type Volume interface { 53 // Name returns the name of the volume 54 Name() string 55 // DriverName returns the name of the driver which owns this volume. 56 DriverName() string 57 // Path returns the absolute path to the volume. 58 Path() string 59 // Mount mounts the volume and returns the absolute path to 60 // where it can be consumed. 61 Mount(id string) (string, error) 62 // Unmount unmounts the volume when it is no longer in use. 63 Unmount(id string) error 64 // Status returns low-level status information about a volume 65 Status() map[string]interface{} 66 } 67 68 // LabeledVolume wraps a Volume with user-defined labels 69 type LabeledVolume interface { 70 Labels() map[string]string 71 Volume 72 } 73 74 // ScopedVolume wraps a volume with a cluster scope (e.g., `local` or `global`) 75 type ScopedVolume interface { 76 Scope() string 77 Volume 78 } 79 80 // MountPoint is the intersection point between a volume and a container. It 81 // specifies which volume is to be used and where inside a container it should 82 // be mounted. 83 type MountPoint struct { 84 Source string // Container host directory 85 Destination string // Inside the container 86 RW bool // True if writable 87 Name string // Name set by user 88 Driver string // Volume driver to use 89 Volume Volume `json:"-"` 90 91 // Note Mode is not used on Windows 92 Mode string `json:"Relabel"` // Originally field was `Relabel`" 93 94 // Note Propagation is not used on Windows 95 Propagation string // Mount propagation string 96 Named bool // specifies if the mountpoint was specified by name 97 98 // Specifies if data should be copied from the container before the first mount 99 // Use a pointer here so we can tell if the user set this value explicitly 100 // This allows us to error out when the user explicitly enabled copy but we can't copy due to the volume being populated 101 CopyData bool `json:"-"` 102 // ID is the opaque ID used to pass to the volume driver. 103 // This should be set by calls to `Mount` and unset by calls to `Unmount` 104 ID string 105 } 106 107 // Setup sets up a mount point by either mounting the volume if it is 108 // configured, or creating the source directory if supplied. 109 func (m *MountPoint) Setup(mountLabel string) (string, error) { 110 if m.Volume != nil { 111 if m.ID == "" { 112 m.ID = stringid.GenerateNonCryptoID() 113 } 114 return m.Volume.Mount(m.ID) 115 } 116 if len(m.Source) == 0 { 117 return "", fmt.Errorf("Unable to setup mount point, neither source nor volume defined") 118 } 119 // system.MkdirAll() produces an error if m.Source exists and is a file (not a directory), 120 if err := system.MkdirAll(m.Source, 0755); err != nil { 121 if perr, ok := err.(*os.PathError); ok { 122 if perr.Err != syscall.ENOTDIR { 123 return "", err 124 } 125 } 126 } 127 if label.RelabelNeeded(m.Mode) { 128 if err := label.Relabel(m.Source, mountLabel, label.IsShared(m.Mode)); err != nil { 129 return "", err 130 } 131 } 132 return m.Source, nil 133 } 134 135 // Path returns the path of a volume in a mount point. 136 func (m *MountPoint) Path() string { 137 if m.Volume != nil { 138 return m.Volume.Path() 139 } 140 return m.Source 141 } 142 143 // Type returns the type of mount point 144 func (m *MountPoint) Type() string { 145 if m.Name != "" { 146 return "volume" 147 } 148 if m.Source != "" { 149 return "bind" 150 } 151 return "ephemeral" 152 } 153 154 // ParseVolumesFrom ensures that the supplied volumes-from is valid. 155 func ParseVolumesFrom(spec string) (string, string, error) { 156 if len(spec) == 0 { 157 return "", "", fmt.Errorf("malformed volumes-from specification: %s", spec) 158 } 159 160 specParts := strings.SplitN(spec, ":", 2) 161 id := specParts[0] 162 mode := "rw" 163 164 if len(specParts) == 2 { 165 mode = specParts[1] 166 if !ValidMountMode(mode) { 167 return "", "", errInvalidMode(mode) 168 } 169 // For now don't allow propagation properties while importing 170 // volumes from data container. These volumes will inherit 171 // the same propagation property as of the original volume 172 // in data container. This probably can be relaxed in future. 173 if HasPropagation(mode) { 174 return "", "", errInvalidMode(mode) 175 } 176 // Do not allow copy modes on volumes-from 177 if _, isSet := getCopyMode(mode); isSet { 178 return "", "", errInvalidMode(mode) 179 } 180 } 181 return id, mode, nil 182 } 183 184 func errInvalidMode(mode string) error { 185 return fmt.Errorf("invalid mode: %v", mode) 186 } 187 188 func errInvalidSpec(spec string) error { 189 return fmt.Errorf("Invalid volume specification: '%s'", spec) 190 }