github.com/jfrazelle/docker@v1.1.2-0.20210712172922-bf78e25fe508/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 // import "github.com/docker/docker/layer"
    11  
    12  import (
    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  	digest "github.com/opencontainers/go-digest"
    20  	"github.com/sirupsen/logrus"
    21  )
    22  
    23  var (
    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.
    61  type ChainID digest.Digest
    62  
    63  // String returns a string rendition of a layer ID
    64  func (id ChainID) String() string {
    65  	return string(id)
    66  }
    67  
    68  // DiffID is the hash of an individual layer tar.
    69  type DiffID digest.Digest
    70  
    71  // String returns a string rendition of a layer DiffID
    72  func (diffID DiffID) String() string {
    73  	return string(diffID)
    74  }
    75  
    76  // TarStreamer represents an object which may
    77  // have its contents exported as a tar stream.
    78  type TarStreamer interface {
    79  	// TarStream returns a tar archive stream
    80  	// for the contents of a layer.
    81  	TarStream() (io.ReadCloser, error)
    82  }
    83  
    84  // Layer represents a read-only layer
    85  type Layer interface {
    86  	TarStreamer
    87  
    88  	// TarStreamFrom returns a tar archive stream for all the layer chain with
    89  	// arbitrary depth.
    90  	TarStreamFrom(ChainID) (io.ReadCloser, error)
    91  
    92  	// ChainID returns the content hash of the entire layer chain. The hash
    93  	// chain is made up of DiffID of top layer and all of its parents.
    94  	ChainID() ChainID
    95  
    96  	// DiffID returns the content hash of the layer
    97  	// tar stream used to create this layer.
    98  	DiffID() DiffID
    99  
   100  	// Parent returns the next layer in the layer chain.
   101  	Parent() Layer
   102  
   103  	// Size returns the size of the entire layer chain. The size
   104  	// is calculated from the total size of all files in the layers.
   105  	Size() (int64, error)
   106  
   107  	// DiffSize returns the size difference of the top layer
   108  	// from parent layer.
   109  	DiffSize() (int64, error)
   110  
   111  	// Metadata returns the low level storage metadata associated
   112  	// with layer.
   113  	Metadata() (map[string]string, error)
   114  }
   115  
   116  // RWLayer represents a layer which is
   117  // read and writable
   118  type RWLayer interface {
   119  	TarStreamer
   120  
   121  	// Name of mounted layer
   122  	Name() string
   123  
   124  	// Parent returns the layer which the writable
   125  	// layer was created from.
   126  	Parent() Layer
   127  
   128  	// Mount mounts the RWLayer and returns the filesystem path
   129  	// to the writable layer.
   130  	Mount(mountLabel string) (containerfs.ContainerFS, error)
   131  
   132  	// Unmount unmounts the RWLayer. This should be called
   133  	// for every mount. If there are multiple mount calls
   134  	// this operation will only decrement the internal mount counter.
   135  	Unmount() error
   136  
   137  	// Size represents the size of the writable layer
   138  	// as calculated by the total size of the files
   139  	// changed in the mutable layer.
   140  	Size() (int64, error)
   141  
   142  	// Changes returns the set of changes for the mutable layer
   143  	// from the base layer.
   144  	Changes() ([]archive.Change, error)
   145  
   146  	// Metadata returns the low level metadata for the mutable layer
   147  	Metadata() (map[string]string, error)
   148  
   149  	// ApplyDiff applies the diff to the RW layer
   150  	ApplyDiff(diff io.Reader) (int64, error)
   151  }
   152  
   153  // Metadata holds information about a
   154  // read-only layer
   155  type Metadata struct {
   156  	// ChainID is the content hash of the layer
   157  	ChainID ChainID
   158  
   159  	// DiffID is the hash of the tar data used to
   160  	// create the layer
   161  	DiffID DiffID
   162  
   163  	// Size is the size of the layer and all parents
   164  	Size int64
   165  
   166  	// DiffSize is the size of the top layer
   167  	DiffSize int64
   168  }
   169  
   170  // MountInit is a function to initialize a
   171  // writable mount. Changes made here will
   172  // not be included in the Tar stream of the
   173  // RWLayer.
   174  type MountInit func(root containerfs.ContainerFS) error
   175  
   176  // CreateRWLayerOpts contains optional arguments to be passed to CreateRWLayer
   177  type CreateRWLayerOpts struct {
   178  	MountLabel string
   179  	InitFunc   MountInit
   180  	StorageOpt map[string]string
   181  }
   182  
   183  // Store represents a backend for managing both
   184  // read-only and read-write layers.
   185  type Store interface {
   186  	Register(io.Reader, ChainID) (Layer, error)
   187  	Get(ChainID) (Layer, error)
   188  	Map() map[ChainID]Layer
   189  	Release(Layer) ([]Metadata, error)
   190  
   191  	CreateRWLayer(id string, parent ChainID, opts *CreateRWLayerOpts) (RWLayer, error)
   192  	GetRWLayer(id string) (RWLayer, error)
   193  	GetMountID(id string) (string, error)
   194  	ReleaseRWLayer(RWLayer) ([]Metadata, error)
   195  
   196  	Cleanup() error
   197  	DriverStatus() [][2]string
   198  	DriverName() string
   199  }
   200  
   201  // DescribableStore represents a layer store capable of storing
   202  // descriptors for layers.
   203  type DescribableStore interface {
   204  	RegisterWithDescriptor(io.Reader, ChainID, distribution.Descriptor) (Layer, error)
   205  }
   206  
   207  // CreateChainID returns ID for a layerDigest slice
   208  func CreateChainID(dgsts []DiffID) ChainID {
   209  	return createChainIDFromParent("", dgsts...)
   210  }
   211  
   212  func createChainIDFromParent(parent ChainID, dgsts ...DiffID) ChainID {
   213  	if len(dgsts) == 0 {
   214  		return parent
   215  	}
   216  	if parent == "" {
   217  		return createChainIDFromParent(ChainID(dgsts[0]), dgsts[1:]...)
   218  	}
   219  	// H = "H(n-1) SHA256(n)"
   220  	dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0])))
   221  	return createChainIDFromParent(ChainID(dgst), dgsts[1:]...)
   222  }
   223  
   224  // ReleaseAndLog releases the provided layer from the given layer
   225  // store, logging any error and release metadata
   226  func ReleaseAndLog(ls Store, l Layer) {
   227  	metadata, err := ls.Release(l)
   228  	if err != nil {
   229  		logrus.Errorf("Error releasing layer %s: %v", l.ChainID(), err)
   230  	}
   231  	LogReleaseMetadata(metadata)
   232  }
   233  
   234  // LogReleaseMetadata logs a metadata array, uses this to
   235  // ensure consistent logging for release metadata
   236  func LogReleaseMetadata(metadatas []Metadata) {
   237  	for _, metadata := range metadatas {
   238  		logrus.Infof("Layer %s cleaned up", metadata.ChainID)
   239  	}
   240  }