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.
 package layer
 
 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
 // MetadataTransaction represents functions for setting layer metadata
 // with a single transaction.
 type MetadataTransaction interface {
 	SetSize(int64) error
 	SetParent(parent ChainID) error
 	SetDiffID(DiffID) error
 	SetCacheID(string) error
2c60430a
 	SetDescriptor(distribution.Descriptor) error
0cba7740
 	setOS(string) error
a8f88ef4
 	TarSplitWriter(compressInput bool) (io.WriteCloser, error)
500e77ba
 
 	Commit(ChainID) error
 	Cancel() error
 	String() string
 }
 
 // MetadataStore represents a backend for persisting
 // metadata about layers and providing the metadata
 // for restoring a Store.
 type MetadataStore interface {
 	// StartTransaction starts an update for new metadata
 	// which will be used to represent an ID on commit.
 	StartTransaction() (MetadataTransaction, error)
 
 	GetSize(ChainID) (int64, error)
 	GetParent(ChainID) (ChainID, error)
 	GetDiffID(ChainID) (DiffID, error)
 	GetCacheID(ChainID) (string, error)
2c60430a
 	GetDescriptor(ChainID) (distribution.Descriptor, error)
0cba7740
 	getOS(ChainID) (string, error)
500e77ba
 	TarSplitReader(ChainID) (io.ReadCloser, error)
 
 	SetMountID(string, string) error
 	SetInitID(string, string) error
 	SetMountParent(string, ChainID) error
 
 	GetMountID(string) (string, error)
 	GetInitID(string) (string, error)
 	GetMountParent(string) (ChainID, error)
 
927b334e
 	// List returns the full list of referenced
500e77ba
 	// read-only and read-write layers
 	List() ([]ChainID, []string, error)
 
 	Remove(ChainID) error
 	RemoveMount(string) error
 }
 
 // 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)
 	}
 }