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 }