layer/layer.go
bbeb859b
 // Package layer is package for managing read-only
500e77ba
 // and read-write mounts on the union file system
927b334e
 // driver. Read-only mounts are referenced using a
500e77ba
 // content hash and are protected from mutation in
 // the exposed interface. The tar format is used
bbeb859b
 // to create read-only layers and export both
 // read-only and writable layers. The exported
 // tar data for a read-only layer should match
500e77ba
 // the tar used to create the layer.
4f0d95fa
 package layer // import "github.com/docker/docker/layer"
500e77ba
 
 import (
 	"errors"
 	"io"
 
05bd0435
 	"github.com/docker/distribution"
500e77ba
 	"github.com/docker/docker/pkg/archive"
7a7357da
 	"github.com/docker/docker/pkg/containerfs"
7a855799
 	"github.com/opencontainers/go-digest"
1009e6a4
 	"github.com/sirupsen/logrus"
500e77ba
 )
 
 var (
 	// ErrLayerDoesNotExist is used when an operation is
 	// attempted on a layer which does not exist.
 	ErrLayerDoesNotExist = errors.New("layer does not exist")
 
 	// ErrLayerNotRetained is used when a release is
 	// attempted on a layer which is not retained.
 	ErrLayerNotRetained = errors.New("layer not retained")
 
 	// ErrMountDoesNotExist is used when an operation is
 	// attempted on a mount layer which does not exist.
 	ErrMountDoesNotExist = errors.New("mount does not exist")
 
d04fa49a
 	// ErrMountNameConflict is used when a mount is attempted
 	// to be created but there is already a mount with the name
 	// used for creation.
 	ErrMountNameConflict = errors.New("mount already exists with name")
 
500e77ba
 	// ErrActiveMount is used when an operation on a
 	// mount is attempted but the layer is still
 	// mounted and the operation cannot be performed.
 	ErrActiveMount = errors.New("mount still active")
 
 	// ErrNotMounted is used when requesting an active
 	// mount but the layer is not mounted.
 	ErrNotMounted = errors.New("not mounted")
 
 	// ErrMaxDepthExceeded is used when a layer is attempted
 	// to be created which would result in a layer depth
 	// greater than the 125 max.
 	ErrMaxDepthExceeded = errors.New("max depth exceeded")
65d79e3e
 
950073aa
 	// ErrNotSupported is used when the action is not supported
0380fbff
 	// on the current host operating system.
 	ErrNotSupported = errors.New("not support on this host operating system")
500e77ba
 )
 
 // ChainID is the content-addressable ID of a layer.
 type ChainID digest.Digest
 
 // String returns a string rendition of a layer ID
 func (id ChainID) String() string {
 	return string(id)
 }
 
 // DiffID is the hash of an individual layer tar.
 type DiffID digest.Digest
 
 // String returns a string rendition of a layer DiffID
 func (diffID DiffID) String() string {
 	return string(diffID)
 }
 
 // TarStreamer represents an object which may
 // have its contents exported as a tar stream.
 type TarStreamer interface {
 	// TarStream returns a tar archive stream
 	// for the contents of a layer.
21278efa
 	TarStream() (io.ReadCloser, error)
500e77ba
 }
 
bbeb859b
 // Layer represents a read-only layer
500e77ba
 type Layer interface {
 	TarStreamer
 
8625d253
 	// TarStreamFrom returns a tar archive stream for all the layer chain with
 	// arbitrary depth.
 	TarStreamFrom(ChainID) (io.ReadCloser, error)
 
500e77ba
 	// ChainID returns the content hash of the entire layer chain. The hash
 	// chain is made up of DiffID of top layer and all of its parents.
 	ChainID() ChainID
 
 	// DiffID returns the content hash of the layer
 	// tar stream used to create this layer.
 	DiffID() DiffID
 
 	// Parent returns the next layer in the layer chain.
 	Parent() Layer
 
 	// Size returns the size of the entire layer chain. The size
 	// is calculated from the total size of all files in the layers.
 	Size() (int64, error)
 
 	// DiffSize returns the size difference of the top layer
 	// from parent layer.
 	DiffSize() (int64, error)
 
 	// Metadata returns the low level storage metadata associated
 	// with layer.
 	Metadata() (map[string]string, error)
 }
 
 // RWLayer represents a layer which is
 // read and writable
 type RWLayer interface {
 	TarStreamer
 
d04fa49a
 	// Name of mounted layer
 	Name() string
500e77ba
 
 	// Parent returns the layer which the writable
 	// layer was created from.
 	Parent() Layer
 
d04fa49a
 	// Mount mounts the RWLayer and returns the filesystem path
 	// the to the writable layer.
7a7357da
 	Mount(mountLabel string) (containerfs.ContainerFS, error)
d04fa49a
 
 	// Unmount unmounts the RWLayer. This should be called
 	// for every mount. If there are multiple mount calls
 	// this operation will only decrement the internal mount counter.
 	Unmount() error
 
500e77ba
 	// Size represents the size of the writable layer
 	// as calculated by the total size of the files
 	// changed in the mutable layer.
 	Size() (int64, error)
d04fa49a
 
 	// Changes returns the set of changes for the mutable layer
 	// from the base layer.
 	Changes() ([]archive.Change, error)
 
 	// Metadata returns the low level metadata for the mutable layer
 	Metadata() (map[string]string, error)
500e77ba
 }
 
 // Metadata holds information about a
