github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/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/docker/distribution" 17 "github.com/docker/docker/pkg/archive" 18 "github.com/docker/docker/pkg/containerfs" 19 "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 // OS is the operating system of a layer 69 type OS string 70 71 // String returns a string rendition of layers target operating system 72 func (id OS) String() string { 73 return string(id) 74 } 75 76 // DiffID is the hash of an individual layer tar. 77 type DiffID digest.Digest 78 79 // String returns a string rendition of a layer DiffID 80 func (diffID DiffID) String() string { 81 return string(diffID) 82 } 83 84 // TarStreamer represents an object which may 85 // have its contents exported as a tar stream. 86 type TarStreamer interface { 87 // TarStream returns a tar archive stream 88 // for the contents of a layer. 89 TarStream() (io.ReadCloser, error) 90 } 91 92 // Layer represents a read-only layer 93 type Layer interface { 94 TarStreamer 95 96 // TarStreamFrom returns a tar archive stream for all the layer chain with 97 // arbitrary depth. 98 TarStreamFrom(ChainID) (io.ReadCloser, error) 99 100 // ChainID returns the content hash of the entire layer chain. The hash 101 // chain is made up of DiffID of top layer and all of its parents. 102 ChainID() ChainID 103 104 // DiffID returns the content hash of the layer 105 // tar stream used to create this layer. 106 DiffID() DiffID 107 108 // Parent returns the next layer in the layer chain. 109 Parent() Layer 110 111 // OS returns the operating system of the layer 112 OS() OS 113 114 // Size returns the size of the entire layer chain. The size 115 // is calculated from the total size of all files in the layers. 116 Size() (int64, error) 117 118 // DiffSize returns the size difference of the top layer 119 // from parent layer. 120 DiffSize() (int64, error) 121 122 // Metadata returns the low level storage metadata associated 123 // with layer. 124 Metadata() (map[string]string, error) 125 } 126 127 // RWLayer represents a layer which is 128 // read and writable 129 type RWLayer interface { 130 TarStreamer 131 132 // Name of mounted layer 133 Name() string 134 135 // Parent returns the layer which the writable 136 // layer was created from. 137 Parent() Layer 138 139 // Mount mounts the RWLayer and returns the filesystem path 140 // the to the writable layer. 141 Mount(mountLabel string) (containerfs.ContainerFS, error) 142 143 // Unmount unmounts the RWLayer. This should be called 144 // for every mount. If there are multiple mount calls 145 // this operation will only decrement the internal mount counter. 146 Unmount() error 147 148 // Size represents the size of the writable layer 149 // as calculated by the total size of the files 150 // changed in the mutable layer. 151 Size() (int64, error) 152 153 // Changes returns the set of changes for the mutable layer 154 // from the base layer. 155 Changes() ([]archive.Change, error) 156 157 // Metadata returns the low level metadata for the mutable layer 158 Metadata() (map[string]string, error) 159 } 160 161 // Metadata holds information about a 162 // read-only layer 163 type Metadata struct { 164 // ChainID is the content hash of the layer 165 ChainID ChainID 166 167 // DiffID is the hash of the tar data used to 168 // create the layer 169 DiffID DiffID 170 171 // Size is the size of the layer and all parents 172 Size int64 173 174 // DiffSize is the size of the top layer 175 DiffSize int64 176 } 177 178 // MountInit is a function to initialize a 179 // writable mount. Changes made here will 180 // not be included in the Tar stream of the 181 // RWLayer. 182 type MountInit func(root containerfs.ContainerFS) error 183 184 // CreateRWLayerOpts contains optional arguments to be passed to CreateRWLayer 185 type CreateRWLayerOpts struct { 186 MountLabel string 187 InitFunc MountInit 188 StorageOpt map[string]string 189 } 190 191 // Store represents a backend for managing both 192 // read-only and read-write layers. 193 type Store interface { 194 Register(io.Reader, ChainID, OS) (Layer, error) 195 Get(ChainID) (Layer, error) 196 Map() map[ChainID]Layer 197 Release(Layer) ([]Metadata, error) 198 199 CreateRWLayer(id string, parent ChainID, opts *CreateRWLayerOpts) (RWLayer, error) 200 GetRWLayer(id string) (RWLayer, error) 201 GetMountID(id string) (string, error) 202 ReleaseRWLayer(RWLayer) ([]Metadata, error) 203 204 Cleanup() error 205 DriverStatus() [][2]string 206 DriverName() string 207 } 208 209 // DescribableStore represents a layer store capable of storing 210 // descriptors for layers. 211 type DescribableStore interface { 212 RegisterWithDescriptor(io.Reader, ChainID, OS, distribution.Descriptor) (Layer, error) 213 } 214 215 // MetadataTransaction represents functions for setting layer metadata 216 // with a single transaction. 217 type MetadataTransaction interface { 218 SetSize(int64) error 219 SetParent(parent ChainID) error 220 SetDiffID(DiffID) error 221 SetCacheID(string) error 222 SetDescriptor(distribution.Descriptor) error 223 SetOS(OS) error 224 TarSplitWriter(compressInput bool) (io.WriteCloser, error) 225 226 Commit(ChainID) error 227 Cancel() error 228 String() string 229 } 230 231 // MetadataStore represents a backend for persisting 232 // metadata about layers and providing the metadata 233 // for restoring a Store. 234 type MetadataStore interface { 235 // StartTransaction starts an update for new metadata 236 // which will be used to represent an ID on commit. 237 StartTransaction() (MetadataTransaction, error) 238 239 GetSize(ChainID) (int64, error) 240 GetParent(ChainID) (ChainID, error) 241 GetDiffID(ChainID) (DiffID, error) 242 GetCacheID(ChainID) (string, error) 243 GetDescriptor(ChainID) (distribution.Descriptor, error) 244 GetOS(ChainID) (OS, error) 245 TarSplitReader(ChainID) (io.ReadCloser, error) 246 247 SetMountID(string, string) error 248 SetInitID(string, string) error 249 SetMountParent(string, ChainID) error 250 251 GetMountID(string) (string, error) 252 GetInitID(string) (string, error) 253 GetMountParent(string) (ChainID, error) 254 255 // List returns the full list of referenced 256 // read-only and read-write layers 257 List() ([]ChainID, []string, error) 258 259 Remove(ChainID) error 260 RemoveMount(string) error 261 } 262 263 // CreateChainID returns ID for a layerDigest slice 264 func CreateChainID(dgsts []DiffID) ChainID { 265 return createChainIDFromParent("", dgsts...) 266 } 267 268 func createChainIDFromParent(parent ChainID, dgsts ...DiffID) ChainID { 269 if len(dgsts) == 0 { 270 return parent 271 } 272 if parent == "" { 273 return createChainIDFromParent(ChainID(dgsts[0]), dgsts[1:]...) 274 } 275 // H = "H(n-1) SHA256(n)" 276 dgst := digest.FromBytes([]byte(string(parent) + " " + string(dgsts[0]))) 277 return createChainIDFromParent(ChainID(dgst), dgsts[1:]...) 278 } 279 280 // ReleaseAndLog releases the provided layer from the given layer 281 // store, logging any error and release metadata 282 func ReleaseAndLog(ls Store, l Layer) { 283 metadata, err := ls.Release(l) 284 if err != nil { 285 logrus.Errorf("Error releasing layer %s: %v", l.ChainID(), err) 286 } 287 LogReleaseMetadata(metadata) 288 } 289 290 // LogReleaseMetadata logs a metadata array, uses this to 291 // ensure consistent logging for release metadata 292 func LogReleaseMetadata(metadatas []Metadata) { 293 for _, metadata := range metadatas { 294 logrus.Infof("Layer %s cleaned up", metadata.ChainID) 295 } 296 }