github.com/portworx/docker@v1.12.1/layer/layer.go (about)

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