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 }