layer.go 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. // Package layer is package for managing read-only
  2. // and read-write mounts on the union file system
  3. // driver. Read-only mounts are referenced using a
  4. // content hash and are protected from mutation in
  5. // the exposed interface. The tar format is used
  6. // to create read-only layers and export both
  7. // read-only and writable layers. The exported
  8. // tar data for a read-only layer should match
  9. // the tar used to create the layer.
  10. package layer
  11. import (
  12. "errors"
  13. "io"
  14. "github.com/Sirupsen/logrus"
  15. "github.com/docker/distribution"
  16. "github.com/docker/docker/pkg/archive"
  17. "github.com/opencontainers/go-digest"
  18. )
  19. var (
  20. // ErrLayerDoesNotExist is used when an operation is
  21. // attempted on a layer which does not exist.
  22. ErrLayerDoesNotExist = errors.New("layer does not exist")
  23. // ErrLayerNotRetained is used when a release is
  24. // attempted on a layer which is not retained.
  25. ErrLayerNotRetained = errors.New("layer not retained")
  26. // ErrMountDoesNotExist is used when an operation is
  27. // attempted on a mount layer which does not exist.
  28. ErrMountDoesNotExist = errors.New("mount does not exist")
  29. // ErrMountNameConflict is used when a mount is attempted
  30. // to be created but there is already a mount with the name
  31. // used for creation.
  32. ErrMountNameConflict = errors.New("mount already exists with name")
  33. // ErrActiveMount is used when an operation on a
  34. // mount is attempted but the layer is still
  35. // mounted and the operation cannot be performed.
  36. ErrActiveMount = errors.New("mount still active")
  37. // ErrNotMounted is used when requesting an active
  38. // mount but the layer is not mounted.
  39. ErrNotMounted = errors.New("not mounted")
  40. // ErrMaxDepthExceeded is used when a layer is attempted
  41. // to be created which would result in a layer depth
  42. // greater than the 125 max.
  43. ErrMaxDepthExceeded = errors.New("max depth exceeded")
  44. // ErrNotSupported is used when the action is not supported
  45. // on the current platform
  46. ErrNotSupported = errors.New("not support on this platform")
  47. )
  48. // ChainID is the content-addressable ID of a layer.
  49. type ChainID digest.Digest
  50. // String returns a string rendition of a layer ID
  51. func (id ChainID) String() string {
  52. return string(id)
  53. }
  54. // DiffID is the hash of an individual layer tar.
  55. type DiffID digest.Digest
  56. // String returns a string rendition of a layer DiffID
  57. func (diffID DiffID) String() string {
  58. return string(diffID)
  59. }
  60. // TarStreamer represents an object which may
  61. // have its contents exported as a tar stream.
  62. type TarStreamer interface {
  63. // TarStream returns a tar archive stream
  64. // for the contents of a layer.
  65. TarStream() (io.ReadCloser, error)
  66. }
  67. // Layer represents a read-only layer
  68. type Layer interface {
  69. TarStreamer
  70. // TarStreamFrom returns a tar archive stream for all the layer chain with
  71. // arbitrary depth.
  72. TarStreamFrom(ChainID) (io.ReadCloser, error)
  73. // ChainID returns the content hash of the entire layer chain. The hash
  74. // chain is made up of DiffID of top layer and all of its parents.
  75. ChainID() ChainID
  76. // DiffID returns the content hash of the layer
  77. // tar stream used to create this layer.
  78. DiffID() DiffID
  79. // Parent returns the next layer in the layer chain.
  80. Parent() Layer
  81. // Size returns the size of the entire layer chain. The size
  82. // is calculated from the total size of all files in the layers.
  83. Size() (int64, error)
  84. // DiffSize returns the size difference of the top layer
  85. // from parent layer.
  86. DiffSize() (int64, error)
  87. // Metadata returns the low level storage metadata associated
  88. // with layer.
  89. Metadata() (map[string]string, error)
  90. }
  91. // RWLayer represents a layer which is
  92. // read and writable
  93. type RWLayer interface {
  94. TarStreamer
  95. // Name of mounted layer
  96. Name() string
  97. // Parent returns the layer which the writable
  98. // layer was created from.
  99. Parent() Layer
  100. // Mount mounts the RWLayer and returns the filesystem path
  101. // the to the writable layer.
  102. Mount(mountLabel string) (string, error)
  103. // Unmount unmounts the RWLayer. This should be called
  104. // for every mount. If there are multiple mount calls
  105. // this operation will only decrement the internal mount counter.
  106. Unmount() error
  107. // Size represents the size of the writable layer
  108. // as calculated by the total size of the files
  109. // changed in the mutable layer.
  110. Size() (int64, error)
  111. // Changes returns the set of changes for the mutable layer
  112. // from the base layer.
  113. Changes() ([]archive.Change, error)
  114. // Metadata returns the low level metadata for the mutable layer
  115. Metadata() (map[string]string, error)
  116. }
  117. // Metadata holds information about a
  118. // read-only layer
  119. type Metadata struct {
  120. // ChainID is the content hash of the layer
  121. ChainID ChainID
  122. // DiffID is the hash of the tar data used to
  123. // create the layer
  124. DiffID DiffID
  125. // Size is the size of the layer and all parents
  126. Size int64
  127. // DiffSize is the size of the top layer
  128. DiffSize int64
  129. }
  130. // MountInit is a function to initialize a
  131. // writable mount. Changes made here will
  132. // not be included in the Tar stream of the
  133. // RWLayer.
  134. type MountInit func(root string) error
  135. // CreateRWLayerOpts contains optional arguments to be passed to CreateRWLayer
  136. type CreateRWLayerOpts struct {
  137. MountLabel string
  138. InitFunc MountInit
  139. StorageOpt map[string]string
  140. }
  141. // Store represents a backend for managing both
  142. // read-only and read-write layers.
  143. type Store interface {
  144. Register(io.Reader, ChainID) (Layer, error)
  145. Get(ChainID) (Layer, error)
  146. Map() map[ChainID]Layer
  147. Release(Layer) ([]Metadata, error)
  148. CreateRWLayer(id string, parent ChainID, opts *CreateRWLayerOpts) (RWLayer, error)
  149. GetRWLayer(id string) (RWLayer, error)
  150. GetMountID(id string) (string, error)
  151. ReleaseRWLayer(RWLayer) ([]Metadata, error)
  152. Cleanup() error
  153. DriverStatus() [][2]string
  154. DriverName() string
  155. }
  156. // DescribableStore represents a layer store capable of storing
  157. // descriptors for layers.
  158. type DescribableStore interface {
  159. RegisterWithDescriptor(io.Reader, ChainID, distribution.Descriptor) (Layer, error)
  160. }
  161. // MetadataTransaction represents functions for setting layer metadata
  162. // with a single transaction.
  163. type MetadataTransaction interface {
  164. SetSize(int64) error
  165. SetParent(parent ChainID) error
  166. SetDiffID(DiffID) error
  167. SetCacheID(string) error
  168. SetDescriptor(distribution.Descriptor) error
  169. TarSplitWriter(compressInput bool) (io.WriteCloser, error)
  170. Commit(ChainID) error
  171. Cancel() error
  172. String() string
  173. }
  174. // MetadataStore represents a backend for persisting
  175. // metadata about layers and providing the metadata
  176. // for restoring a Store.
  177. type MetadataStore interface {
  178. // StartTransaction starts an update for new metadata
  179. // which will be used to represent an ID on commit.
  180. StartTransaction() (MetadataTransaction, error)
  181. GetSize(ChainID) (int64, error)
  182. GetParent(ChainID) (ChainID, error)
  183. GetDiffID(ChainID) (DiffID, error)
  184. GetCacheID(ChainID) (string, error)
  185. GetDescriptor(ChainID) (distribution.Descriptor, error)
  186. TarSplitReader(ChainID) (io.ReadCloser, error)
  187. SetMountID(string, string) error
  188. SetInitID(string, string) error
  189. SetMountParent(string, ChainID) error
  190. GetMountID(string) (string, error)
  191. GetInitID(string) (string, error)
  192. GetMountParent(string) (ChainID, error)
  193. // List returns the full list of referenced
  194. // read-only and read-write layers
  195. List() ([]ChainID, []string, error)
  196. Remove(ChainID) error
  197. RemoveMount(string) error
  198. }
  199. // CreateChainID returns ID for a layerDigest slice
  200. func CreateChainID(dgsts []DiffID) ChainID {
  201. return createChainIDFromParent("", dgsts...)
  202. }
  203. func createChainIDFromParent(parent ChainID, dgsts ...DiffID) ChainID {
  204. if len(dgsts) == 0 {
  205. return parent
  206. }
  207. if parent == "" {
  208. return createChainIDFromParent(ChainID(dgsts[0]), dgsts[1:]...)
  209. }
  210. // H = "H(n-1) SHA256(n)"
  211. dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
  212. return createChainIDFromParent(ChainID(dgst), dgsts[1:]...)
  213. }
  214. // ReleaseAndLog releases the provided layer from the given layer
  215. // store, logging any error and release metadata
  216. func ReleaseAndLog(ls Store, l Layer) {
  217. metadata, err := ls.Release(l)
  218. if err != nil {
  219. logrus.Errorf("Error releasing layer %s: %v", l.ChainID(), err)
  220. }
  221. LogReleaseMetadata(metadata)
  222. }
  223. // LogReleaseMetadata logs a metadata array, uses this to
  224. // ensure consistent logging for release metadata
  225. func LogReleaseMetadata(metadatas []Metadata) {
  226. for _, metadata := range metadatas {
  227. logrus.Infof("Layer %s cleaned up", metadata.ChainID)
  228. }
  229. }