github.com/rawahars/moby@v24.0.4+incompatible/daemon/images/image_list.go (about) 1 package images // import "github.com/docker/docker/daemon/images" 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "sort" 8 "time" 9 10 "github.com/docker/distribution/reference" 11 "github.com/docker/docker/api/types" 12 imagetypes "github.com/docker/docker/api/types/image" 13 "github.com/docker/docker/container" 14 "github.com/docker/docker/image" 15 "github.com/docker/docker/layer" 16 "github.com/docker/docker/pkg/system" 17 ) 18 19 var acceptedImageFilterTags = map[string]bool{ 20 "dangling": true, 21 "label": true, 22 "before": true, 23 "since": true, 24 "reference": true, 25 } 26 27 // byCreated is a temporary type used to sort a list of images by creation 28 // time. 29 type byCreated []*types.ImageSummary 30 31 func (r byCreated) Len() int { return len(r) } 32 func (r byCreated) Swap(i, j int) { r[i], r[j] = r[j], r[i] } 33 func (r byCreated) Less(i, j int) bool { return r[i].Created < r[j].Created } 34 35 // Images returns a filtered list of images. 36 func (i *ImageService) Images(ctx context.Context, opts types.ImageListOptions) ([]*types.ImageSummary, error) { 37 if err := opts.Filters.Validate(acceptedImageFilterTags); err != nil { 38 return nil, err 39 } 40 41 danglingOnly, err := opts.Filters.GetBoolOrDefault("dangling", false) 42 if err != nil { 43 return nil, err 44 } 45 46 var ( 47 beforeFilter, sinceFilter time.Time 48 ) 49 err = opts.Filters.WalkValues("before", func(value string) error { 50 img, err := i.GetImage(ctx, value, imagetypes.GetImageOpts{}) 51 if err != nil { 52 return err 53 } 54 // Resolve multiple values to the oldest image, 55 // equivalent to ANDing all the values together. 56 if beforeFilter.IsZero() || beforeFilter.After(img.Created) { 57 beforeFilter = img.Created 58 } 59 return nil 60 }) 61 if err != nil { 62 return nil, err 63 } 64 65 err = opts.Filters.WalkValues("since", func(value string) error { 66 img, err := i.GetImage(ctx, value, imagetypes.GetImageOpts{}) 67 if err != nil { 68 return err 69 } 70 // Resolve multiple values to the newest image, 71 // equivalent to ANDing all the values together. 72 if sinceFilter.Before(img.Created) { 73 sinceFilter = img.Created 74 } 75 return nil 76 }) 77 if err != nil { 78 return nil, err 79 } 80 81 var selectedImages map[image.ID]*image.Image 82 if danglingOnly { 83 selectedImages = i.imageStore.Heads() 84 } else { 85 selectedImages = i.imageStore.Map() 86 } 87 88 var ( 89 summaries = make([]*types.ImageSummary, 0, len(selectedImages)) 90 summaryMap map[*image.Image]*types.ImageSummary 91 allContainers []*container.Container 92 ) 93 for id, img := range selectedImages { 94 select { 95 case <-ctx.Done(): 96 return nil, ctx.Err() 97 default: 98 } 99 100 if !beforeFilter.IsZero() && !img.Created.Before(beforeFilter) { 101 continue 102 } 103 if !sinceFilter.IsZero() && !img.Created.After(sinceFilter) { 104 continue 105 } 106 107 if opts.Filters.Contains("label") { 108 // Very old image that do not have image.Config (or even labels) 109 if img.Config == nil { 110 continue 111 } 112 // We are now sure image.Config is not nil 113 if !opts.Filters.MatchKVList("label", img.Config.Labels) { 114 continue 115 } 116 } 117 118 // Skip any images with an unsupported operating system to avoid a potential 119 // panic when indexing through the layerstore. Don't error as we want to list 120 // the other images. This should never happen, but here as a safety precaution. 121 if !system.IsOSSupported(img.OperatingSystem()) { 122 continue 123 } 124 125 var size int64 126 if layerID := img.RootFS.ChainID(); layerID != "" { 127 l, err := i.layerStore.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 errors.Is(err, layer.ErrLayerDoesNotExist) { 132 continue 133 } 134 return nil, err 135 } 136 137 size = l.Size() 138 layer.ReleaseAndLog(i.layerStore, l) 139 } 140 141 summary := newImageSummary(img, size) 142 143 for _, ref := range i.referenceStore.References(id.Digest()) { 144 if opts.Filters.Contains("reference") { 145 var found bool 146 var matchErr error 147 for _, pattern := range opts.Filters.Get("reference") { 148 found, matchErr = reference.FamiliarMatch(pattern, ref) 149 if matchErr != nil { 150 return nil, matchErr 151 } 152 if found { 153 break 154 } 155 } 156 if !found { 157 continue 158 } 159 } 160 if _, ok := ref.(reference.Canonical); ok { 161 summary.RepoDigests = append(summary.RepoDigests, reference.FamiliarString(ref)) 162 } 163 if _, ok := ref.(reference.NamedTagged); ok { 164 summary.RepoTags = append(summary.RepoTags, reference.FamiliarString(ref)) 165 } 166 } 167 if summary.RepoDigests == nil && summary.RepoTags == nil { 168 if opts.All || len(i.imageStore.Children(id)) == 0 { 169 if opts.Filters.Contains("dangling") && !danglingOnly { 170 // dangling=false case, so dangling image is not needed 171 continue 172 } 173 if opts.Filters.Contains("reference") { // skip images with no references if filtering by reference 174 continue 175 } 176 } else { 177 continue 178 } 179 } else if danglingOnly && len(summary.RepoTags) > 0 { 180 continue 181 } 182 183 if opts.ContainerCount { 184 // Lazily init allContainers. 185 if allContainers == nil { 186 allContainers = i.containers.List() 187 } 188 189 // Get container count 190 var containers int64 191 for _, c := range allContainers { 192 if c.ImageID == id { 193 containers++ 194 } 195 } 196 // NOTE: By default, Containers is -1, or "not set" 197 summary.Containers = containers 198 } 199 200 if opts.ContainerCount || opts.SharedSize { 201 // Lazily init summaryMap. 202 if summaryMap == nil { 203 summaryMap = make(map[*image.Image]*types.ImageSummary, len(selectedImages)) 204 } 205 summaryMap[img] = summary 206 } 207 summaries = append(summaries, summary) 208 } 209 210 if opts.SharedSize { 211 allLayers := i.layerStore.Map() 212 layerRefs := make(map[layer.ChainID]int, len(allLayers)) 213 214 allImages := selectedImages 215 if danglingOnly { 216 // If danglingOnly is true, then selectedImages include only dangling images, 217 // but we need to consider all existing images to correctly perform reference counting. 218 // If danglingOnly is false, selectedImages (and, hence, allImages) is already equal to i.imageStore.Map() 219 // and we can avoid performing an otherwise redundant method call. 220 allImages = i.imageStore.Map() 221 } 222 // Count layer references across all known images 223 for _, img := range allImages { 224 rootFS := *img.RootFS 225 rootFS.DiffIDs = nil 226 for _, id := range img.RootFS.DiffIDs { 227 rootFS.Append(id) 228 layerRefs[rootFS.ChainID()]++ 229 } 230 } 231 232 // Get Shared sizes 233 for img, summary := range summaryMap { 234 rootFS := *img.RootFS 235 rootFS.DiffIDs = nil 236 237 // Indicate that we collected shared size information (default is -1, or "not set") 238 summary.SharedSize = 0 239 for _, id := range img.RootFS.DiffIDs { 240 rootFS.Append(id) 241 chid := rootFS.ChainID() 242 243 if layerRefs[chid] > 1 { 244 if _, ok := allLayers[chid]; !ok { 245 return nil, fmt.Errorf("layer %v was not found (corruption?)", chid) 246 } 247 summary.SharedSize += allLayers[chid].DiffSize() 248 } 249 } 250 } 251 } 252 253 sort.Sort(sort.Reverse(byCreated(summaries))) 254 255 return summaries, nil 256 } 257 258 func newImageSummary(image *image.Image, size int64) *types.ImageSummary { 259 summary := &types.ImageSummary{ 260 ParentID: image.Parent.String(), 261 ID: image.ID().String(), 262 Created: image.Created.Unix(), 263 Size: size, 264 VirtualSize: size, //nolint:staticcheck // ignore SA1019: field is deprecated, but still set on API < v1.44. 265 // -1 indicates that the value has not been set (avoids ambiguity 266 // between 0 (default) and "not set". We cannot use a pointer (nil) 267 // for this, as the JSON representation uses "omitempty", which would 268 // consider both "0" and "nil" to be "empty". 269 SharedSize: -1, 270 Containers: -1, 271 } 272 if image.Config != nil { 273 summary.Labels = image.Config.Labels 274 } 275 return summary 276 }