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