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