github.com/kaisenlinux/docker.io@v0.0.0-20230510090727-ea55db55fac7/engine/daemon/images/images.go (about) 1 package images // import "github.com/docker/docker/daemon/images" 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "sort" 7 "time" 8 9 "github.com/pkg/errors" 10 11 "github.com/docker/distribution/reference" 12 "github.com/docker/docker/api/types" 13 "github.com/docker/docker/api/types/filters" 14 "github.com/docker/docker/container" 15 "github.com/docker/docker/image" 16 "github.com/docker/docker/layer" 17 "github.com/docker/docker/pkg/system" 18 ) 19 20 var acceptedImageFilterTags = map[string]bool{ 21 "dangling": true, 22 "label": true, 23 "before": true, 24 "since": true, 25 "reference": true, 26 } 27 28 // byCreated is a temporary type used to sort a list of images by creation 29 // time. 30 type byCreated []*types.ImageSummary 31 32 func (r byCreated) Len() int { return len(r) } 33 func (r byCreated) Swap(i, j int) { r[i], r[j] = r[j], r[i] } 34 func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created } 35 36 // Map returns a map of all images in the ImageStore 37 func (i *ImageService) Map() map[image.ID]*image.Image { 38 return i.imageStore.Map() 39 } 40 41 // Images returns a filtered list of images. filterArgs is a JSON-encoded set 42 // of filter arguments which will be interpreted by api/types/filters. 43 // filter is a shell glob string applied to repository names. The argument 44 // named all controls whether all images in the graph are filtered, or just 45 // the heads. 46 func (i *ImageService) Images(imageFilters filters.Args, all bool, withExtraAttrs bool) ([]*types.ImageSummary, error) { 47 var ( 48 allImages map[image.ID]*image.Image 49 err error 50 danglingOnly = false 51 ) 52 53 if err := imageFilters.Validate(acceptedImageFilterTags); err != nil { 54 return nil, err 55 } 56 57 if imageFilters.Contains("dangling") { 58 if imageFilters.ExactMatch("dangling", "true") { 59 danglingOnly = true 60 } else if !imageFilters.ExactMatch("dangling", "false") { 61 return nil, invalidFilter{"dangling", imageFilters.Get("dangling")} 62 } 63 } 64 if danglingOnly { 65 allImages = i.imageStore.Heads() 66 } else { 67 allImages = i.imageStore.Map() 68 } 69 70 var beforeFilter, sinceFilter *image.Image 71 err = imageFilters.WalkValues("before", func(value string) error { 72 beforeFilter, err = i.GetImage(value, nil) 73 return err 74 }) 75 if err != nil { 76 return nil, err 77 } 78 79 err = imageFilters.WalkValues("since", func(value string) error { 80 sinceFilter, err = i.GetImage(value, nil) 81 return err 82 }) 83 if err != nil { 84 return nil, err 85 } 86 87 images := []*types.ImageSummary{} 88 var imagesMap map[*image.Image]*types.ImageSummary 89 var layerRefs map[layer.ChainID]int 90 var allLayers map[layer.ChainID]layer.Layer 91 var allContainers []*container.Container 92 93 for id, img := range allImages { 94 if beforeFilter != nil { 95 if img.Created.Equal(beforeFilter.Created) || img.Created.After(beforeFilter.Created) { 96 continue 97 } 98 } 99 100 if sinceFilter != nil { 101 if img.Created.Equal(sinceFilter.Created) || img.Created.Before(sinceFilter.Created) { 102 continue 103 } 104 } 105 106 if imageFilters.Contains("label") { 107 // Very old image that do not have image.Config (or even labels) 108 if img.Config == nil { 109 continue 110 } 111 // We are now sure image.Config is not nil 112 if !imageFilters.MatchKVList("label", img.Config.Labels) { 113 continue 114 } 115 } 116 117 // Skip any images with an unsupported operating system to avoid a potential 118 // panic when indexing through the layerstore. Don't error as we want to list 119 // the other images. This should never happen, but here as a safety precaution. 120 if !system.IsOSSupported(img.OperatingSystem()) { 121 continue 122 } 123 124 layerID := img.RootFS.ChainID() 125 var size int64 126 if layerID != "" { 127 l, err := i.layerStores[img.OperatingSystem()].Get(layerID) 128 if err != nil { 129 // The layer may have been deleted between the call to `Map()` or 130 // `Heads()` and the call to `Get()`, so we just ignore this error 131 if err == layer.ErrLayerDoesNotExist { 132 continue 133 } 134 return nil, err 135 } 136 137 size, err = l.Size() 138 layer.ReleaseAndLog(i.layerStores[img.OperatingSystem()], l) 139 if err != nil { 140 return nil, err 141 } 142 } 143 144 newImage := newImage(img, size) 145 146 for _, ref := range i.referenceStore.References(id.Digest()) { 147 if imageFilters.Contains("reference") { 148 var found bool 149 var matchErr error 150 for _, pattern := range imageFilters.Get("reference") { 151 found, matchErr = reference.FamiliarMatch(pattern, ref) 152 if matchErr != nil { 153 return nil, matchErr 154 } 155 if found { 156 break 157 } 158 } 159 if !found { 160 continue 161 } 162 } 163 if _, ok := ref.(reference.Canonical); ok { 164 newImage.RepoDigests = append(newImage.RepoDigests, reference.FamiliarString(ref)) 165 } 166 if _, ok := ref.(reference.NamedTagged); ok { 167 newImage.RepoTags = append(newImage.RepoTags, reference.FamiliarString(ref)) 168 } 169 } 170 if newImage.RepoDigests == nil && newImage.RepoTags == nil { 171 if all || len(i.imageStore.Children(id)) == 0 { 172 173 if imageFilters.Contains("dangling") && !danglingOnly { 174 // dangling=false case, so dangling image is not needed 175 continue 176 } 177 if imageFilters.Contains("reference") { // skip images with no references if filtering by reference 178 continue 179 } 180 newImage.RepoDigests = []string{"<none>@<none>"} 181 newImage.RepoTags = []string{"<none>:<none>"} 182 } else { 183 continue 184 } 185 } else if danglingOnly && len(newImage.RepoTags) > 0 { 186 continue 187 } 188 189 if withExtraAttrs { 190 // lazily init variables 191 if imagesMap == nil { 192 allContainers = i.containers.List() 193 194 // allLayers is built from all layerstores combined 195 allLayers = make(map[layer.ChainID]layer.Layer) 196 for _, ls := range i.layerStores { 197 layers := ls.Map() 198 for k, v := range layers { 199 allLayers[k] = v 200 } 201 } 202 imagesMap = make(map[*image.Image]*types.ImageSummary) 203 layerRefs = make(map[layer.ChainID]int) 204 } 205 206 // Get container count 207 newImage.Containers = 0 208 for _, c := range allContainers { 209 if c.ImageID == id { 210 newImage.Containers++ 211 } 212 } 213 214 // count layer references 215 rootFS := *img.RootFS 216 rootFS.DiffIDs = nil 217 for _, id := range img.RootFS.DiffIDs { 218 rootFS.Append(id) 219 chid := rootFS.ChainID() 220 layerRefs[chid]++ 221 if _, ok := allLayers[chid]; !ok { 222 return nil, fmt.Errorf("layer %v was not found (corruption?)", chid) 223 } 224 } 225 imagesMap[img] = newImage 226 } 227 228 images = append(images, newImage) 229 } 230 231 if withExtraAttrs { 232 // Get Shared sizes 233 for img, newImage := range imagesMap { 234 rootFS := *img.RootFS 235 rootFS.DiffIDs = nil 236 237 newImage.SharedSize = 0 238 for _, id := range img.RootFS.DiffIDs { 239 rootFS.Append(id) 240 chid := rootFS.ChainID() 241 242 diffSize, err := allLayers[chid].DiffSize() 243 if err != nil { 244 return nil, err 245 } 246 247 if layerRefs[chid] > 1 { 248 newImage.SharedSize += diffSize 249 } 250 } 251 } 252 } 253 254 sort.Sort(sort.Reverse(byCreated(images))) 255 256 return images, nil 257 } 258 259 // SquashImage creates a new image with the diff of the specified image and the specified parent. 260 // This new image contains only the layers from it's parent + 1 extra layer which contains the diff of all the layers in between. 261 // The existing image(s) is not destroyed. 262 // If no parent is specified, a new image with the diff of all the specified image's layers merged into a new layer that has no parents. 263 func (i *ImageService) SquashImage(id, parent string) (string, error) { 264 265 var ( 266 img *image.Image 267 err error 268 ) 269 if img, err = i.imageStore.Get(image.ID(id)); err != nil { 270 return "", err 271 } 272 273 var parentImg *image.Image 274 var parentChainID layer.ChainID 275 if len(parent) != 0 { 276 parentImg, err = i.imageStore.Get(image.ID(parent)) 277 if err != nil { 278 return "", errors.Wrap(err, "error getting specified parent layer") 279 } 280 parentChainID = parentImg.RootFS.ChainID() 281 } else { 282 rootFS := image.NewRootFS() 283 parentImg = &image.Image{RootFS: rootFS} 284 } 285 if !system.IsOSSupported(img.OperatingSystem()) { 286 return "", errors.Wrap(err, system.ErrNotSupportedOperatingSystem.Error()) 287 } 288 l, err := i.layerStores[img.OperatingSystem()].Get(img.RootFS.ChainID()) 289 if err != nil { 290 return "", errors.Wrap(err, "error getting image layer") 291 } 292 defer i.layerStores[img.OperatingSystem()].Release(l) 293 294 ts, err := l.TarStreamFrom(parentChainID) 295 if err != nil { 296 return "", errors.Wrapf(err, "error getting tar stream to parent") 297 } 298 defer ts.Close() 299 300 newL, err := i.layerStores[img.OperatingSystem()].Register(ts, parentChainID) 301 if err != nil { 302 return "", errors.Wrap(err, "error registering layer") 303 } 304 defer i.layerStores[img.OperatingSystem()].Release(newL) 305 306 newImage := *img 307 newImage.RootFS = nil 308 309 rootFS := *parentImg.RootFS 310 rootFS.DiffIDs = append(rootFS.DiffIDs, newL.DiffID()) 311 newImage.RootFS = &rootFS 312 313 for i, hi := range newImage.History { 314 if i >= len(parentImg.History) { 315 hi.EmptyLayer = true 316 } 317 newImage.History[i] = hi 318 } 319 320 now := time.Now() 321 var historyComment string 322 if len(parent) > 0 { 323 historyComment = fmt.Sprintf("merge %s to %s", id, parent) 324 } else { 325 historyComment = fmt.Sprintf("create new from %s", id) 326 } 327 328 newImage.History = append(newImage.History, image.History{ 329 Created: now, 330 Comment: historyComment, 331 }) 332 newImage.Created = now 333 334 b, err := json.Marshal(&newImage) 335 if err != nil { 336 return "", errors.Wrap(err, "error marshalling image config") 337 } 338 339 newImgID, err := i.imageStore.Create(b) 340 if err != nil { 341 return "", errors.Wrap(err, "error creating new image after squash") 342 } 343 return string(newImgID), nil 344 } 345 346 func newImage(image *image.Image, size int64) *types.ImageSummary { 347 newImage := new(types.ImageSummary) 348 newImage.ParentID = image.Parent.String() 349 newImage.ID = image.ID().String() 350 newImage.Created = image.Created.Unix() 351 newImage.Size = size 352 newImage.VirtualSize = size 353 newImage.SharedSize = -1 354 newImage.Containers = -1 355 if image.Config != nil { 356 newImage.Labels = image.Config.Labels 357 } 358 return newImage 359 }