bbeb859b
 // read-only layer
500e77ba
 type Metadata struct {
 	// ChainID is the content hash of the layer
 	ChainID ChainID
 
 	// DiffID is the hash of the tar data used to
 	// create the layer
 	DiffID DiffID
 
 	// Size is the size of the layer and all parents
 	Size int64
 
 	// DiffSize is the size of the top layer
 	DiffSize int64
 }
 
 // MountInit is a function to initialize a
 // writable mount. Changes made here will
 // not be included in the Tar stream of the
 // RWLayer.
7a7357da
 type MountInit func(root containerfs.ContainerFS) error
500e77ba
 
f7f3d342
 // CreateRWLayerOpts contains optional arguments to be passed to CreateRWLayer
 type CreateRWLayerOpts struct {
 	MountLabel string
 	InitFunc   MountInit
 	StorageOpt map[string]string
 }
 
500e77ba
 // Store represents a backend for managing both
 // read-only and read-write layers.
 type Store interface {
afd305c4
 	Register(io.Reader, ChainID) (Layer, error)
500e77ba
 	Get(ChainID) (Layer, error)
148aef91
 	Map() map[ChainID]Layer
500e77ba
 	Release(Layer) ([]Metadata, error)
 
afd305c4
 	CreateRWLayer(id string, parent ChainID, opts *CreateRWLayerOpts) (RWLayer, error)
d04fa49a
 	GetRWLayer(id string) (RWLayer, error)
9c4570a9
 	GetMountID(id string) (string, error)
d04fa49a
 	ReleaseRWLayer(RWLayer) ([]Metadata, error)
f5916b10
 
 	Cleanup() error
afd305c4
 	DriverStatus() [][2]string
 	DriverName() string
500e77ba
 }
 
2c60430a
 // DescribableStore represents a layer store capable of storing
 // descriptors for layers.
 type DescribableStore interface {
afd305c4
 	RegisterWithDescriptor(io.Reader, ChainID, distribution.Descriptor) (Layer, error)
2c60430a
 }
 
500e77ba
 // CreateChainID returns ID for a layerDigest slice
 func CreateChainID(dgsts []DiffID) ChainID {
 	return createChainIDFromParent("", dgsts...)
 }
 
 func createChainIDFromParent(parent ChainID, dgsts ...DiffID) ChainID {
 	if len(dgsts) == 0 {
 		return parent
 	}
 	if parent == "" {
 		return createChainIDFromParent(ChainID(dgsts[0]), dgsts[1:]...)
 	}
 	// H = "H(n-1) SHA256(n)"
c168a005
 	dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
500e77ba
 	return createChainIDFromParent(ChainID(dgst), dgsts[1:]...)
 }
 
 // ReleaseAndLog releases the provided layer from the given layer
 // store, logging any error and release metadata
 func ReleaseAndLog(ls Store, l Layer) {
 	metadata, err := ls.Release(l)
 	if err != nil {
 		logrus.Errorf("Error releasing layer %s: %v", l.ChainID(), err)
 	}
 	LogReleaseMetadata(metadata)
 }
 
bbeb859b
 // LogReleaseMetadata logs a metadata array, uses this to
500e77ba
 // ensure consistent logging for release metadata
 func LogReleaseMetadata(metadatas []Metadata) {
 	for _, metadata := range metadatas {
 		logrus.Infof("Layer %s cleaned up", metadata.ChainID)
 	}
 }