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