github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/moby/image/store.go (about) 1 package image // import "github.com/docker/docker/image" 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "sync" 7 "time" 8 9 "github.com/docker/distribution/digestset" 10 "github.com/docker/docker/layer" 11 "github.com/docker/docker/pkg/system" 12 digest "github.com/opencontainers/go-digest" 13 "github.com/pkg/errors" 14 "github.com/sirupsen/logrus" 15 ) 16 17 // Store is an interface for creating and accessing images 18 type Store interface { 19 Create(config []byte) (ID, error) 20 Get(id ID) (*Image, error) 21 Delete(id ID) ([]layer.Metadata, error) 22 Search(partialID string) (ID, error) 23 SetParent(id ID, parent ID) error 24 GetParent(id ID) (ID, error) 25 SetLastUpdated(id ID) error 26 GetLastUpdated(id ID) (time.Time, error) 27 Children(id ID) []ID 28 Map() map[ID]*Image 29 Heads() map[ID]*Image 30 Len() int 31 } 32 33 // LayerGetReleaser is a minimal interface for getting and releasing images. 34 type LayerGetReleaser interface { 35 Get(layer.ChainID) (layer.Layer, error) 36 Release(layer.Layer) ([]layer.Metadata, error) 37 } 38 39 type imageMeta struct { 40 layer layer.Layer 41 children map[ID]struct{} 42 } 43 44 type store struct { 45 sync.RWMutex 46 lss map[string]LayerGetReleaser 47 images map[ID]*imageMeta 48 fs StoreBackend 49 digestSet *digestset.Set 50 } 51 52 // NewImageStore returns new store object for given set of layer stores 53 func NewImageStore(fs StoreBackend, lss map[string]LayerGetReleaser) (Store, error) { 54 is := &store{ 55 lss: lss, 56 images: make(map[ID]*imageMeta), 57 fs: fs, 58 digestSet: digestset.NewSet(), 59 } 60 61 // load all current images and retain layers 62 if err := is.restore(); err != nil { 63 return nil, err 64 } 65 66 return is, nil 67 } 68 69 func (is *store) restore() error { 70 err := is.fs.Walk(func(dgst digest.Digest) error { 71 img, err := is.Get(IDFromDigest(dgst)) 72 if err != nil { 73 logrus.Errorf("invalid image %v, %v", dgst, err) 74 return nil 75 } 76 var l layer.Layer 77 if chainID := img.RootFS.ChainID(); chainID != "" { 78 if !system.IsOSSupported(img.OperatingSystem()) { 79 logrus.Errorf("not restoring image with unsupported operating system %v, %v, %s", dgst, chainID, img.OperatingSystem()) 80 return nil 81 } 82 l, err = is.lss[img.OperatingSystem()].Get(chainID) 83 if err != nil { 84 if err == layer.ErrLayerDoesNotExist { 85 logrus.Errorf("layer does not exist, not restoring image %v, %v, %s", dgst, chainID, img.OperatingSystem()) 86 return nil 87 } 88 return err 89 } 90 } 91 if err := is.digestSet.Add(dgst); err != nil { 92 return err 93 } 94 95 imageMeta := &imageMeta{ 96 layer: l, 97 children: make(map[ID]struct{}), 98 } 99 100 is.images[IDFromDigest(dgst)] = imageMeta 101 102 return nil 103 }) 104 if err != nil { 105 return err 106 } 107 108 // Second pass to fill in children maps 109 for id := range is.images { 110 if parent, err := is.GetParent(id); err == nil { 111 if parentMeta := is.images[parent]; parentMeta != nil { 112 parentMeta.children[id] = struct{}{} 113 } 114 } 115 } 116 117 return nil 118 } 119 120 func (is *store) Create(config []byte) (ID, error) { 121 var img Image 122 err := json.Unmarshal(config, &img) 123 if err != nil { 124 return "", err 125 } 126 127 // Must reject any config that references diffIDs from the history 128 // which aren't among the rootfs layers. 129 rootFSLayers := make(map[layer.DiffID]struct{}) 130 for _, diffID := range img.RootFS.DiffIDs { 131 rootFSLayers[diffID] = struct{}{} 132 } 133 134 layerCounter := 0 135 for _, h := range img.History { 136 if !h.EmptyLayer { 137 layerCounter++ 138 } 139 } 140 if layerCounter > len(img.RootFS.DiffIDs) { 141 return "", errors.New("too many non-empty layers in History section") 142 } 143 144 dgst, err := is.fs.Set(config) 145 if err != nil { 146 return "", err 147 } 148 imageID := IDFromDigest(dgst) 149 150 is.Lock() 151 defer is.Unlock() 152 153 if _, exists := is.images[imageID]; exists { 154 return imageID, nil 155 } 156 157 layerID := img.RootFS.ChainID() 158 159 var l layer.Layer 160 if layerID != "" { 161 if !system.IsOSSupported(img.OperatingSystem()) { 162 return "", system.ErrNotSupportedOperatingSystem 163 } 164 l, err = is.lss[img.OperatingSystem()].Get(layerID) 165 if err != nil { 166 return "", errors.Wrapf(err, "failed to get layer %s", layerID) 167 } 168 } 169 170 imageMeta := &imageMeta{ 171 layer: l, 172 children: make(map[ID]struct{}), 173 } 174 175 is.images[imageID] = imageMeta 176 if err := is.digestSet.Add(imageID.Digest()); err != nil { 177 delete(is.images, imageID) 178 return "", err 179 } 180 181 return imageID, nil 182 } 183 184 type imageNotFoundError string 185 186 func (e imageNotFoundError) Error() string { 187 return "No such image: " + string(e) 188 } 189 190 func (imageNotFoundError) NotFound() {} 191 192 func (is *store) Search(term string) (ID, error) { 193 dgst, err := is.digestSet.Lookup(term) 194 if err != nil { 195 if err == digestset.ErrDigestNotFound { 196 err = imageNotFoundError(term) 197 } 198 return "", errors.WithStack(err) 199 } 200 return IDFromDigest(dgst), nil 201 } 202 203 func (is *store) Get(id ID) (*Image, error) { 204 // todo: Check if image is in images 205 // todo: Detect manual insertions and start using them 206 config, err := is.fs.Get(id.Digest()) 207 if err != nil { 208 return nil, err 209 } 210 211 img, err := NewFromJSON(config) 212 if err != nil { 213 return nil, err 214 } 215 img.computedID = id 216 217 img.Parent, err = is.GetParent(id) 218 if err != nil { 219 img.Parent = "" 220 } 221 222 return img, nil 223 } 224 225 func (is *store) Delete(id ID) ([]layer.Metadata, error) { 226 is.Lock() 227 defer is.Unlock() 228 229 imageMeta := is.images[id] 230 if imageMeta == nil { 231 return nil, fmt.Errorf("unrecognized image ID %s", id.String()) 232 } 233 img, err := is.Get(id) 234 if err != nil { 235 return nil, fmt.Errorf("unrecognized image %s, %v", id.String(), err) 236 } 237 if !system.IsOSSupported(img.OperatingSystem()) { 238 return nil, fmt.Errorf("unsupported image operating system %q", img.OperatingSystem()) 239 } 240 for id := range imageMeta.children { 241 is.fs.DeleteMetadata(id.Digest(), "parent") 242 } 243 if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil { 244 delete(is.images[parent].children, id) 245 } 246 247 if err := is.digestSet.Remove(id.Digest()); err != nil { 248 logrus.Errorf("error removing %s from digest set: %q", id, err) 249 } 250 delete(is.images, id) 251 is.fs.Delete(id.Digest()) 252 253 if imageMeta.layer != nil { 254 return is.lss[img.OperatingSystem()].Release(imageMeta.layer) 255 } 256 return nil, nil 257 } 258 259 func (is *store) SetParent(id, parent ID) error { 260 is.Lock() 261 defer is.Unlock() 262 parentMeta := is.images[parent] 263 if parentMeta == nil { 264 return fmt.Errorf("unknown parent image ID %s", parent.String()) 265 } 266 if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil { 267 delete(is.images[parent].children, id) 268 } 269 parentMeta.children[id] = struct{}{} 270 return is.fs.SetMetadata(id.Digest(), "parent", []byte(parent)) 271 } 272 273 func (is *store) GetParent(id ID) (ID, error) { 274 d, err := is.fs.GetMetadata(id.Digest(), "parent") 275 if err != nil { 276 return "", err 277 } 278 return ID(d), nil // todo: validate? 279 } 280 281 // SetLastUpdated time for the image ID to the current time 282 func (is *store) SetLastUpdated(id ID) error { 283 lastUpdated := []byte(time.Now().Format(time.RFC3339Nano)) 284 return is.fs.SetMetadata(id.Digest(), "lastUpdated", lastUpdated) 285 } 286 287 // GetLastUpdated time for the image ID 288 func (is *store) GetLastUpdated(id ID) (time.Time, error) { 289 bytes, err := is.fs.GetMetadata(id.Digest(), "lastUpdated") 290 if err != nil || len(bytes) == 0 { 291 // No lastUpdated time 292 return time.Time{}, nil 293 } 294 return time.Parse(time.RFC3339Nano, string(bytes)) 295 } 296 297 func (is *store) Children(id ID) []ID { 298 is.RLock() 299 defer is.RUnlock() 300 301 return is.children(id) 302 } 303 304 func (is *store) children(id ID) []ID { 305 var ids []ID 306 if is.images[id] != nil { 307 for id := range is.images[id].children { 308 ids = append(ids, id) 309 } 310 } 311 return ids 312 } 313 314 func (is *store) Heads() map[ID]*Image { 315 return is.imagesMap(false) 316 } 317 318 func (is *store) Map() map[ID]*Image { 319 return is.imagesMap(true) 320 } 321 322 func (is *store) imagesMap(all bool) map[ID]*Image { 323 is.RLock() 324 defer is.RUnlock() 325 326 images := make(map[ID]*Image) 327 328 for id := range is.images { 329 if !all && len(is.children(id)) > 0 { 330 continue 331 } 332 img, err := is.Get(id) 333 if err != nil { 334 logrus.Errorf("invalid image access: %q, error: %q", id, err) 335 continue 336 } 337 images[id] = img 338 } 339 return images 340 } 341 342 func (is *store) Len() int { 343 is.RLock() 344 defer is.RUnlock() 345 return len(is.images) 346 }