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