github.com/rhatdan/docker@v0.7.7-0.20180119204836-47a0dcbcd20a/image/store.go (about) 1 package 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 "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 } 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 return system.ErrNotSupportedOperatingSystem 79 } 80 l, err = is.lss[img.OperatingSystem()].Get(chainID) 81 if err != nil { 82 return err 83 } 84 } 85 if err := is.digestSet.Add(dgst); err != nil { 86 return err 87 } 88 89 imageMeta := &imageMeta{ 90 layer: l, 91 children: make(map[ID]struct{}), 92 } 93 94 is.images[IDFromDigest(dgst)] = imageMeta 95 96 return nil 97 }) 98 if err != nil { 99 return err 100 } 101 102 // Second pass to fill in children maps 103 for id := range is.images { 104 if parent, err := is.GetParent(id); err == nil { 105 if parentMeta := is.images[parent]; parentMeta != nil { 106 parentMeta.children[id] = struct{}{} 107 } 108 } 109 } 110 111 return nil 112 } 113 114 func (is *store) Create(config []byte) (ID, error) { 115 var img Image 116 err := json.Unmarshal(config, &img) 117 if err != nil { 118 return "", err 119 } 120 121 // Must reject any config that references diffIDs from the history 122 // which aren't among the rootfs layers. 123 rootFSLayers := make(map[layer.DiffID]struct{}) 124 for _, diffID := range img.RootFS.DiffIDs { 125 rootFSLayers[diffID] = struct{}{} 126 } 127 128 layerCounter := 0 129 for _, h := range img.History { 130 if !h.EmptyLayer { 131 layerCounter++ 132 } 133 } 134 if layerCounter > len(img.RootFS.DiffIDs) { 135 return "", errors.New("too many non-empty layers in History section") 136 } 137 138 dgst, err := is.fs.Set(config) 139 if err != nil { 140 return "", err 141 } 142 imageID := IDFromDigest(dgst) 143 144 is.Lock() 145 defer is.Unlock() 146 147 if _, exists := is.images[imageID]; exists { 148 return imageID, nil 149 } 150 151 layerID := img.RootFS.ChainID() 152 153 var l layer.Layer 154 if layerID != "" { 155 if !system.IsOSSupported(img.OperatingSystem()) { 156 return "", system.ErrNotSupportedOperatingSystem 157 } 158 l, err = is.lss[img.OperatingSystem()].Get(layerID) 159 if err != nil { 160 return "", errors.Wrapf(err, "failed to get layer %s", layerID) 161 } 162 } 163 164 imageMeta := &imageMeta{ 165 layer: l, 166 children: make(map[ID]struct{}), 167 } 168 169 is.images[imageID] = imageMeta 170 if err := is.digestSet.Add(imageID.Digest()); err != nil { 171 delete(is.images, imageID) 172 return "", err 173 } 174 175 return imageID, nil 176 } 177 178 type imageNotFoundError string 179 180 func (e imageNotFoundError) Error() string { 181 return "No such image: " + string(e) 182 } 183 184 func (imageNotFoundError) NotFound() {} 185 186 func (is *store) Search(term string) (ID, error) { 187 dgst, err := is.digestSet.Lookup(term) 188 if err != nil { 189 if err == digestset.ErrDigestNotFound { 190 err = imageNotFoundError(term) 191 } 192 return "", errors.WithStack(err) 193 } 194 return IDFromDigest(dgst), nil 195 } 196 197 func (is *store) Get(id ID) (*Image, error) { 198 // todo: Check if image is in images 199 // todo: Detect manual insertions and start using them 200 config, err := is.fs.Get(id.Digest()) 201 if err != nil { 202 return nil, err 203 } 204 205 img, err := NewFromJSON(config) 206 if err != nil { 207 return nil, err 208 } 209 img.computedID = id 210 211 img.Parent, err = is.GetParent(id) 212 if err != nil { 213 img.Parent = "" 214 } 215 216 return img, nil 217 } 218 219 func (is *store) Delete(id ID) ([]layer.Metadata, error) { 220 is.Lock() 221 defer is.Unlock() 222 223 imageMeta := is.images[id] 224 if imageMeta == nil { 225 return nil, fmt.Errorf("unrecognized image ID %s", id.String()) 226 } 227 img, err := is.Get(id) 228 if err != nil { 229 return nil, fmt.Errorf("unrecognized image %s, %v", id.String(), err) 230 } 231 if !system.IsOSSupported(img.OperatingSystem()) { 232 return nil, fmt.Errorf("unsupported image operating system %q", img.OperatingSystem()) 233 } 234 for id := range imageMeta.children { 235 is.fs.DeleteMetadata(id.Digest(), "parent") 236 } 237 if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil { 238 delete(is.images[parent].children, id) 239 } 240 241 if err := is.digestSet.Remove(id.Digest()); err != nil { 242 logrus.Errorf("error removing %s from digest set: %q", id, err) 243 } 244 delete(is.images, id) 245 is.fs.Delete(id.Digest()) 246 247 if imageMeta.layer != nil { 248 return is.lss[img.OperatingSystem()].Release(imageMeta.layer) 249 } 250 return nil, nil 251 } 252 253 func (is *store) SetParent(id, parent ID) error { 254 is.Lock() 255 defer is.Unlock() 256 parentMeta := is.images[parent] 257 if parentMeta == nil { 258 return fmt.Errorf("unknown parent image ID %s", parent.String()) 259 } 260 if parent, err := is.GetParent(id); err == nil && is.images[parent] != nil { 261 delete(is.images[parent].children, id) 262 } 263 parentMeta.children[id] = struct{}{} 264 return is.fs.SetMetadata(id.Digest(), "parent", []byte(parent)) 265 } 266 267 func (is *store) GetParent(id ID) (ID, error) { 268 d, err := is.fs.GetMetadata(id.Digest(), "parent") 269 if err != nil { 270 return "", err 271 } 272 return ID(d), nil // todo: validate? 273 } 274 275 // SetLastUpdated time for the image ID to the current time 276 func (is *store) SetLastUpdated(id ID) error { 277 lastUpdated := []byte(time.Now().Format(time.RFC3339Nano)) 278 return is.fs.SetMetadata(id.Digest(), "lastUpdated", lastUpdated) 279 } 280 281 // GetLastUpdated time for the image ID 282 func (is *store) GetLastUpdated(id ID) (time.Time, error) { 283 bytes, err := is.fs.GetMetadata(id.Digest(), "lastUpdated") 284 if err != nil || len(bytes) == 0 { 285 // No lastUpdated time 286 return time.Time{}, nil 287 } 288 return time.Parse(time.RFC3339Nano, string(bytes)) 289 } 290 291 func (is *store) Children(id ID) []ID { 292 is.RLock() 293 defer is.RUnlock() 294 295 return is.children(id) 296 } 297 298 func (is *store) children(id ID) []ID { 299 var ids []ID 300 if is.images[id] != nil { 301 for id := range is.images[id].children { 302 ids = append(ids, id) 303 } 304 } 305 return ids 306 } 307 308 func (is *store) Heads() map[ID]*Image { 309 return is.imagesMap(false) 310 } 311 312 func (is *store) Map() map[ID]*Image { 313 return is.imagesMap(true) 314 } 315 316 func (is *store) imagesMap(all bool) map[ID]*Image { 317 is.RLock() 318 defer is.RUnlock() 319 320 images := make(map[ID]*Image) 321 322 for id := range is.images { 323 if !all && len(is.children(id)) > 0 { 324 continue 325 } 326 img, err := is.Get(id) 327 if err != nil { 328 logrus.Errorf("invalid image access: %q, error: %q", id, err) 329 continue 330 } 331 images[id] = img 332 } 333 return images 334 }