volume.go 5.8 KB

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