Browse code

api/image/list: Return `Containers` count

This parameter was already supported for some time in the backend (for
purposes related to docker system prune). It was also already present in
the imagetypes.ListOptions but was never actually handled by the client.

Make it available by default in the response.

Signed-off-by: Paweł Gronowski <pawel.gronowski@docker.com>

Paweł Gronowski authored on 2024/03/06 01:26:27
Showing 7 changed files
... ...
@@ -459,6 +459,7 @@ func (ir *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
459 459
 	useNone := versions.LessThan(version, "1.43")
460 460
 	withVirtualSize := versions.LessThan(version, "1.44")
461 461
 	noDescriptor := versions.LessThan(version, "1.48")
462
+	noContainers := versions.LessThan(version, "1.51")
462 463
 	for _, img := range images {
463 464
 		if useNone {
464 465
 			if len(img.RepoTags) == 0 && len(img.RepoDigests) == 0 {
... ...
@@ -479,6 +480,9 @@ func (ir *imageRouter) getImagesJSON(ctx context.Context, w http.ResponseWriter,
479 479
 		if noDescriptor {
480 480
 			img.Descriptor = nil
481 481
 		}
482
+		if noContainers {
483
+			img.Containers = -1
484
+		}
482 485
 	}
483 486
 
484 487
 	return httputils.WriteJSON(w, http.StatusOK, images)
... ...
@@ -2196,8 +2196,7 @@ definitions:
2196 2196
           Number of containers using this image. Includes both stopped and running
2197 2197
           containers.
2198 2198
 
2199
-          This size is not calculated by default, and depends on which API endpoint
2200
-          is used. `-1` indicates that the value has not been set / calculated.
2199
+          `-1` indicates that the value has not been set / calculated.
2201 2200
         x-nullable: false
2202 2201
         type: "integer"
2203 2202
         example: 2
... ...
@@ -75,6 +75,8 @@ type ListOptions struct {
75 75
 	SharedSize bool
76 76
 
77 77
 	// ContainerCount indicates whether container count should be computed.
78
+	//
79
+	// Deprecated: This field has been unused and is no longer required and will be removed in a future version.
78 80
 	ContainerCount bool
79 81
 
80 82
 	// Manifests indicates whether the image manifests should be returned.
... ...
@@ -409,10 +409,7 @@ func (i *ImageService) imageSummary(ctx context.Context, img c8dimages.Image, pl
409 409
 	image.Manifests = summary.Manifests
410 410
 	target := img.Target
411 411
 	image.Descriptor = &target
412
-
413
-	if opts.ContainerCount {
414
-		image.Containers = summary.ContainersCount
415
-	}
412
+	image.Containers = summary.ContainersCount
416 413
 	return image, summary, nil
417 414
 }
418 415
 
... ...
@@ -57,9 +57,8 @@ func (daemon *Daemon) imageDiskUsage(ctx context.Context) ([]*image.Summary, err
57 57
 	imgs, _, err := daemon.usageImages.Do(ctx, struct{}{}, func(ctx context.Context) ([]*image.Summary, error) {
58 58
 		// Get all top images with extra attributes
59 59
 		imgs, err := daemon.imageService.Images(ctx, image.ListOptions{
60
-			Filters:        filters.NewArgs(),
61
-			SharedSize:     true,
62
-			ContainerCount: true,
60
+			Filters:    filters.NewArgs(),
61
+			SharedSize: true,
63 62
 		})
64 63
 		if err != nil {
65 64
 			return nil, errors.Wrap(err, "failed to retrieve image list")
... ...
@@ -105,7 +105,7 @@ func (i *ImageService) Images(ctx context.Context, opts imagetypes.ListOptions)
105 105
 
106 106
 	var (
107 107
 		summaries     = make([]*imagetypes.Summary, 0, len(selectedImages))
108
-		summaryMap    map[*image.Image]*imagetypes.Summary
108
+		summaryMap    = make(map[*image.Image]*imagetypes.Summary, len(selectedImages))
109 109
 		allContainers []*container.Container
110 110
 	)
111 111
 	for id, img := range selectedImages {
... ...
@@ -198,30 +198,20 @@ func (i *ImageService) Images(ctx context.Context, opts imagetypes.ListOptions)
198 198
 			continue
199 199
 		}
200 200
 
201
-		if opts.ContainerCount {
202
-			// Lazily init allContainers.
203
-			if allContainers == nil {
204
-				allContainers = i.containers.List()
205
-			}
206
-
207
-			// Get container count
208
-			var containers int64
209
-			for _, c := range allContainers {
210
-				if c.ImageID == id {
211
-					containers++
212
-				}
213
-			}
214
-			// NOTE: By default, Containers is -1, or "not set"
215
-			summary.Containers = containers
201
+		// Lazily init allContainers.
202
+		if allContainers == nil {
203
+			allContainers = i.containers.List()
216 204
 		}
217 205
 
218
-		if opts.ContainerCount || opts.SharedSize {
219
-			// Lazily init summaryMap.
220
-			if summaryMap == nil {
221
-				summaryMap = make(map[*image.Image]*imagetypes.Summary, len(selectedImages))
206
+		// Get container count
207
+		var containersCount int64
208
+		for _, c := range allContainers {
209
+			if c.ImageID == id {
210
+				containersCount++
222 211
 			}
223
-			summaryMap[img] = summary
224 212
 		}
213
+		summary.Containers = containersCount
214
+		summaryMap[img] = summary
225 215
 		summaries = append(summaries, summary)
226 216
 	}
227 217
 
... ...
@@ -17,6 +17,9 @@ keywords: "API, Docker, rcli, REST, documentation"
17 17
 
18 18
 [Docker Engine API v1.51](https://docs.docker.com/reference/api/engine/version/v1.51/) documentation
19 19
 
20
+* `GET /images/json` now sets the value of `Containers` field for all images
21
+  to the count of containers using the image.
22
+  This field was previously always -1.
20 23
 
21 24
 ## v1.50 API changes
22 25