Browse code

api/types/system: add type specific usage fields to `DiskUsage`

This change adds type specific fields to `GET /system/df` endpoint with high level information of disk usage. This change also introduces `verbose` query to the endpoint so that detailed information is by default excluded unless queried to reduce memory consumption. The previous top level `DiskUsage` fields (`Images`, `Containers`, `Volumes` and `BuildCache`) are now deprecated and kept for backwards compatibility.

Co-authored-by: Claude <noreply@anthropic.com>
Signed-off-by: Austin Vazquez <austin.vazquez@docker.com>

Austin Vazquez authored on 2025/10/21 05:11:53
Showing 27 changed files
... ...
@@ -71,6 +71,13 @@ keywords: "API, Docker, rcli, REST, documentation"
71 71
   part of the `Resource` requirements.
72 72
 * `GET /containers/{id}/stats` now returns an `os_type` field to allow platform-
73 73
   specific handling of the stats.
74
+* `GET /system/df` returns `ImagesUsage`, `ContainersUsage`, `VolumesUsage`, and
75
+  `BuildCacheUsage` fields with brief system disk usage data for each system object type.
76
+  The endpoint supports the `?verbose=1` query to return verbose system disk usage information.
77
+* Deprecated: `GET /system/df` response fields `LayersSize`, `Images`, `Containers`,
78
+  `Volumes`, and `BuildCache` are deprecated in favor of the type specific usage fields.
79
+  The legacy fields will not be populated for new API versions that specify the `verbose`
80
+  query.
74 81
 
75 82
 ## v1.51 API changes
76 83
 
... ...
@@ -2059,6 +2059,47 @@ definitions:
2059 2059
         x-nullable: true
2060 2060
         $ref: "#/definitions/OCIDescriptor"
2061 2061
 
2062
+  ImagesDiskUsage:
2063
+    type: "object"
2064
+    description: |
2065
+      ImagesDiskUsage represents system data usage for image resources.
2066
+    properties:
2067
+      ActiveImages:
2068
+        description: |
2069
+          Count of active images.
2070
+        type: "integer"
2071
+        format: "int64"
2072
+        example: 1
2073
+      TotalImages:
2074
+        description: |
2075
+          Count of all images.
2076
+        type: "integer"
2077
+        format: "int64"
2078
+        example: 4
2079
+      Reclaimable:
2080
+        description: |
2081
+          Disk space that can be reclaimed by removing unused images.
2082
+        type: "integer"
2083
+        format: "int64"
2084
+        example: 12345678
2085
+      TotalSize:
2086
+        description: |
2087
+          Disk space in use by images.
2088
+        type: "integer"
2089
+        format: "int64"
2090
+        example: 98765432
2091
+      Items:
2092
+        description: |
2093
+          List of image summaries.
2094
+        type: "array"
2095
+        x-omitempty: true
2096
+        items:
2097
+          x-nullable: true
2098
+          x-go-type:
2099
+            type: Summary
2100
+            import:
2101
+              package: github.com/moby/moby/api/types/image
2102
+
2062 2103
   AuthConfig:
2063 2104
     type: "object"
2064 2105
     properties:
... ...
@@ -2201,6 +2242,47 @@ definitions:
2201 2201
               is set to `-1` if the reference-count is not available.
2202 2202
             x-nullable: false
2203 2203
 
2204
+  VolumesDiskUsage:
2205
+    type: "object"
2206
+    description: |
2207
+      VolumesDiskUsage represents system data usage for volume resources.
2208
+    properties:
2209
+      ActiveVolumes:
2210
+        description: |
2211
+          Count of active volumes.
2212
+        type: "integer"
2213
+        format: "int64"
2214
+        example: 1
2215
+      TotalVolumes:
2216
+        description: |
2217
+          Count of all volumes.
2218
+        type: "integer"
2219
+        format: "int64"
2220
+        example: 4
2221
+      Reclaimable:
2222
+        description: |
2223
+          Disk space that can be reclaimed by removing inactive volumes.
2224
+        type: "integer"
2225
+        format: "int64"
2226
+        example: 12345678
2227
+      TotalSize:
2228
+        description: |
2229
+          Disk space in use by volumes.
2230
+        type: "integer"
2231
+        format: "int64"
2232
+        example: 98765432
2233
+      Items:
2234
+        description: |
2235
+          List of volumes.
2236
+        type: "array"
2237
+        x-omitempty: true
2238
+        items:
2239
+          x-nullable: true
2240
+          x-go-type:
2241
+            type: Volume
2242
+            import:
2243
+              package: github.com/moby/moby/api/types/volume
2244
+
2204 2245
   VolumeCreateRequest:
2205 2246
     description: "Volume configuration"
2206 2247
     type: "object"
... ...
@@ -2628,6 +2710,8 @@ definitions:
2628 2628
         type: "string"
2629 2629
         x-omitempty: false
2630 2630
         example: "02:42:ac:13:00:02"
2631
+        x-go-type:
2632
+          type: HardwareAddr
2631 2633
       IPv4Address:
2632 2634
         type: "string"
2633 2635
         x-omitempty: false
... ...
@@ -2772,6 +2856,47 @@ definitions:
2772 2772
         type: "integer"
2773 2773
         example: 26
2774 2774
 
2775
+  BuildCacheDiskUsage:
2776
+    type: "object"
2777
+    description: |
2778
+      BuildCacheDiskUsage represents system data usage for build cache resources.
2779
+    properties:
2780
+      ActiveBuildCacheRecords:
2781
+        description: |
2782
+          Count of active build cache records.
2783
+        type: "integer"
2784
+        format: "int64"
2785
+        example: 1
2786
+      TotalBuildCacheRecords:
2787
+        description: |
2788
+          Count of all build cache records.
2789
+        type: "integer"
2790
+        format: "int64"
2791
+        example: 4
2792
+      Reclaimable:
2793
+        description: |
2794
+          Disk space that can be reclaimed by removing inactive build cache records.
2795
+        type: "integer"
2796
+        format: "int64"
2797
+        example: 12345678
2798
+      TotalSize:
2799
+        description: |
2800
+          Disk space in use by build cache records.
2801
+        type: "integer"
2802
+        format: "int64"
2803
+        example: 98765432
2804
+      Items:
2805
+        description: |
2806
+          List of build cache records.
2807
+        type: "array"
2808
+        x-omitempty: true
2809
+        items:
2810
+          x-nullable: true
2811
+          x-go-type:
2812
+            type: CacheRecord
2813
+            import:
2814
+              package: github.com/moby/moby/api/types/build
2815
+
2775 2816
   ImageID:
2776 2817
     type: "object"
2777 2818
     description: "Image ID or Digest"
... ...
@@ -2914,6 +3039,8 @@ definitions:
2914 2914
           MAC address for the endpoint on this network. The network driver might ignore this parameter.
2915 2915
         type: "string"
2916 2916
         example: "02:42:ac:11:00:04"
2917
+        x-go-type:
2918
+          type: HardwareAddr
2917 2919
       Aliases:
2918 2920
         type: "array"
2919 2921
         items:
... ...
@@ -5453,6 +5580,47 @@ definitions:
5453 5453
             type: "integer"
5454 5454
             example: 0
5455 5455
 
5456
+  ContainersDiskUsage:
5457
+    type: "object"
5458
+    description: |
5459
+      ContainersDiskUsage provides system data usage information for container resources.
5460
+    properties:
5461
+      ActiveContainers:
5462
+        description: |
5463
+          Count of active containers.
5464
+        type: "integer"
5465
+        format: "int64"
5466
+        example: 1
5467
+      TotalContainers:
5468
+        description: |
5469
+          Count of all containers.
5470
+        type: "integer"
5471
+        format: "int64"
5472
+        example: 4
5473
+      Reclaimable:
5474
+        description: |
5475
+          Disk space that can be reclaimed by removing inactive containers.
5476
+        type: "integer"
5477
+        format: "int64"
5478
+        example: 12345678
5479
+      TotalSize:
5480
+        description: |
5481
+          Disk space in use by containers.
5482
+        type: "integer"
5483
+        format: "int64"
5484
+        example: 98765432
5485
+      Items:
5486
+        description: |
5487
+          List of container summaries.
5488
+        type: "array"
5489
+        x-omitempty: true
5490
+        items:
5491
+          x-nullable: true
5492
+          x-go-type:
5493
+            type: Summary
5494
+            import:
5495
+              package: github.com/moby/moby/api/types/container
5496
+
5456 5497
   Driver:
5457 5498
     description: "Driver represents a driver (network, logging, secrets)."
5458 5499
     type: "object"
... ...
@@ -10332,106 +10500,14 @@ paths:
10332 10332
             type: "object"
10333 10333
             title: "SystemDataUsageResponse"
10334 10334
             properties:
10335
-              LayersSize:
10336
-                type: "integer"
10337
-                format: "int64"
10338
-              Images:
10339
-                type: "array"
10340
-                items:
10341
-                  $ref: "#/definitions/ImageSummary"
10342
-              Containers:
10343
-                type: "array"
10344
-                items:
10345
-                  $ref: "#/definitions/ContainerSummary"
10346
-              Volumes:
10347
-                type: "array"
10348
-                items:
10349
-                  $ref: "#/definitions/Volume"
10350
-              BuildCache:
10351
-                type: "array"
10352
-                items:
10353
-                  $ref: "#/definitions/BuildCache"
10354
-            example:
10355
-              LayersSize: 1092588
10356
-              Images:
10357
-                -
10358
-                  Id: "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749"
10359
-                  ParentId: ""
10360
-                  RepoTags:
10361
-                    - "busybox:latest"
10362
-                  RepoDigests:
10363
-                    - "busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6"
10364
-                  Created: 1466724217
10365
-                  Size: 1092588
10366
-                  SharedSize: 0
10367
-                  Labels: {}
10368
-                  Containers: 1
10369
-              Containers:
10370
-                -
10371
-                  Id: "e575172ed11dc01bfce087fb27bee502db149e1a0fad7c296ad300bbff178148"
10372
-                  Names:
10373
-                    - "/top"
10374
-                  Image: "busybox"
10375
-                  ImageID: "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749"
10376
-                  Command: "top"
10377
-                  Created: 1472592424
10378
-                  Ports: []
10379
-                  SizeRootFs: 1092588
10380
-                  Labels: {}
10381
-                  State: "exited"
10382
-                  Status: "Exited (0) 56 minutes ago"
10383
-                  HostConfig:
10384
-                    NetworkMode: "default"
10385
-                  NetworkSettings:
10386
-                    Networks:
10387
-                      bridge:
10388
-                        IPAMConfig: null
10389
-                        Links: null
10390
-                        Aliases: null
10391
-                        NetworkID: "d687bc59335f0e5c9ee8193e5612e8aee000c8c62ea170cfb99c098f95899d92"
10392
-                        EndpointID: "8ed5115aeaad9abb174f68dcf135b49f11daf597678315231a32ca28441dec6a"
10393
-                        Gateway: "172.18.0.1"
10394
-                        IPAddress: "172.18.0.2"
10395
-                        IPPrefixLen: 16
10396
-                        IPv6Gateway: ""
10397
-                        GlobalIPv6Address: ""
10398
-                        GlobalIPv6PrefixLen: 0
10399
-                        MacAddress: "02:42:ac:12:00:02"
10400
-                  Mounts: []
10401
-              Volumes:
10402
-                -
10403
-                  Name: "my-volume"
10404
-                  Driver: "local"
10405
-                  Mountpoint: "/var/lib/docker/volumes/my-volume/_data"
10406
-                  Labels: null
10407
-                  Scope: "local"
10408
-                  Options: null
10409
-                  UsageData:
10410
-                    Size: 10920104
10411
-                    RefCount: 2
10412
-              BuildCache:
10413
-                -
10414
-                  ID: "hw53o5aio51xtltp5xjp8v7fx"
10415
-                  Parents: []
10416
-                  Type: "regular"
10417
-                  Description: "pulled from docker.io/library/debian@sha256:234cb88d3020898631af0ccbbcca9a66ae7306ecd30c9720690858c1b007d2a0"
10418
-                  InUse: false
10419
-                  Shared: true
10420
-                  Size: 0
10421
-                  CreatedAt: "2021-06-28T13:31:01.474619385Z"
10422
-                  LastUsedAt: "2021-07-07T22:02:32.738075951Z"
10423
-                  UsageCount: 26
10424
-                -
10425
-                  ID: "ndlpt0hhvkqcdfkputsk4cq9c"
10426
-                  Parents: ["ndlpt0hhvkqcdfkputsk4cq9c"]
10427
-                  Type: "regular"
10428
-                  Description: "mount / from exec /bin/sh -c echo 'Binary::apt::APT::Keep-Downloaded-Packages \"true\";' > /etc/apt/apt.conf.d/keep-cache"
10429
-                  InUse: false
10430
-                  Shared: true
10431
-                  Size: 51
10432
-                  CreatedAt: "2021-06-28T13:31:03.002625487Z"
10433
-                  LastUsedAt: "2021-07-07T22:02:32.773909517Z"
10434
-                  UsageCount: 26
10335
+              ImagesDiskUsage:
10336
+                $ref: "#/definitions/ImagesDiskUsage"
10337
+              ContainersDiskUsage:
10338
+                $ref: "#/definitions/ContainersDiskUsage"
10339
+              VolumesDiskUsage:
10340
+                $ref: "#/definitions/VolumesDiskUsage"
10341
+              BuildCacheDiskUsage:
10342
+                $ref: "#/definitions/BuildCacheDiskUsage"
10435 10343
         500:
10436 10344
           description: "server error"
10437 10345
           schema:
... ...
@@ -10446,6 +10522,12 @@ paths:
10446 10446
           items:
10447 10447
             type: "string"
10448 10448
             enum: ["container", "image", "volume", "build-cache"]
10449
+        - name: "verbose"
10450
+          in: "query"
10451
+          description: |
10452
+            Show detailed information on space usage.
10453
+          type: "boolean"
10454
+          default: false
10449 10455
       tags: ["System"]
10450 10456
   /images/{name}/get:
10451 10457
     get:
... ...
@@ -2059,6 +2059,47 @@ definitions:
2059 2059
         x-nullable: true
2060 2060
         $ref: "#/definitions/OCIDescriptor"
2061 2061
 
2062
+  ImagesDiskUsage:
2063
+    type: "object"
2064
+    description: |
2065
+      ImagesDiskUsage represents system data usage for image resources.
2066
+    properties:
2067
+      ActiveImages:
2068
+        description: |
2069
+          Count of active images.
2070
+        type: "integer"
2071
+        format: "int64"
2072
+        example: 1
2073
+      TotalImages:
2074
+        description: |
2075
+          Count of all images.
2076
+        type: "integer"
2077
+        format: "int64"
2078
+        example: 4
2079
+      Reclaimable:
2080
+        description: |
2081
+          Disk space that can be reclaimed by removing unused images.
2082
+        type: "integer"
2083
+        format: "int64"
2084
+        example: 12345678
2085
+      TotalSize:
2086
+        description: |
2087
+          Disk space in use by images.
2088
+        type: "integer"
2089
+        format: "int64"
2090
+        example: 98765432
2091
+      Items:
2092
+        description: |
2093
+          List of image summaries.
2094
+        type: "array"
2095
+        x-omitempty: true
2096
+        items:
2097
+          x-nullable: true
2098
+          x-go-type:
2099
+            type: Summary
2100
+            import:
2101
+              package: github.com/moby/moby/api/types/image
2102
+
2062 2103
   AuthConfig:
2063 2104
     type: "object"
2064 2105
     properties:
... ...
@@ -2201,6 +2242,47 @@ definitions:
2201 2201
               is set to `-1` if the reference-count is not available.
2202 2202
             x-nullable: false
2203 2203
 
2204
+  VolumesDiskUsage:
2205
+    type: "object"
2206
+    description: |
2207
+      VolumesDiskUsage represents system data usage for volume resources.
2208
+    properties:
2209
+      ActiveVolumes:
2210
+        description: |
2211
+          Count of active volumes.
2212
+        type: "integer"
2213
+        format: "int64"
2214
+        example: 1
2215
+      TotalVolumes:
2216
+        description: |
2217
+          Count of all volumes.
2218
+        type: "integer"
2219
+        format: "int64"
2220
+        example: 4
2221
+      Reclaimable:
2222
+        description: |
2223
+          Disk space that can be reclaimed by removing inactive volumes.
2224
+        type: "integer"
2225
+        format: "int64"
2226
+        example: 12345678
2227
+      TotalSize:
2228
+        description: |
2229
+          Disk space in use by volumes.
2230
+        type: "integer"
2231
+        format: "int64"
2232
+        example: 98765432
2233
+      Items:
2234
+        description: |
2235
+          List of volumes.
2236
+        type: "array"
2237
+        x-omitempty: true
2238
+        items:
2239
+          x-nullable: true
2240
+          x-go-type:
2241
+            type: Volume
2242
+            import:
2243
+              package: github.com/moby/moby/api/types/volume
2244
+
2204 2245
   VolumeCreateRequest:
2205 2246
     description: "Volume configuration"
2206 2247
     type: "object"
... ...
@@ -2774,6 +2856,47 @@ definitions:
2774 2774
         type: "integer"
2775 2775
         example: 26
2776 2776
 
2777
+  BuildCacheDiskUsage:
2778
+    type: "object"
2779
+    description: |
2780
+      BuildCacheDiskUsage represents system data usage for build cache resources.
2781
+    properties:
2782
+      ActiveBuildCacheRecords:
2783
+        description: |
2784
+          Count of active build cache records.
2785
+        type: "integer"
2786
+        format: "int64"
2787
+        example: 1
2788
+      TotalBuildCacheRecords:
2789
+        description: |
2790
+          Count of all build cache records.
2791
+        type: "integer"
2792
+        format: "int64"
2793
+        example: 4
2794
+      Reclaimable:
2795
+        description: |
2796
+          Disk space that can be reclaimed by removing inactive build cache records.
2797
+        type: "integer"
2798
+        format: "int64"
2799
+        example: 12345678
2800
+      TotalSize:
2801
+        description: |
2802
+          Disk space in use by build cache records.
2803
+        type: "integer"
2804
+        format: "int64"
2805
+        example: 98765432
2806
+      Items:
2807
+        description: |
2808
+          List of build cache records.
2809
+        type: "array"
2810
+        x-omitempty: true
2811
+        items:
2812
+          x-nullable: true
2813
+          x-go-type:
2814
+            type: CacheRecord
2815
+            import:
2816
+              package: github.com/moby/moby/api/types/build
2817
+
2777 2818
   ImageID:
2778 2819
     type: "object"
2779 2820
     description: "Image ID or Digest"
... ...
@@ -5457,6 +5580,47 @@ definitions:
5457 5457
             type: "integer"
5458 5458
             example: 0
5459 5459
 
5460
+  ContainersDiskUsage:
5461
+    type: "object"
5462
+    description: |
5463
+      ContainersDiskUsage provides system data usage information for container resources.
5464
+    properties:
5465
+      ActiveContainers:
5466
+        description: |
5467
+          Count of active containers.
5468
+        type: "integer"
5469
+        format: "int64"
5470
+        example: 1
5471
+      TotalContainers:
5472
+        description: |
5473
+          Count of all containers.
5474
+        type: "integer"
5475
+        format: "int64"
5476
+        example: 4
5477
+      Reclaimable:
5478
+        description: |
5479
+          Disk space that can be reclaimed by removing inactive containers.
5480
+        type: "integer"
5481
+        format: "int64"
5482
+        example: 12345678
5483
+      TotalSize:
5484
+        description: |
5485
+          Disk space in use by containers.
5486
+        type: "integer"
5487
+        format: "int64"
5488
+        example: 98765432
5489
+      Items:
5490
+        description: |
5491
+          List of container summaries.
5492
+        type: "array"
5493
+        x-omitempty: true
5494
+        items:
5495
+          x-nullable: true
5496
+          x-go-type:
5497
+            type: Summary
5498
+            import:
5499
+              package: github.com/moby/moby/api/types/container
5500
+
5460 5501
   Driver:
5461 5502
     description: "Driver represents a driver (network, logging, secrets)."
5462 5503
     type: "object"
... ...
@@ -10336,106 +10500,14 @@ paths:
10336 10336
             type: "object"
10337 10337
             title: "SystemDataUsageResponse"
10338 10338
             properties:
10339
-              LayersSize:
10340
-                type: "integer"
10341
-                format: "int64"
10342
-              Images:
10343
-                type: "array"
10344
-                items:
10345
-                  $ref: "#/definitions/ImageSummary"
10346
-              Containers:
10347
-                type: "array"
10348
-                items:
10349
-                  $ref: "#/definitions/ContainerSummary"
10350
-              Volumes:
10351
-                type: "array"
10352
-                items:
10353
-                  $ref: "#/definitions/Volume"
10354
-              BuildCache:
10355
-                type: "array"
10356
-                items:
10357
-                  $ref: "#/definitions/BuildCache"
10358
-            example:
10359
-              LayersSize: 1092588
10360
-              Images:
10361
-                -
10362
-                  Id: "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749"
10363
-                  ParentId: ""
10364
-                  RepoTags:
10365
-                    - "busybox:latest"
10366
-                  RepoDigests:
10367
-                    - "busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6"
10368
-                  Created: 1466724217
10369
-                  Size: 1092588
10370
-                  SharedSize: 0
10371
-                  Labels: {}
10372
-                  Containers: 1
10373
-              Containers:
10374
-                -
10375
-                  Id: "e575172ed11dc01bfce087fb27bee502db149e1a0fad7c296ad300bbff178148"
10376
-                  Names:
10377
-                    - "/top"
10378
-                  Image: "busybox"
10379
-                  ImageID: "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749"
10380
-                  Command: "top"
10381
-                  Created: 1472592424
10382
-                  Ports: []
10383
-                  SizeRootFs: 1092588
10384
-                  Labels: {}
10385
-                  State: "exited"
10386
-                  Status: "Exited (0) 56 minutes ago"
10387
-                  HostConfig:
10388
-                    NetworkMode: "default"
10389
-                  NetworkSettings:
10390
-                    Networks:
10391
-                      bridge:
10392
-                        IPAMConfig: null
10393
-                        Links: null
10394
-                        Aliases: null
10395
-                        NetworkID: "d687bc59335f0e5c9ee8193e5612e8aee000c8c62ea170cfb99c098f95899d92"
10396
-                        EndpointID: "8ed5115aeaad9abb174f68dcf135b49f11daf597678315231a32ca28441dec6a"
10397
-                        Gateway: "172.18.0.1"
10398
-                        IPAddress: "172.18.0.2"
10399
-                        IPPrefixLen: 16
10400
-                        IPv6Gateway: ""
10401
-                        GlobalIPv6Address: ""
10402
-                        GlobalIPv6PrefixLen: 0
10403
-                        MacAddress: "02:42:ac:12:00:02"
10404
-                  Mounts: []
10405
-              Volumes:
10406
-                -
10407
-                  Name: "my-volume"
10408
-                  Driver: "local"
10409
-                  Mountpoint: "/var/lib/docker/volumes/my-volume/_data"
10410
-                  Labels: null
10411
-                  Scope: "local"
10412
-                  Options: null
10413
-                  UsageData:
10414
-                    Size: 10920104
10415
-                    RefCount: 2
10416
-              BuildCache:
10417
-                -
10418
-                  ID: "hw53o5aio51xtltp5xjp8v7fx"
10419
-                  Parents: []
10420
-                  Type: "regular"
10421
-                  Description: "pulled from docker.io/library/debian@sha256:234cb88d3020898631af0ccbbcca9a66ae7306ecd30c9720690858c1b007d2a0"
10422
-                  InUse: false
10423
-                  Shared: true
10424
-                  Size: 0
10425
-                  CreatedAt: "2021-06-28T13:31:01.474619385Z"
10426
-                  LastUsedAt: "2021-07-07T22:02:32.738075951Z"
10427
-                  UsageCount: 26
10428
-                -
10429
-                  ID: "ndlpt0hhvkqcdfkputsk4cq9c"
10430
-                  Parents: ["ndlpt0hhvkqcdfkputsk4cq9c"]
10431
-                  Type: "regular"
10432
-                  Description: "mount / from exec /bin/sh -c echo 'Binary::apt::APT::Keep-Downloaded-Packages \"true\";' > /etc/apt/apt.conf.d/keep-cache"
10433
-                  InUse: false
10434
-                  Shared: true
10435
-                  Size: 51
10436
-                  CreatedAt: "2021-06-28T13:31:03.002625487Z"
10437
-                  LastUsedAt: "2021-07-07T22:02:32.773909517Z"
10438
-                  UsageCount: 26
10339
+              ImagesDiskUsage:
10340
+                $ref: "#/definitions/ImagesDiskUsage"
10341
+              ContainersDiskUsage:
10342
+                $ref: "#/definitions/ContainersDiskUsage"
10343
+              VolumesDiskUsage:
10344
+                $ref: "#/definitions/VolumesDiskUsage"
10345
+              BuildCacheDiskUsage:
10346
+                $ref: "#/definitions/BuildCacheDiskUsage"
10439 10347
         500:
10440 10348
           description: "server error"
10441 10349
           schema:
... ...
@@ -10450,6 +10522,12 @@ paths:
10450 10450
           items:
10451 10451
             type: "string"
10452 10452
             enum: ["container", "image", "volume", "build-cache"]
10453
+        - name: "verbose"
10454
+          in: "query"
10455
+          description: |
10456
+            Show detailed information on space usage.
10457
+          type: "boolean"
10458
+          default: false
10453 10459
       tags: ["System"]
10454 10460
   /images/{name}/get:
10455 10461
     get:
10456 10462
new file mode 100644
... ...
@@ -0,0 +1,40 @@
0
+// Code generated by go-swagger; DO NOT EDIT.
1
+
2
+package system
3
+
4
+// This file was generated by the swagger tool.
5
+// Editing this file might prove futile when you re-run the swagger generate command
6
+
7
+import (
8
+	"github.com/moby/moby/api/types/build"
9
+)
10
+
11
+// BuildCacheDiskUsage BuildCacheDiskUsage represents system data usage for build cache resources.
12
+//
13
+// swagger:model BuildCacheDiskUsage
14
+type BuildCacheDiskUsage struct {
15
+
16
+	// Count of active build cache records.
17
+	//
18
+	// Example: 1
19
+	ActiveBuildCacheRecords int64 `json:"ActiveBuildCacheRecords,omitempty"`
20
+
21
+	// List of build cache records.
22
+	//
23
+	Items []*build.CacheRecord `json:"Items,omitempty"`
24
+
25
+	// Disk space that can be reclaimed by removing inactive build cache records.
26
+	//
27
+	// Example: 12345678
28
+	Reclaimable int64 `json:"Reclaimable,omitempty"`
29
+
30
+	// Count of all build cache records.
31
+	//
32
+	// Example: 4
33
+	TotalBuildCacheRecords int64 `json:"TotalBuildCacheRecords,omitempty"`
34
+
35
+	// Disk space in use by build cache records.
36
+	//
37
+	// Example: 98765432
38
+	TotalSize int64 `json:"TotalSize,omitempty"`
39
+}
0 40
new file mode 100644
... ...
@@ -0,0 +1,40 @@
0
+// Code generated by go-swagger; DO NOT EDIT.
1
+
2
+package system
3
+
4
+// This file was generated by the swagger tool.
5
+// Editing this file might prove futile when you re-run the swagger generate command
6
+
7
+import (
8
+	"github.com/moby/moby/api/types/container"
9
+)
10
+
11
+// ContainersDiskUsage ContainersDiskUsage provides system data usage information for container resources.
12
+//
13
+// swagger:model ContainersDiskUsage
14
+type ContainersDiskUsage struct {
15
+
16
+	// Count of active containers.
17
+	//
18
+	// Example: 1
19
+	ActiveContainers int64 `json:"ActiveContainers,omitempty"`
20
+
21
+	// List of container summaries.
22
+	//
23
+	Items []*container.Summary `json:"Items,omitempty"`
24
+
25
+	// Disk space that can be reclaimed by removing inactive containers.
26
+	//
27
+	// Example: 12345678
28
+	Reclaimable int64 `json:"Reclaimable,omitempty"`
29
+
30
+	// Count of all containers.
31
+	//
32
+	// Example: 4
33
+	TotalContainers int64 `json:"TotalContainers,omitempty"`
34
+
35
+	// Disk space in use by containers.
36
+	//
37
+	// Example: 98765432
38
+	TotalSize int64 `json:"TotalSize,omitempty"`
39
+}
... ...
@@ -24,9 +24,27 @@ const (
24 24
 // DiskUsage contains response of Engine API:
25 25
 // GET "/system/df"
26 26
 type DiskUsage struct {
27
-	LayersSize int64
28
-	Images     []*image.Summary
29
-	Containers []*container.Summary
30
-	Volumes    []*volume.Volume
31
-	BuildCache []*build.CacheRecord
27
+	LegacyDiskUsage
28
+
29
+	ImageUsage      *ImagesDiskUsage     `json:"ImageUsage,omitempty"`
30
+	ContainerUsage  *ContainersDiskUsage `json:"ContainerUsage,omitempty"`
31
+	VolumeUsage     *VolumesDiskUsage    `json:"VolumeUsage,omitempty"`
32
+	BuildCacheUsage *BuildCacheDiskUsage `json:"BuildCacheUsage,omitempty"`
33
+}
34
+
35
+type LegacyDiskUsage struct {
36
+	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.TotalSize] instead.
37
+	LayersSize int64 `json:"LayersSize,omitempty"`
38
+
39
+	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.Items] instead.
40
+	Images []*image.Summary `json:"Images,omitempty"`
41
+
42
+	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ContainersDiskUsage.Items] instead.
43
+	Containers []*container.Summary `json:"Containers,omitempty"`
44
+
45
+	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [VolumesDiskUsage.Items] instead.
46
+	Volumes []*volume.Volume `json:"Volumes,omitempty"`
47
+
48
+	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [BuildCacheDiskUsage.Items] instead.
49
+	BuildCache []*build.CacheRecord `json:"BuildCache,omitempty"`
32 50
 }
33 51
new file mode 100644
... ...
@@ -0,0 +1,40 @@
0
+// Code generated by go-swagger; DO NOT EDIT.
1
+
2
+package system
3
+
4
+// This file was generated by the swagger tool.
5
+// Editing this file might prove futile when you re-run the swagger generate command
6
+
7
+import (
8
+	"github.com/moby/moby/api/types/image"
9
+)
10
+
11
+// ImagesDiskUsage ImagesDiskUsage represents system data usage for image resources.
12
+//
13
+// swagger:model ImagesDiskUsage
14
+type ImagesDiskUsage struct {
15
+
16
+	// Count of active images.
17
+	//
18
+	// Example: 1
19
+	ActiveImages int64 `json:"ActiveImages,omitempty"`
20
+
21
+	// List of image summaries.
22
+	//
23
+	Items []*image.Summary `json:"Items,omitempty"`
24
+
25
+	// Disk space that can be reclaimed by removing unused images.
26
+	//
27
+	// Example: 12345678
28
+	Reclaimable int64 `json:"Reclaimable,omitempty"`
29
+
30
+	// Count of all images.
31
+	//
32
+	// Example: 4
33
+	TotalImages int64 `json:"TotalImages,omitempty"`
34
+
35
+	// Disk space in use by images.
36
+	//
37
+	// Example: 98765432
38
+	TotalSize int64 `json:"TotalSize,omitempty"`
39
+}
0 40
new file mode 100644
... ...
@@ -0,0 +1,40 @@
0
+// Code generated by go-swagger; DO NOT EDIT.
1
+
2
+package system
3
+
4
+// This file was generated by the swagger tool.
5
+// Editing this file might prove futile when you re-run the swagger generate command
6
+
7
+import (
8
+	"github.com/moby/moby/api/types/volume"
9
+)
10
+
11
+// VolumesDiskUsage VolumesDiskUsage represents system data usage for volume resources.
12
+//
13
+// swagger:model VolumesDiskUsage
14
+type VolumesDiskUsage struct {
15
+
16
+	// Count of active volumes.
17
+	//
18
+	// Example: 1
19
+	ActiveVolumes int64 `json:"ActiveVolumes,omitempty"`
20
+
21
+	// List of volumes.
22
+	//
23
+	Items []*volume.Volume `json:"Items,omitempty"`
24
+
25
+	// Disk space that can be reclaimed by removing inactive volumes.
26
+	//
27
+	// Example: 12345678
28
+	Reclaimable int64 `json:"Reclaimable,omitempty"`
29
+
30
+	// Disk space in use by volumes.
31
+	//
32
+	// Example: 98765432
33
+	TotalSize int64 `json:"TotalSize,omitempty"`
34
+
35
+	// Count of all volumes.
36
+	//
37
+	// Example: 4
38
+	TotalVolumes int64 `json:"TotalVolumes,omitempty"`
39
+}
... ...
@@ -4,8 +4,6 @@ import (
4 4
 	"context"
5 5
 	"io"
6 6
 	"net"
7
-
8
-	"github.com/moby/moby/api/types/system"
9 7
 )
10 8
 
11 9
 // APIClient is an interface that clients that talk with a docker server must implement.
... ...
@@ -173,7 +171,7 @@ type SystemAPIClient interface {
173 173
 	Events(ctx context.Context, options EventsListOptions) EventsResult
174 174
 	Info(ctx context.Context, options InfoOptions) (SystemInfoResult, error)
175 175
 	RegistryLogin(ctx context.Context, auth RegistryLoginOptions) (RegistryLoginResult, error)
176
-	DiskUsage(ctx context.Context, options DiskUsageOptions) (system.DiskUsage, error)
176
+	DiskUsage(ctx context.Context, options DiskUsageOptions) (DiskUsageResult, error)
177 177
 	Ping(ctx context.Context, options PingOptions) (PingResult, error)
178 178
 }
179 179
 
... ...
@@ -29,6 +29,17 @@ func assertRequest(req *http.Request, expMethod string, expectedPath string) err
29 29
 	return nil
30 30
 }
31 31
 
32
+func assertRequestWithQuery(req *http.Request, expMethod string, expectedPath string, expectedQuery string) error {
33
+	if err := assertRequest(req, expMethod, expectedPath); err != nil {
34
+		return err
35
+	}
36
+	q := req.URL.Query().Encode()
37
+	if q != expectedQuery {
38
+		return fmt.Errorf("expected query '%s', got '%s'", expectedQuery, q)
39
+	}
40
+	return nil
41
+}
42
+
32 43
 // ensureBody makes sure the response has a Body, using [http.NoBody] if
33 44
 // none is present, and returns it as a testRoundTripper.
34 45
 func ensureBody(f func(req *http.Request) (*http.Response, error)) testRoundTripper {
... ...
@@ -6,28 +6,248 @@ import (
6 6
 	"fmt"
7 7
 	"net/url"
8 8
 
9
+	"github.com/moby/moby/api/types/build"
10
+	"github.com/moby/moby/api/types/container"
11
+	"github.com/moby/moby/api/types/image"
9 12
 	"github.com/moby/moby/api/types/system"
13
+	"github.com/moby/moby/api/types/volume"
10 14
 )
11 15
 
12
-// DiskUsage requests the current data usage from the daemon
13
-func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (system.DiskUsage, error) {
14
-	var query url.Values
15
-	if len(options.Types) > 0 {
16
-		query = url.Values{}
17
-		for _, t := range options.Types {
18
-			query.Add("type", string(t))
16
+// DiskUsageOptions holds parameters for [Client.DiskUsage] operations.
17
+type DiskUsageOptions struct {
18
+	// Containers controls whether container disk usage should be computed.
19
+	Containers bool
20
+
21
+	// Images controls whether image disk usage should be computed.
22
+	Images bool
23
+
24
+	// BuildCache controls whether build cache disk usage should be computed.
25
+	BuildCache bool
26
+
27
+	// Volumes controls whether volume disk usage should be computed.
28
+	Volumes bool
29
+
30
+	// Verbose enables more detailed disk usage information.
31
+	Verbose bool
32
+}
33
+
34
+// DiskUsageResult is the result of [Client.DiskUsage] operations.
35
+type DiskUsageResult struct {
36
+	// Containers holds container disk usage information.
37
+	Containers ContainersDiskUsage
38
+
39
+	// Images holds image disk usage information.
40
+	Images ImagesDiskUsage
41
+
42
+	// BuildCache holds build cache disk usage information.
43
+	BuildCache BuildCacheDiskUsage
44
+
45
+	// Volumes holds volume disk usage information.
46
+	Volumes VolumesDiskUsage
47
+}
48
+
49
+// ContainersDiskUsage contains disk usage information for containers.
50
+type ContainersDiskUsage struct {
51
+	// ActiveContainers is the number of active containers.
52
+	ActiveContainers int64
53
+
54
+	// TotalContainers is the total number of containers.
55
+	TotalContainers int64
56
+
57
+	// Reclaimable is the amount of disk space that can be reclaimed.
58
+	Reclaimable int64
59
+
60
+	// TotalSize is the total disk space used by all containers.
61
+	TotalSize int64
62
+
63
+	// Items holds detailed information about each container.
64
+	Items []container.Summary
65
+}
66
+
67
+// ImagesDiskUsage contains disk usage information for images.
68
+type ImagesDiskUsage struct {
69
+	// ActiveImages is the number of active images.
70
+	ActiveImages int64
71
+
72
+	// TotalImages is the total number of images.
73
+	TotalImages int64
74
+
75
+	// Reclaimable is the amount of disk space that can be reclaimed.
76
+	Reclaimable int64
77
+
78
+	// TotalSize is the total disk space used by all images.
79
+	TotalSize int64
80
+
81
+	// Items holds detailed information about each image.
82
+	Items []image.Summary
83
+}
84
+
85
+// VolumesDiskUsage contains disk usage information for volumes.
86
+type VolumesDiskUsage struct {
87
+	// ActiveVolumes is the number of active volumes.
88
+	ActiveVolumes int64
89
+
90
+	// TotalVolumes is the total number of volumes.
91
+	TotalVolumes int64
92
+
93
+	// Reclaimable is the amount of disk space that can be reclaimed.
94
+	Reclaimable int64
95
+
96
+	// TotalSize is the total disk space used by all volumes.
97
+	TotalSize int64
98
+
99
+	// Items holds detailed information about each volume.
100
+	Items []volume.Volume
101
+}
102
+
103
+// BuildCacheDiskUsage contains disk usage information for build cache.
104
+type BuildCacheDiskUsage struct {
105
+	// ActiveBuildCacheRecords is the number of active build cache records.
106
+	ActiveBuildCacheRecords int64
107
+
108
+	// TotalBuildCacheRecords is the total number of build cache records.
109
+	TotalBuildCacheRecords int64
110
+
111
+	// Reclaimable is the amount of disk space that can be reclaimed.
112
+	Reclaimable int64
113
+
114
+	// TotalSize is the total disk space used by all build cache records.
115
+	TotalSize int64
116
+
117
+	// Items holds detailed information about each build cache record.
118
+	Items []build.CacheRecord
119
+}
120
+
121
+// DiskUsage requests the current data usage from the daemon.
122
+func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (DiskUsageResult, error) {
123
+	query := url.Values{}
124
+
125
+	for _, t := range []struct {
126
+		flag   bool
127
+		sysObj system.DiskUsageObject
128
+	}{
129
+		{options.Containers, system.ContainerObject},
130
+		{options.Images, system.ImageObject},
131
+		{options.Volumes, system.VolumeObject},
132
+		{options.BuildCache, system.BuildCacheObject},
133
+	} {
134
+		if t.flag {
135
+			query.Add("type", string(t.sysObj))
19 136
 		}
20 137
 	}
21 138
 
139
+	if options.Verbose {
140
+		query.Set("verbose", "1")
141
+	}
142
+
22 143
 	resp, err := cli.get(ctx, "/system/df", query, nil)
23 144
 	defer ensureReaderClosed(resp)
24 145
 	if err != nil {
25
-		return system.DiskUsage{}, err
146
+		return DiskUsageResult{}, err
26 147
 	}
27 148
 
28 149
 	var du system.DiskUsage
29 150
 	if err := json.NewDecoder(resp.Body).Decode(&du); err != nil {
30
-		return system.DiskUsage{}, fmt.Errorf("Error retrieving disk usage: %v", err)
151
+		return DiskUsageResult{}, fmt.Errorf("Error retrieving disk usage: %v", err)
152
+	}
153
+
154
+	var (
155
+		r              DiskUsageResult
156
+		imagesFrom     = []*image.Summary{}
157
+		containersFrom = []*container.Summary{}
158
+		volumesFrom    = []*volume.Volume{}
159
+		buildCacheFrom = []*build.CacheRecord{}
160
+	)
161
+
162
+	if du.ImageUsage != nil {
163
+		r.Images = ImagesDiskUsage{
164
+			ActiveImages: du.ImageUsage.ActiveImages,
165
+			Reclaimable:  du.ImageUsage.Reclaimable,
166
+			TotalImages:  du.ImageUsage.TotalImages,
167
+			TotalSize:    du.ImageUsage.TotalSize,
168
+		}
169
+
170
+		if options.Verbose {
171
+			imagesFrom = du.ImageUsage.Items
172
+		}
173
+	} else {
174
+		// Fallback for legacy response.
175
+		r.Images = ImagesDiskUsage{
176
+			TotalSize: du.LayersSize,
177
+		}
178
+
179
+		if du.Images != nil && options.Verbose {
180
+			imagesFrom = du.Images
181
+		}
182
+	}
183
+
184
+	r.Images.Items = make([]image.Summary, len(imagesFrom))
185
+	for i, ii := range imagesFrom {
186
+		r.Images.Items[i] = *ii
187
+	}
188
+
189
+	if du.ContainerUsage != nil {
190
+		r.Containers = ContainersDiskUsage{
191
+			ActiveContainers: du.ContainerUsage.ActiveContainers,
192
+			Reclaimable:      du.ContainerUsage.Reclaimable,
193
+			TotalContainers:  du.ContainerUsage.TotalContainers,
194
+			TotalSize:        du.ContainerUsage.TotalSize,
195
+		}
196
+
197
+		if options.Verbose {
198
+			containersFrom = du.ContainerUsage.Items
199
+		}
200
+	} else if du.Containers != nil && options.Verbose {
201
+		// Fallback for legacy response.
202
+		containersFrom = du.Containers
31 203
 	}
32
-	return du, nil
204
+
205
+	r.Containers.Items = make([]container.Summary, len(containersFrom))
206
+	for i, c := range containersFrom {
207
+		r.Containers.Items[i] = *c
208
+	}
209
+
210
+	if du.BuildCacheUsage != nil {
211
+		r.BuildCache = BuildCacheDiskUsage{
212
+			ActiveBuildCacheRecords: du.BuildCacheUsage.ActiveBuildCacheRecords,
213
+			Reclaimable:             du.BuildCacheUsage.Reclaimable,
214
+			TotalBuildCacheRecords:  du.BuildCacheUsage.TotalBuildCacheRecords,
215
+			TotalSize:               du.BuildCacheUsage.TotalSize,
216
+		}
217
+
218
+		if options.Verbose {
219
+			buildCacheFrom = du.BuildCacheUsage.Items
220
+		}
221
+	} else if du.BuildCache != nil && options.Verbose {
222
+		// Fallback for legacy response.
223
+		buildCacheFrom = du.BuildCache
224
+	}
225
+
226
+	r.BuildCache.Items = make([]build.CacheRecord, len(buildCacheFrom))
227
+	for i, b := range buildCacheFrom {
228
+		r.BuildCache.Items[i] = *b
229
+	}
230
+
231
+	if du.VolumeUsage != nil {
232
+		r.Volumes = VolumesDiskUsage{
233
+			ActiveVolumes: du.VolumeUsage.ActiveVolumes,
234
+			Reclaimable:   du.VolumeUsage.Reclaimable,
235
+			TotalSize:     du.VolumeUsage.TotalSize,
236
+			TotalVolumes:  du.VolumeUsage.TotalVolumes,
237
+		}
238
+
239
+		if options.Verbose {
240
+			volumesFrom = du.VolumeUsage.Items
241
+		}
242
+	} else if du.Volumes != nil && options.Verbose {
243
+		// Fallback for legacy response.
244
+		volumesFrom = du.Volumes
245
+	}
246
+
247
+	r.Volumes.Items = make([]volume.Volume, len(volumesFrom))
248
+	for i, v := range volumesFrom {
249
+		r.Volumes.Items[i] = *v
250
+	}
251
+
252
+	return r, nil
33 253
 }
34 254
deleted file mode 100644
... ...
@@ -1,10 +0,0 @@
1
-package client
2
-
3
-import "github.com/moby/moby/api/types/system"
4
-
5
-// DiskUsageOptions holds parameters for system disk usage query.
6
-type DiskUsageOptions struct {
7
-	// Types specifies what object types to include in the response. If empty,
8
-	// all object types are returned.
9
-	Types []system.DiskUsageObject
10
-}
... ...
@@ -2,10 +2,12 @@ package client
2 2
 
3 3
 import (
4 4
 	"context"
5
+	"fmt"
5 6
 	"net/http"
6 7
 	"testing"
7 8
 
8 9
 	cerrdefs "github.com/containerd/errdefs"
10
+	"github.com/moby/moby/api/types/image"
9 11
 	"github.com/moby/moby/api/types/system"
10 12
 	"gotest.tools/v3/assert"
11 13
 	is "gotest.tools/v3/assert/cmp"
... ...
@@ -26,13 +28,129 @@ func TestDiskUsage(t *testing.T) {
26 26
 		}
27 27
 
28 28
 		return mockJSONResponse(http.StatusOK, nil, system.DiskUsage{
29
-			LayersSize: int64(100),
30
-			Images:     nil,
31
-			Containers: nil,
32
-			Volumes:    nil,
29
+			ImageUsage: &system.ImagesDiskUsage{
30
+				ActiveImages: 0,
31
+				TotalImages:  0,
32
+				Reclaimable:  0,
33
+				TotalSize:    4096,
34
+				Items:        []*image.Summary{},
35
+			},
33 36
 		})(req)
34 37
 	}))
35 38
 	assert.NilError(t, err)
36
-	_, err = client.DiskUsage(context.Background(), DiskUsageOptions{})
39
+
40
+	du, err := client.DiskUsage(context.Background(), DiskUsageOptions{})
41
+	assert.NilError(t, err)
42
+	assert.Equal(t, du.Images.ActiveImages, int64(0))
43
+	assert.Equal(t, du.Images.TotalImages, int64(0))
44
+	assert.Equal(t, du.Images.Reclaimable, int64(0))
45
+	assert.Equal(t, du.Images.TotalSize, int64(4096))
46
+	assert.Equal(t, len(du.Images.Items), 0)
47
+}
48
+
49
+func TestDiskUsageWithOptions(t *testing.T) {
50
+	const expectedURL = "/system/df"
51
+
52
+	tests := []struct {
53
+		options       DiskUsageOptions
54
+		expectedQuery string
55
+	}{
56
+		{
57
+			options: DiskUsageOptions{
58
+				Containers: true,
59
+			},
60
+			expectedQuery: "type=container",
61
+		},
62
+		{
63
+			options: DiskUsageOptions{
64
+				Images: true,
65
+			},
66
+			expectedQuery: "type=image",
67
+		},
68
+		{
69
+			options: DiskUsageOptions{
70
+				Volumes: true,
71
+			},
72
+			expectedQuery: "type=volume",
73
+		},
74
+		{
75
+			options: DiskUsageOptions{
76
+				BuildCache: true,
77
+			},
78
+			expectedQuery: "type=build-cache",
79
+		},
80
+		{
81
+			options: DiskUsageOptions{
82
+				Containers: true,
83
+				Images:     true,
84
+			},
85
+			expectedQuery: "type=container&type=image",
86
+		},
87
+		{
88
+			options: DiskUsageOptions{
89
+				Containers: true,
90
+				Images:     true,
91
+				Volumes:    true,
92
+				BuildCache: true,
93
+			},
94
+			expectedQuery: "type=container&type=image&type=volume&type=build-cache",
95
+		},
96
+		{
97
+			options: DiskUsageOptions{
98
+				Containers: true,
99
+				Verbose:    true,
100
+			},
101
+			expectedQuery: "type=container&verbose=1",
102
+		},
103
+		{
104
+			options: DiskUsageOptions{
105
+				Containers: true,
106
+				Images:     true,
107
+				Volumes:    true,
108
+				BuildCache: true,
109
+				Verbose:    true,
110
+			},
111
+			expectedQuery: "type=container&type=image&type=volume&type=build-cache&verbose=1",
112
+		},
113
+	}
114
+
115
+	for _, tt := range tests {
116
+		t.Run(fmt.Sprintf("options=%+v", tt.options), func(t *testing.T) {
117
+			client, err := NewClientWithOpts(WithMockClient(func(req *http.Request) (*http.Response, error) {
118
+				if err := assertRequestWithQuery(req, http.MethodGet, expectedURL, tt.expectedQuery); err != nil {
119
+					return nil, err
120
+				}
121
+
122
+				return mockJSONResponse(http.StatusOK, nil, system.DiskUsage{})(req)
123
+			}))
124
+			assert.NilError(t, err)
125
+			_, err = client.DiskUsage(t.Context(), tt.options)
126
+			assert.NilError(t, err)
127
+		})
128
+	}
129
+}
130
+
131
+func TestLegacyDiskUsage(t *testing.T) {
132
+	const expectedURL = "/system/df"
133
+	client, err := NewClientWithOpts(WithMockClient(func(req *http.Request) (*http.Response, error) {
134
+		if err := assertRequest(req, http.MethodGet, expectedURL); err != nil {
135
+			return nil, err
136
+		}
137
+
138
+		return mockJSONResponse(http.StatusOK, nil, system.DiskUsage{
139
+			LegacyDiskUsage: system.LegacyDiskUsage{
140
+				LayersSize: 4096,
141
+				Images:     []*image.Summary{},
142
+			},
143
+		})(req)
144
+	}))
145
+	assert.NilError(t, err)
146
+
147
+	du, err := client.DiskUsage(context.Background(), DiskUsageOptions{})
37 148
 	assert.NilError(t, err)
149
+	assert.Equal(t, du.Images.ActiveImages, int64(0))
150
+	assert.Equal(t, du.Images.TotalImages, int64(0))
151
+	assert.Equal(t, du.Images.Reclaimable, int64(0))
152
+	assert.Equal(t, du.Images.TotalSize, int64(4096))
153
+	assert.Equal(t, len(du.Images.Items), 0)
38 154
 }
... ...
@@ -34,7 +34,6 @@ import (
34 34
 	"github.com/moby/buildkit/util/tracing"
35 35
 	"github.com/moby/locker"
36 36
 	containertypes "github.com/moby/moby/api/types/container"
37
-	imagetypes "github.com/moby/moby/api/types/image"
38 37
 	networktypes "github.com/moby/moby/api/types/network"
39 38
 	registrytypes "github.com/moby/moby/api/types/registry"
40 39
 	"github.com/moby/moby/api/types/swarm"
... ...
@@ -134,7 +133,7 @@ type Daemon struct {
134 134
 	seccompProfilePath string
135 135
 
136 136
 	usageContainers singleflight.Group[struct{}, *backend.ContainerDiskUsage]
137
-	usageImages     singleflight.Group[struct{}, []*imagetypes.Summary]
137
+	usageImages     singleflight.Group[struct{}, *backend.ImageDiskUsage]
138 138
 	usageVolumes    singleflight.Group[struct{}, *backend.VolumeDiskUsage]
139 139
 	usageLayer      singleflight.Group[struct{}, int64]
140 140
 
... ...
@@ -5,7 +5,6 @@ import (
5 5
 	"fmt"
6 6
 
7 7
 	"github.com/moby/moby/api/types/container"
8
-	"github.com/moby/moby/api/types/image"
9 8
 	"github.com/moby/moby/v2/daemon/internal/filters"
10 9
 	"github.com/moby/moby/v2/daemon/server/backend"
11 10
 	"github.com/moby/moby/v2/daemon/server/imagebackend"
... ...
@@ -15,7 +14,7 @@ import (
15 15
 
16 16
 // containerDiskUsage obtains information about container data disk usage
17 17
 // and makes sure that only one calculation is performed at the same time.
18
-func (daemon *Daemon) containerDiskUsage(ctx context.Context) (*backend.ContainerDiskUsage, error) {
18
+func (daemon *Daemon) containerDiskUsage(ctx context.Context, verbose bool) (*backend.ContainerDiskUsage, error) {
19 19
 	res, _, err := daemon.usageContainers.Do(ctx, struct{}{}, func(ctx context.Context) (*backend.ContainerDiskUsage, error) {
20 20
 		// Retrieve container list
21 21
 		containers, err := daemon.Containers(ctx, &backend.ContainerListOptions{
... ...
@@ -38,13 +37,23 @@ func (daemon *Daemon) containerDiskUsage(ctx context.Context) (*backend.Containe
38 38
 				ctr.State == container.StateRestarting
39 39
 		}
40 40
 
41
-		du := &backend.ContainerDiskUsage{Items: containers}
42
-		for _, ctr := range du.Items {
41
+		activeCount := int64(len(containers))
42
+
43
+		du := &backend.ContainerDiskUsage{TotalCount: activeCount}
44
+		for _, ctr := range containers {
43 45
 			du.TotalSize += ctr.SizeRw
44 46
 			if !isActive(ctr) {
45 47
 				du.Reclaimable += ctr.SizeRw
48
+				activeCount--
46 49
 			}
47 50
 		}
51
+
52
+		du.ActiveCount = activeCount
53
+
54
+		if verbose {
55
+			du.Items = containers
56
+		}
57
+
48 58
 		return du, nil
49 59
 	})
50 60
 	return res, err
... ...
@@ -52,54 +61,83 @@ func (daemon *Daemon) containerDiskUsage(ctx context.Context) (*backend.Containe
52 52
 
53 53
 // imageDiskUsage obtains information about image data disk usage from image service
54 54
 // and makes sure that only one calculation is performed at the same time.
55
-func (daemon *Daemon) imageDiskUsage(ctx context.Context) ([]*image.Summary, error) {
56
-	imgs, _, err := daemon.usageImages.Do(ctx, struct{}{}, func(ctx context.Context) ([]*image.Summary, error) {
55
+func (daemon *Daemon) imageDiskUsage(ctx context.Context, verbose bool) (*backend.ImageDiskUsage, error) {
56
+	du, _, err := daemon.usageImages.Do(ctx, struct{}{}, func(ctx context.Context) (*backend.ImageDiskUsage, error) {
57 57
 		// Get all top images with extra attributes
58
-		imgs, err := daemon.imageService.Images(ctx, imagebackend.ListOptions{
58
+		images, err := daemon.imageService.Images(ctx, imagebackend.ListOptions{
59 59
 			Filters:    filters.NewArgs(),
60 60
 			SharedSize: true,
61 61
 		})
62 62
 		if err != nil {
63 63
 			return nil, errors.Wrap(err, "failed to retrieve image list")
64 64
 		}
65
-		return imgs, nil
65
+
66
+		reclaimable, _, err := daemon.usageLayer.Do(ctx, struct{}{}, func(ctx context.Context) (int64, error) {
67
+			return daemon.imageService.ImageDiskUsage(ctx)
68
+		})
69
+		if err != nil {
70
+			return nil, errors.Wrap(err, "failed to calculate image disk usage")
71
+		}
72
+
73
+		activeCount := int64(len(images))
74
+
75
+		du := &backend.ImageDiskUsage{TotalCount: activeCount, TotalSize: reclaimable}
76
+		for _, i := range images {
77
+			if i.Containers == 0 {
78
+				activeCount--
79
+				if i.Size == -1 || i.SharedSize == -1 {
80
+					continue
81
+				}
82
+				reclaimable -= i.Size - i.SharedSize
83
+			}
84
+		}
85
+
86
+		du.Reclaimable = reclaimable
87
+		du.ActiveCount = activeCount
88
+
89
+		if verbose {
90
+			du.Items = images
91
+		}
92
+
93
+		return du, nil
66 94
 	})
67 95
 
68
-	return imgs, err
96
+	return du, err
69 97
 }
70 98
 
71 99
 // localVolumesSize obtains information about volume disk usage from volumes service
72 100
 // and makes sure that only one size calculation is performed at the same time.
73
-func (daemon *Daemon) localVolumesSize(ctx context.Context) (*backend.VolumeDiskUsage, error) {
101
+func (daemon *Daemon) localVolumesSize(ctx context.Context, verbose bool) (*backend.VolumeDiskUsage, error) {
74 102
 	volumes, _, err := daemon.usageVolumes.Do(ctx, struct{}{}, func(ctx context.Context) (*backend.VolumeDiskUsage, error) {
75 103
 		volumes, err := daemon.volumes.LocalVolumesSize(ctx)
76 104
 		if err != nil {
77 105
 			return nil, err
78 106
 		}
79 107
 
80
-		du := &backend.VolumeDiskUsage{Items: volumes}
81
-		for _, v := range du.Items {
108
+		activeCount := int64(len(volumes))
109
+
110
+		du := &backend.VolumeDiskUsage{TotalCount: activeCount}
111
+		for _, v := range volumes {
82 112
 			if v.UsageData.Size != -1 {
83 113
 				if v.UsageData.RefCount == 0 {
84 114
 					du.Reclaimable += v.UsageData.Size
115
+					activeCount--
85 116
 				}
86 117
 				du.TotalSize += v.UsageData.Size
87 118
 			}
88 119
 		}
120
+
121
+		du.ActiveCount = activeCount
122
+
123
+		if verbose {
124
+			du.Items = volumes
125
+		}
126
+
89 127
 		return du, nil
90 128
 	})
91 129
 	return volumes, err
92 130
 }
93 131
 
94
-// layerDiskUsage obtains information about layer disk usage from image service
95
-// and makes sure that only one size calculation is performed at the same time.
96
-func (daemon *Daemon) layerDiskUsage(ctx context.Context) (int64, error) {
97
-	usage, _, err := daemon.usageLayer.Do(ctx, struct{}{}, func(ctx context.Context) (usage int64, err error) {
98
-		return daemon.imageService.ImageDiskUsage(ctx)
99
-	})
100
-	return usage, err
101
-}
102
-
103 132
 // SystemDiskUsage returns information about the daemon data disk usage.
104 133
 // Callers must not mutate contents of the returned fields.
105 134
 func (daemon *Daemon) SystemDiskUsage(ctx context.Context, opts backend.DiskUsageOptions) (*backend.DiskUsage, error) {
... ...
@@ -108,29 +146,21 @@ func (daemon *Daemon) SystemDiskUsage(ctx context.Context, opts backend.DiskUsag
108 108
 	du := &backend.DiskUsage{}
109 109
 	if opts.Containers {
110 110
 		eg.Go(func() (err error) {
111
-			du.Containers, err = daemon.containerDiskUsage(ctx)
111
+			du.Containers, err = daemon.containerDiskUsage(ctx, opts.Verbose)
112 112
 			return err
113 113
 		})
114 114
 	}
115 115
 
116
-	var (
117
-		layersSize int64
118
-		images     []*image.Summary
119
-	)
120 116
 	if opts.Images {
121 117
 		eg.Go(func() (err error) {
122
-			images, err = daemon.imageDiskUsage(ctx)
123
-			return err
124
-		})
125
-		eg.Go(func() (err error) {
126
-			layersSize, err = daemon.layerDiskUsage(ctx)
118
+			du.Images, err = daemon.imageDiskUsage(ctx, opts.Verbose)
127 119
 			return err
128 120
 		})
129 121
 	}
130 122
 
131 123
 	if opts.Volumes {
132 124
 		eg.Go(func() (err error) {
133
-			du.Volumes, err = daemon.localVolumesSize(ctx)
125
+			du.Volumes, err = daemon.localVolumesSize(ctx, opts.Verbose)
134 126
 			return err
135 127
 		})
136 128
 	}
... ...
@@ -139,22 +169,5 @@ func (daemon *Daemon) SystemDiskUsage(ctx context.Context, opts backend.DiskUsag
139 139
 		return nil, err
140 140
 	}
141 141
 
142
-	if opts.Images {
143
-		reclaimable := layersSize
144
-		for _, i := range images {
145
-			if i.Containers != 0 {
146
-				if i.Size == -1 || i.SharedSize == -1 {
147
-					continue
148
-				}
149
-				reclaimable -= i.Size - i.SharedSize
150
-			}
151
-		}
152
-
153
-		du.Images = &backend.ImageDiskUsage{
154
-			TotalSize:   layersSize,
155
-			Reclaimable: reclaimable,
156
-			Items:       images,
157
-		}
158
-	}
159 142
 	return du, nil
160 143
 }
... ...
@@ -17,6 +17,9 @@ type DiskUsageOptions struct {
17 17
 
18 18
 	// Volumes controls whether volume disk usage should be computed.
19 19
 	Volumes bool
20
+
21
+	// Verbose indicates whether to include detailed information.
22
+	Verbose bool
20 23
 }
21 24
 
22 25
 // DiskUsage contains the information returned by the backend for the
... ...
@@ -30,6 +33,8 @@ type DiskUsage struct {
30 30
 
31 31
 // BuildCacheDiskUsage contains disk usage for the build cache.
32 32
 type BuildCacheDiskUsage struct {
33
+	ActiveCount int64
34
+	TotalCount  int64
33 35
 	TotalSize   int64
34 36
 	Reclaimable int64
35 37
 	Items       []*build.CacheRecord
... ...
@@ -37,6 +42,8 @@ type BuildCacheDiskUsage struct {
37 37
 
38 38
 // ContainerDiskUsage contains disk usage for containers.
39 39
 type ContainerDiskUsage struct {
40
+	ActiveCount int64
41
+	TotalCount  int64
40 42
 	TotalSize   int64
41 43
 	Reclaimable int64
42 44
 	Items       []*container.Summary
... ...
@@ -44,6 +51,8 @@ type ContainerDiskUsage struct {
44 44
 
45 45
 // ImageDiskUsage contains disk usage for images.
46 46
 type ImageDiskUsage struct {
47
+	ActiveCount int64
48
+	TotalCount  int64
47 49
 	TotalSize   int64
48 50
 	Reclaimable int64
49 51
 	Items       []*image.Summary
... ...
@@ -51,6 +60,8 @@ type ImageDiskUsage struct {
51 51
 
52 52
 // VolumeDiskUsage contains disk usage for volumes.
53 53
 type VolumeDiskUsage struct {
54
+	ActiveCount int64
55
+	TotalCount  int64
54 56
 	TotalSize   int64
55 57
 	Reclaimable int64
56 58
 	Items       []*volume.Volume
... ...
@@ -5,6 +5,7 @@ import (
5 5
 	"encoding/json"
6 6
 	"fmt"
7 7
 	"net/http"
8
+	"strconv"
8 9
 	"time"
9 10
 
10 11
 	"github.com/containerd/log"
... ...
@@ -161,6 +162,21 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
161 161
 		}
162 162
 	}
163 163
 
164
+	// To maintain backwards compatibility with older clients, when communicating with API versions prior to 1.52,
165
+	// verbose mode is always enabled. For API 1.52 and onwards, if the "verbose" query parameter is not set,
166
+	// assume legacy fields should be included.
167
+	var verbose, legacyFields bool
168
+	if v := r.Form.Get("verbose"); versions.GreaterThanOrEqualTo(version, "1.52") && v != "" {
169
+		var err error
170
+		verbose, err = strconv.ParseBool(v)
171
+		if err != nil {
172
+			return invalidRequestError{Err: fmt.Errorf("invalid value for verbose: %s", v)}
173
+		}
174
+	} else {
175
+		// In versions prior to 1.52, legacy fields were always included.
176
+		legacyFields, verbose = true, true
177
+	}
178
+
164 179
 	eg, ctx := errgroup.WithContext(ctx)
165 180
 
166 181
 	var systemDiskUsage *backend.DiskUsage
... ...
@@ -171,6 +187,7 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
171 171
 				Containers: getContainers,
172 172
 				Images:     getImages,
173 173
 				Volumes:    getVolumes,
174
+				Verbose:    verbose,
174 175
 			})
175 176
 			return err
176 177
 		})
... ...
@@ -197,40 +214,80 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
197 197
 		return err
198 198
 	}
199 199
 
200
-	var builderSize int64
201
-	if versions.LessThan(version, "1.42") {
202
-		for _, b := range buildCache {
203
-			builderSize += b.Size
200
+	var v system.DiskUsage
201
+	if systemDiskUsage != nil && systemDiskUsage.Images != nil {
202
+		v.ImageUsage = &system.ImagesDiskUsage{
203
+			ActiveImages: systemDiskUsage.Images.ActiveCount,
204
+			Reclaimable:  systemDiskUsage.Images.Reclaimable,
205
+			TotalImages:  systemDiskUsage.Images.TotalCount,
206
+			TotalSize:    systemDiskUsage.Images.TotalSize,
204 207
 		}
205
-	}
206 208
 
207
-	du := backend.DiskUsage{}
208
-	if getBuildCache {
209
-		du.BuildCache = &backend.BuildCacheDiskUsage{
210
-			TotalSize: builderSize,
211
-			Items:     buildCache,
209
+		if legacyFields {
210
+			v.LayersSize = systemDiskUsage.Images.TotalSize //nolint: staticcheck,SA1019: v.LayersSize is deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.TotalSize] instead.
211
+			v.Images = systemDiskUsage.Images.Items         //nolint: staticcheck,SA1019: v.Images is deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.Items] instead.
212
+		} else if verbose {
213
+			v.ImageUsage.Items = systemDiskUsage.Images.Items
212 214
 		}
213 215
 	}
214
-	if systemDiskUsage != nil {
215
-		du.Images = systemDiskUsage.Images
216
-		du.Containers = systemDiskUsage.Containers
217
-		du.Volumes = systemDiskUsage.Volumes
218
-	}
216
+	if systemDiskUsage != nil && systemDiskUsage.Containers != nil {
217
+		v.ContainerUsage = &system.ContainersDiskUsage{
218
+			ActiveContainers: systemDiskUsage.Containers.ActiveCount,
219
+			Reclaimable:      systemDiskUsage.Containers.Reclaimable,
220
+			TotalContainers:  systemDiskUsage.Containers.TotalCount,
221
+			TotalSize:        systemDiskUsage.Containers.TotalSize,
222
+		}
219 223
 
220
-	// Use the old struct for the API return value.
221
-	var v system.DiskUsage
222
-	if du.Images != nil {
223
-		v.LayersSize = du.Images.TotalSize
224
-		v.Images = du.Images.Items
225
-	}
226
-	if du.Containers != nil {
227
-		v.Containers = du.Containers.Items
224
+		if legacyFields {
225
+			v.Containers = systemDiskUsage.Containers.Items //nolint: staticcheck,SA1019: v.Containers is deprecated: kept to maintain backwards compatibility with API < v1.52, use [ContainersDiskUsage.Items] instead.
226
+		} else if verbose {
227
+			v.ContainerUsage.Items = systemDiskUsage.Containers.Items
228
+		}
228 229
 	}
229
-	if du.Volumes != nil {
230
-		v.Volumes = du.Volumes.Items
230
+	if systemDiskUsage != nil && systemDiskUsage.Volumes != nil {
231
+		v.VolumeUsage = &system.VolumesDiskUsage{
232
+			ActiveVolumes: systemDiskUsage.Volumes.ActiveCount,
233
+			TotalSize:     systemDiskUsage.Volumes.TotalSize,
234
+			Reclaimable:   systemDiskUsage.Volumes.Reclaimable,
235
+			TotalVolumes:  systemDiskUsage.Volumes.TotalCount,
236
+		}
237
+
238
+		if legacyFields {
239
+			v.Volumes = systemDiskUsage.Volumes.Items //nolint: staticcheck,SA1019: v.Volumes is deprecated: kept to maintain backwards compatibility with API < v1.52, use [VolumesDiskUsage.Items] instead.
240
+		} else if verbose {
241
+			v.VolumeUsage.Items = systemDiskUsage.Volumes.Items
242
+		}
231 243
 	}
232
-	if du.BuildCache != nil {
233
-		v.BuildCache = du.BuildCache.Items
244
+	if getBuildCache {
245
+		v.BuildCacheUsage = &system.BuildCacheDiskUsage{
246
+			TotalBuildCacheRecords: int64(len(buildCache)),
247
+		}
248
+
249
+		activeCount := v.BuildCacheUsage.TotalBuildCacheRecords
250
+		var totalSize, reclaimable int64
251
+
252
+		for _, b := range buildCache {
253
+			if versions.LessThan(version, "1.42") {
254
+				totalSize += b.Size
255
+			}
256
+
257
+			if !b.InUse {
258
+				activeCount--
259
+			}
260
+			if !b.InUse && !b.Shared {
261
+				reclaimable += b.Size
262
+			}
263
+		}
264
+
265
+		v.BuildCacheUsage.ActiveBuildCacheRecords = activeCount
266
+		v.BuildCacheUsage.TotalSize = totalSize
267
+		v.BuildCacheUsage.Reclaimable = reclaimable
268
+
269
+		if legacyFields {
270
+			v.BuildCache = buildCache //nolint: staticcheck,SA1019: v.BuildCache is deprecated: kept to maintain backwards compatibility with API < v1.52, use [BuildCacheDiskUsage.Items] instead.
271
+		} else if verbose {
272
+			v.BuildCacheUsage.Items = buildCache
273
+		}
234 274
 	}
235 275
 	return httputils.WriteJSON(w, http.StatusOK, v)
236 276
 }
... ...
@@ -95,6 +95,13 @@ generate_model types/storage <<- 'EOT'
95 95
 	Storage
96 96
 EOT
97 97
 
98
+generate_model types/system <<- 'EOT'
99
+	BuildCacheDiskUsage
100
+	ContainersDiskUsage
101
+	ImagesDiskUsage
102
+	VolumesDiskUsage
103
+EOT
104
+
98 105
 generate_model types/swarm <<- 'EOT'
99 106
 	ServiceCreateResponse
100 107
 	ServiceUpdateResponse
... ...
@@ -8,7 +8,6 @@ import (
8 8
 	"github.com/moby/moby/api/types/build"
9 9
 	containertypes "github.com/moby/moby/api/types/container"
10 10
 	"github.com/moby/moby/api/types/image"
11
-	"github.com/moby/moby/api/types/system"
12 11
 	"github.com/moby/moby/api/types/volume"
13 12
 	"github.com/moby/moby/client"
14 13
 	"github.com/moby/moby/v2/integration/internal/container"
... ...
@@ -30,78 +29,110 @@ func TestDiskUsage(t *testing.T) {
30 30
 	defer d.Stop(t)
31 31
 	apiClient := d.NewClientT(t)
32 32
 
33
-	var stepDU system.DiskUsage
33
+	var stepDU client.DiskUsageResult
34 34
 	for _, step := range []struct {
35 35
 		doc  string
36
-		next func(t *testing.T, prev system.DiskUsage) system.DiskUsage
36
+		next func(t *testing.T, prev client.DiskUsageResult) client.DiskUsageResult
37 37
 	}{
38 38
 		{
39 39
 			doc: "empty",
40
-			next: func(t *testing.T, _ system.DiskUsage) system.DiskUsage {
41
-				du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{})
40
+			next: func(t *testing.T, _ client.DiskUsageResult) client.DiskUsageResult {
41
+				du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{
42
+					Images:     true,
43
+					Containers: true,
44
+					BuildCache: true,
45
+					Volumes:    true,
46
+					Verbose:    true,
47
+				})
42 48
 				assert.NilError(t, err)
43 49
 
44 50
 				expectedLayersSize := int64(0)
45 51
 				// TODO: Investigate https://github.com/moby/moby/issues/47119
46 52
 				// Make 4096 (block size) also a valid value for zero usage.
47 53
 				if testEnv.UsingSnapshotter() && testEnv.IsRootless() {
48
-					if du.LayersSize == 4096 {
49
-						expectedLayersSize = du.LayersSize
54
+					if du.Images.TotalSize == 4096 {
55
+						expectedLayersSize = 4096
50 56
 					}
51 57
 				}
52 58
 
53
-				assert.DeepEqual(t, du, system.DiskUsage{
54
-					LayersSize: expectedLayersSize,
55
-					Images:     []*image.Summary{},
56
-					Containers: []*containertypes.Summary{},
57
-					Volumes:    []*volume.Volume{},
58
-					BuildCache: []*build.CacheRecord{},
59
+				assert.DeepEqual(t, du, client.DiskUsageResult{
60
+					Containers: client.ContainersDiskUsage{
61
+						Items: []containertypes.Summary{},
62
+					},
63
+					Images: client.ImagesDiskUsage{
64
+						TotalSize: expectedLayersSize,
65
+						Items:     []image.Summary{},
66
+					},
67
+					BuildCache: client.BuildCacheDiskUsage{
68
+						Items: []build.CacheRecord{},
69
+					},
70
+					Volumes: client.VolumesDiskUsage{
71
+						Items: []volume.Volume{},
72
+					},
59 73
 				})
60 74
 				return du
61 75
 			},
62 76
 		},
63 77
 		{
64 78
 			doc: "after LoadBusybox",
65
-			next: func(t *testing.T, _ system.DiskUsage) system.DiskUsage {
79
+			next: func(t *testing.T, _ client.DiskUsageResult) client.DiskUsageResult {
66 80
 				d.LoadBusybox(ctx, t)
67 81
 
68
-				du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{})
82
+				du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{
83
+					Images:     true,
84
+					Containers: true,
85
+					BuildCache: true,
86
+					Volumes:    true,
87
+					Verbose:    true,
88
+				})
69 89
 				assert.NilError(t, err)
70
-				assert.Assert(t, du.LayersSize > 0)
71
-				assert.Equal(t, len(du.Images), 1)
72
-				assert.Equal(t, len(du.Images[0].RepoTags), 1)
73
-				assert.Check(t, is.Equal(du.Images[0].RepoTags[0], "busybox:latest"))
90
+
91
+				assert.Assert(t, du.Images.TotalSize > 0)
92
+				assert.Equal(t, len(du.Images.Items), 1)
93
+				assert.Equal(t, len(du.Images.Items[0].RepoTags), 1)
94
+				assert.Check(t, is.Equal(du.Images.Items[0].RepoTags[0], "busybox:latest"))
74 95
 
75 96
 				// Image size is layer size + content size. Content size is included in layers size.
76
-				assert.Equal(t, du.Images[0].Size, du.LayersSize)
97
+				assert.Equal(t, du.Images.Items[0].Size, du.Images.TotalSize)
77 98
 
78 99
 				return du
79 100
 			},
80 101
 		},
81 102
 		{
82 103
 			doc: "after container.Run",
83
-			next: func(t *testing.T, prev system.DiskUsage) system.DiskUsage {
104
+			next: func(t *testing.T, prev client.DiskUsageResult) client.DiskUsageResult {
84 105
 				cID := container.Run(ctx, t, apiClient)
85 106
 
86
-				du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{})
107
+				du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{
108
+					Images:     true,
109
+					Containers: true,
110
+					BuildCache: true,
111
+					Volumes:    true,
112
+					Verbose:    true,
113
+				})
87 114
 				assert.NilError(t, err)
88
-				assert.Equal(t, len(du.Containers), 1)
89
-				assert.Equal(t, len(du.Containers[0].Names), 1)
90
-				assert.Assert(t, len(prev.Images) > 0)
91
-				assert.Check(t, du.Containers[0].Created >= prev.Images[0].Created)
115
+
116
+				assert.Equal(t, du.Containers.ActiveContainers, int64(1))
117
+				assert.Equal(t, du.Containers.TotalContainers, int64(1))
118
+				assert.Equal(t, len(du.Containers.Items), 1)
119
+				assert.Equal(t, len(du.Containers.Items[0].Names), 1)
120
+				assert.Assert(t, len(prev.Images.Items) > 0)
121
+				assert.Check(t, du.Containers.Items[0].Created >= prev.Images.Items[0].Created)
92 122
 
93 123
 				// Additional container layer could add to the size
94
-				assert.Check(t, du.LayersSize >= prev.LayersSize)
124
+				assert.Check(t, du.Images.TotalSize >= prev.Images.TotalSize)
95 125
 
96
-				assert.Equal(t, len(du.Images), 1)
97
-				assert.Equal(t, du.Images[0].Containers, prev.Images[0].Containers+1)
126
+				assert.Equal(t, du.Images.ActiveImages, int64(1))
127
+				assert.Equal(t, du.Images.TotalImages, int64(1))
128
+				assert.Equal(t, len(du.Images.Items), 1)
129
+				assert.Equal(t, du.Images.Items[0].Containers, prev.Images.Items[0].Containers+1)
98 130
 
99
-				assert.Check(t, is.Equal(du.Containers[0].ID, cID))
100
-				assert.Check(t, is.Equal(du.Containers[0].Image, "busybox"))
101
-				assert.Check(t, is.Equal(du.Containers[0].ImageID, prev.Images[0].ID))
131
+				assert.Check(t, is.Equal(du.Containers.Items[0].ID, cID))
132
+				assert.Check(t, is.Equal(du.Containers.Items[0].Image, "busybox"))
133
+				assert.Check(t, is.Equal(du.Containers.Items[0].ImageID, prev.Images.Items[0].ID))
102 134
 
103 135
 				// ImageManifestDescriptor should NOT be populated.
104
-				assert.Check(t, is.Nil(du.Containers[0].ImageManifestDescriptor))
136
+				assert.Check(t, is.Nil(du.Containers.Items[0].ImageManifestDescriptor))
105 137
 
106 138
 				return du
107 139
 			},
... ...
@@ -114,143 +145,153 @@ func TestDiskUsage(t *testing.T) {
114 114
 			for _, tc := range []struct {
115 115
 				doc      string
116 116
 				options  client.DiskUsageOptions
117
-				expected system.DiskUsage
117
+				expected client.DiskUsageResult
118 118
 			}{
119 119
 				{
120 120
 					doc: "container types",
121 121
 					options: client.DiskUsageOptions{
122
-						Types: []system.DiskUsageObject{
123
-							system.ContainerObject,
124
-						},
122
+						Containers: true,
123
+						Verbose:    true,
125 124
 					},
126
-					expected: system.DiskUsage{
125
+					expected: client.DiskUsageResult{
127 126
 						Containers: stepDU.Containers,
127
+						Images:     client.ImagesDiskUsage{Items: []image.Summary{}},
128
+						BuildCache: client.BuildCacheDiskUsage{Items: []build.CacheRecord{}},
129
+						Volumes:    client.VolumesDiskUsage{Items: []volume.Volume{}},
128 130
 					},
129 131
 				},
130 132
 				{
131 133
 					doc: "image types",
132 134
 					options: client.DiskUsageOptions{
133
-						Types: []system.DiskUsageObject{
134
-							system.ImageObject,
135
-						},
135
+						Images:  true,
136
+						Verbose: true,
136 137
 					},
137
-					expected: system.DiskUsage{
138
-						LayersSize: stepDU.LayersSize,
138
+					expected: client.DiskUsageResult{
139
+						Containers: client.ContainersDiskUsage{Items: []containertypes.Summary{}},
139 140
 						Images:     stepDU.Images,
141
+						BuildCache: client.BuildCacheDiskUsage{Items: []build.CacheRecord{}},
142
+						Volumes:    client.VolumesDiskUsage{Items: []volume.Volume{}},
140 143
 					},
141 144
 				},
142 145
 				{
143 146
 					doc: "volume types",
144 147
 					options: client.DiskUsageOptions{
145
-						Types: []system.DiskUsageObject{
146
-							system.VolumeObject,
147
-						},
148
+						Volumes: true,
149
+						Verbose: true,
148 150
 					},
149
-					expected: system.DiskUsage{
150
-						Volumes: stepDU.Volumes,
151
+					expected: client.DiskUsageResult{
152
+						Containers: client.ContainersDiskUsage{Items: []containertypes.Summary{}},
153
+						Images:     client.ImagesDiskUsage{Items: []image.Summary{}},
154
+						BuildCache: client.BuildCacheDiskUsage{Items: []build.CacheRecord{}},
155
+						Volumes:    stepDU.Volumes,
151 156
 					},
152 157
 				},
153 158
 				{
154 159
 					doc: "build-cache types",
155 160
 					options: client.DiskUsageOptions{
156
-						Types: []system.DiskUsageObject{
157
-							system.BuildCacheObject,
158
-						},
161
+						BuildCache: true,
162
+						Verbose:    true,
159 163
 					},
160
-					expected: system.DiskUsage{
164
+					expected: client.DiskUsageResult{
165
+						Containers: client.ContainersDiskUsage{Items: []containertypes.Summary{}},
166
+						Images:     client.ImagesDiskUsage{Items: []image.Summary{}},
161 167
 						BuildCache: stepDU.BuildCache,
168
+						Volumes:    client.VolumesDiskUsage{Items: []volume.Volume{}},
162 169
 					},
163 170
 				},
164 171
 				{
165 172
 					doc: "container, volume types",
166 173
 					options: client.DiskUsageOptions{
167
-						Types: []system.DiskUsageObject{
168
-							system.ContainerObject,
169
-							system.VolumeObject,
170
-						},
174
+						Containers: true,
175
+						Volumes:    true,
176
+						Verbose:    true,
171 177
 					},
172
-					expected: system.DiskUsage{
178
+					expected: client.DiskUsageResult{
173 179
 						Containers: stepDU.Containers,
180
+						Images:     client.ImagesDiskUsage{Items: []image.Summary{}},
181
+						BuildCache: client.BuildCacheDiskUsage{Items: []build.CacheRecord{}},
174 182
 						Volumes:    stepDU.Volumes,
175 183
 					},
176 184
 				},
177 185
 				{
178 186
 					doc: "image, build-cache types",
179 187
 					options: client.DiskUsageOptions{
180
-						Types: []system.DiskUsageObject{
181
-							system.ImageObject,
182
-							system.BuildCacheObject,
183
-						},
188
+						Images:     true,
189
+						BuildCache: true,
190
+						Verbose:    true,
184 191
 					},
185
-					expected: system.DiskUsage{
186
-						LayersSize: stepDU.LayersSize,
192
+					expected: client.DiskUsageResult{
193
+						Containers: client.ContainersDiskUsage{Items: []containertypes.Summary{}},
187 194
 						Images:     stepDU.Images,
188 195
 						BuildCache: stepDU.BuildCache,
196
+						Volumes:    client.VolumesDiskUsage{Items: []volume.Volume{}},
189 197
 					},
190 198
 				},
191 199
 				{
192 200
 					doc: "container, volume, build-cache types",
193 201
 					options: client.DiskUsageOptions{
194
-						Types: []system.DiskUsageObject{
195
-							system.ContainerObject,
196
-							system.VolumeObject,
197
-							system.BuildCacheObject,
198
-						},
202
+						Containers: true,
203
+						BuildCache: true,
204
+						Volumes:    true,
205
+						Verbose:    true,
199 206
 					},
200
-					expected: system.DiskUsage{
207
+					expected: client.DiskUsageResult{
201 208
 						Containers: stepDU.Containers,
202
-						Volumes:    stepDU.Volumes,
209
+						Images: client.ImagesDiskUsage{
210
+							Items: []image.Summary{},
211
+						},
203 212
 						BuildCache: stepDU.BuildCache,
213
+						Volumes:    stepDU.Volumes,
204 214
 					},
205 215
 				},
206 216
 				{
207 217
 					doc: "image, volume, build-cache types",
208 218
 					options: client.DiskUsageOptions{
209
-						Types: []system.DiskUsageObject{
210
-							system.ImageObject,
211
-							system.VolumeObject,
212
-							system.BuildCacheObject,
213
-						},
219
+						Images:     true,
220
+						BuildCache: true,
221
+						Volumes:    true,
222
+						Verbose:    true,
214 223
 					},
215
-					expected: system.DiskUsage{
216
-						LayersSize: stepDU.LayersSize,
224
+					expected: client.DiskUsageResult{
225
+						Containers: client.ContainersDiskUsage{
226
+							Items: []containertypes.Summary{},
227
+						},
217 228
 						Images:     stepDU.Images,
218
-						Volumes:    stepDU.Volumes,
219 229
 						BuildCache: stepDU.BuildCache,
230
+						Volumes:    stepDU.Volumes,
220 231
 					},
221 232
 				},
222 233
 				{
223 234
 					doc: "container, image, volume types",
224 235
 					options: client.DiskUsageOptions{
225
-						Types: []system.DiskUsageObject{
226
-							system.ContainerObject,
227
-							system.ImageObject,
228
-							system.VolumeObject,
229
-						},
236
+						Containers: true,
237
+						Images:     true,
238
+						Volumes:    true,
239
+						Verbose:    true,
230 240
 					},
231
-					expected: system.DiskUsage{
232
-						LayersSize: stepDU.LayersSize,
241
+					expected: client.DiskUsageResult{
233 242
 						Containers: stepDU.Containers,
234 243
 						Images:     stepDU.Images,
235
-						Volumes:    stepDU.Volumes,
244
+						BuildCache: client.BuildCacheDiskUsage{
245
+							Items: []build.CacheRecord{},
246
+						},
247
+						Volumes: stepDU.Volumes,
236 248
 					},
237 249
 				},
238 250
 				{
239 251
 					doc: "container, image, volume, build-cache types",
240 252
 					options: client.DiskUsageOptions{
241
-						Types: []system.DiskUsageObject{
242
-							system.ContainerObject,
243
-							system.ImageObject,
244
-							system.VolumeObject,
245
-							system.BuildCacheObject,
246
-						},
253
+						Containers: true,
254
+						Images:     true,
255
+						BuildCache: true,
256
+						Volumes:    true,
257
+						Verbose:    true,
247 258
 					},
248
-					expected: system.DiskUsage{
249
-						LayersSize: stepDU.LayersSize,
259
+					expected: client.DiskUsageResult{
250 260
 						Containers: stepDU.Containers,
251 261
 						Images:     stepDU.Images,
252
-						Volumes:    stepDU.Volumes,
253 262
 						BuildCache: stepDU.BuildCache,
263
+						Volumes:    stepDU.Volumes,
254 264
 					},
255 265
 				},
256 266
 			} {
257 267
new file mode 100644
... ...
@@ -0,0 +1,40 @@
0
+// Code generated by go-swagger; DO NOT EDIT.
1
+
2
+package system
3
+
4
+// This file was generated by the swagger tool.
5
+// Editing this file might prove futile when you re-run the swagger generate command
6
+
7
+import (
8
+	"github.com/moby/moby/api/types/build"
9
+)
10
+
11
+// BuildCacheDiskUsage BuildCacheDiskUsage represents system data usage for build cache resources.
12
+//
13
+// swagger:model BuildCacheDiskUsage
14
+type BuildCacheDiskUsage struct {
15
+
16
+	// Count of active build cache records.
17
+	//
18
+	// Example: 1
19
+	ActiveBuildCacheRecords int64 `json:"ActiveBuildCacheRecords,omitempty"`
20
+
21
+	// List of build cache records.
22
+	//
23
+	Items []*build.CacheRecord `json:"Items,omitempty"`
24
+
25
+	// Disk space that can be reclaimed by removing inactive build cache records.
26
+	//
27
+	// Example: 12345678
28
+	Reclaimable int64 `json:"Reclaimable,omitempty"`
29
+
30
+	// Count of all build cache records.
31
+	//
32
+	// Example: 4
33
+	TotalBuildCacheRecords int64 `json:"TotalBuildCacheRecords,omitempty"`
34
+
35
+	// Disk space in use by build cache records.
36
+	//
37
+	// Example: 98765432
38
+	TotalSize int64 `json:"TotalSize,omitempty"`
39
+}
0 40
new file mode 100644
... ...
@@ -0,0 +1,40 @@
0
+// Code generated by go-swagger; DO NOT EDIT.
1
+
2
+package system
3
+
4
+// This file was generated by the swagger tool.
5
+// Editing this file might prove futile when you re-run the swagger generate command
6
+
7
+import (
8
+	"github.com/moby/moby/api/types/container"
9
+)
10
+
11
+// ContainersDiskUsage ContainersDiskUsage provides system data usage information for container resources.
12
+//
13
+// swagger:model ContainersDiskUsage
14
+type ContainersDiskUsage struct {
15
+
16
+	// Count of active containers.
17
+	//
18
+	// Example: 1
19
+	ActiveContainers int64 `json:"ActiveContainers,omitempty"`
20
+
21
+	// List of container summaries.
22
+	//
23
+	Items []*container.Summary `json:"Items,omitempty"`
24
+
25
+	// Disk space that can be reclaimed by removing inactive containers.
26
+	//
27
+	// Example: 12345678
28
+	Reclaimable int64 `json:"Reclaimable,omitempty"`
29
+
30
+	// Count of all containers.
31
+	//
32
+	// Example: 4
33
+	TotalContainers int64 `json:"TotalContainers,omitempty"`
34
+
35
+	// Disk space in use by containers.
36
+	//
37
+	// Example: 98765432
38
+	TotalSize int64 `json:"TotalSize,omitempty"`
39
+}
... ...
@@ -24,9 +24,27 @@ const (
24 24
 // DiskUsage contains response of Engine API:
25 25
 // GET "/system/df"
26 26
 type DiskUsage struct {
27
-	LayersSize int64
28
-	Images     []*image.Summary
29
-	Containers []*container.Summary
30
-	Volumes    []*volume.Volume
31
-	BuildCache []*build.CacheRecord
27
+	LegacyDiskUsage
28
+
29
+	ImageUsage      *ImagesDiskUsage     `json:"ImageUsage,omitempty"`
30
+	ContainerUsage  *ContainersDiskUsage `json:"ContainerUsage,omitempty"`
31
+	VolumeUsage     *VolumesDiskUsage    `json:"VolumeUsage,omitempty"`
32
+	BuildCacheUsage *BuildCacheDiskUsage `json:"BuildCacheUsage,omitempty"`
33
+}
34
+
35
+type LegacyDiskUsage struct {
36
+	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.TotalSize] instead.
37
+	LayersSize int64 `json:"LayersSize,omitempty"`
38
+
39
+	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.Items] instead.
40
+	Images []*image.Summary `json:"Images,omitempty"`
41
+
42
+	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ContainersDiskUsage.Items] instead.
43
+	Containers []*container.Summary `json:"Containers,omitempty"`
44
+
45
+	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [VolumesDiskUsage.Items] instead.
46
+	Volumes []*volume.Volume `json:"Volumes,omitempty"`
47
+
48
+	// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [BuildCacheDiskUsage.Items] instead.
49
+	BuildCache []*build.CacheRecord `json:"BuildCache,omitempty"`
32 50
 }
33 51
new file mode 100644
... ...
@@ -0,0 +1,40 @@
0
+// Code generated by go-swagger; DO NOT EDIT.
1
+
2
+package system
3
+
4
+// This file was generated by the swagger tool.
5
+// Editing this file might prove futile when you re-run the swagger generate command
6
+
7
+import (
8
+	"github.com/moby/moby/api/types/image"
9
+)
10
+
11
+// ImagesDiskUsage ImagesDiskUsage represents system data usage for image resources.
12
+//
13
+// swagger:model ImagesDiskUsage
14
+type ImagesDiskUsage struct {
15
+
16
+	// Count of active images.
17
+	//
18
+	// Example: 1
19
+	ActiveImages int64 `json:"ActiveImages,omitempty"`
20
+
21
+	// List of image summaries.
22
+	//
23
+	Items []*image.Summary `json:"Items,omitempty"`
24
+
25
+	// Disk space that can be reclaimed by removing unused images.
26
+	//
27
+	// Example: 12345678
28
+	Reclaimable int64 `json:"Reclaimable,omitempty"`
29
+
30
+	// Count of all images.
31
+	//
32
+	// Example: 4
33
+	TotalImages int64 `json:"TotalImages,omitempty"`
34
+
35
+	// Disk space in use by images.
36
+	//
37
+	// Example: 98765432
38
+	TotalSize int64 `json:"TotalSize,omitempty"`
39
+}
0 40
new file mode 100644
... ...
@@ -0,0 +1,40 @@
0
+// Code generated by go-swagger; DO NOT EDIT.
1
+
2
+package system
3
+
4
+// This file was generated by the swagger tool.
5
+// Editing this file might prove futile when you re-run the swagger generate command
6
+
7
+import (
8
+	"github.com/moby/moby/api/types/volume"
9
+)
10
+
11
+// VolumesDiskUsage VolumesDiskUsage represents system data usage for volume resources.
12
+//
13
+// swagger:model VolumesDiskUsage
14
+type VolumesDiskUsage struct {
15
+
16
+	// Count of active volumes.
17
+	//
18
+	// Example: 1
19
+	ActiveVolumes int64 `json:"ActiveVolumes,omitempty"`
20
+
21
+	// List of volumes.
22
+	//
23
+	Items []*volume.Volume `json:"Items,omitempty"`
24
+
25
+	// Disk space that can be reclaimed by removing inactive volumes.
26
+	//
27
+	// Example: 12345678
28
+	Reclaimable int64 `json:"Reclaimable,omitempty"`
29
+
30
+	// Disk space in use by volumes.
31
+	//
32
+	// Example: 98765432
33
+	TotalSize int64 `json:"TotalSize,omitempty"`
34
+
35
+	// Count of all volumes.
36
+	//
37
+	// Example: 4
38
+	TotalVolumes int64 `json:"TotalVolumes,omitempty"`
39
+}
... ...
@@ -4,8 +4,6 @@ import (
4 4
 	"context"
5 5
 	"io"
6 6
 	"net"
7
-
8
-	"github.com/moby/moby/api/types/system"
9 7
 )
10 8
 
11 9
 // APIClient is an interface that clients that talk with a docker server must implement.
... ...
@@ -173,7 +171,7 @@ type SystemAPIClient interface {
173 173
 	Events(ctx context.Context, options EventsListOptions) EventsResult
174 174
 	Info(ctx context.Context, options InfoOptions) (SystemInfoResult, error)
175 175
 	RegistryLogin(ctx context.Context, auth RegistryLoginOptions) (RegistryLoginResult, error)
176
-	DiskUsage(ctx context.Context, options DiskUsageOptions) (system.DiskUsage, error)
176
+	DiskUsage(ctx context.Context, options DiskUsageOptions) (DiskUsageResult, error)
177 177
 	Ping(ctx context.Context, options PingOptions) (PingResult, error)
178 178
 }
179 179
 
... ...
@@ -6,28 +6,248 @@ import (
6 6
 	"fmt"
7 7
 	"net/url"
8 8
 
9
+	"github.com/moby/moby/api/types/build"
10
+	"github.com/moby/moby/api/types/container"
11
+	"github.com/moby/moby/api/types/image"
9 12
 	"github.com/moby/moby/api/types/system"
13
+	"github.com/moby/moby/api/types/volume"
10 14
 )
11 15
 
12
-// DiskUsage requests the current data usage from the daemon
13
-func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (system.DiskUsage, error) {
14
-	var query url.Values
15
-	if len(options.Types) > 0 {
16
-		query = url.Values{}
17
-		for _, t := range options.Types {
18
-			query.Add("type", string(t))
16
+// DiskUsageOptions holds parameters for [Client.DiskUsage] operations.
17
+type DiskUsageOptions struct {
18
+	// Containers controls whether container disk usage should be computed.
19
+	Containers bool
20
+
21
+	// Images controls whether image disk usage should be computed.
22
+	Images bool
23
+
24
+	// BuildCache controls whether build cache disk usage should be computed.
25
+	BuildCache bool
26
+
27
+	// Volumes controls whether volume disk usage should be computed.
28
+	Volumes bool
29
+
30
+	// Verbose enables more detailed disk usage information.
31
+	Verbose bool
32
+}
33
+
34
+// DiskUsageResult is the result of [Client.DiskUsage] operations.
35
+type DiskUsageResult struct {
36
+	// Containers holds container disk usage information.
37
+	Containers ContainersDiskUsage
38
+
39
+	// Images holds image disk usage information.
40
+	Images ImagesDiskUsage
41
+
42
+	// BuildCache holds build cache disk usage information.
43
+	BuildCache BuildCacheDiskUsage
44
+
45
+	// Volumes holds volume disk usage information.
46
+	Volumes VolumesDiskUsage
47
+}
48
+
49
+// ContainersDiskUsage contains disk usage information for containers.
50
+type ContainersDiskUsage struct {
51
+	// ActiveContainers is the number of active containers.
52
+	ActiveContainers int64
53
+
54
+	// TotalContainers is the total number of containers.
55
+	TotalContainers int64
56
+
57
+	// Reclaimable is the amount of disk space that can be reclaimed.
58
+	Reclaimable int64
59
+
60
+	// TotalSize is the total disk space used by all containers.
61
+	TotalSize int64
62
+
63
+	// Items holds detailed information about each container.
64
+	Items []container.Summary
65
+}
66
+
67
+// ImagesDiskUsage contains disk usage information for images.
68
+type ImagesDiskUsage struct {
69
+	// ActiveImages is the number of active images.
70
+	ActiveImages int64
71
+
72
+	// TotalImages is the total number of images.
73
+	TotalImages int64
74
+
75
+	// Reclaimable is the amount of disk space that can be reclaimed.
76
+	Reclaimable int64
77
+
78
+	// TotalSize is the total disk space used by all images.
79
+	TotalSize int64
80
+
81
+	// Items holds detailed information about each image.
82
+	Items []image.Summary
83
+}
84
+
85
+// VolumesDiskUsage contains disk usage information for volumes.
86
+type VolumesDiskUsage struct {
87
+	// ActiveVolumes is the number of active volumes.
88
+	ActiveVolumes int64
89
+
90
+	// TotalVolumes is the total number of volumes.
91
+	TotalVolumes int64
92
+
93
+	// Reclaimable is the amount of disk space that can be reclaimed.
94
+	Reclaimable int64
95
+
96
+	// TotalSize is the total disk space used by all volumes.
97
+	TotalSize int64
98
+
99
+	// Items holds detailed information about each volume.
100
+	Items []volume.Volume
101
+}
102
+
103
+// BuildCacheDiskUsage contains disk usage information for build cache.
104
+type BuildCacheDiskUsage struct {
105
+	// ActiveBuildCacheRecords is the number of active build cache records.
106
+	ActiveBuildCacheRecords int64
107
+
108
+	// TotalBuildCacheRecords is the total number of build cache records.
109
+	TotalBuildCacheRecords int64
110
+
111
+	// Reclaimable is the amount of disk space that can be reclaimed.
112
+	Reclaimable int64
113
+
114
+	// TotalSize is the total disk space used by all build cache records.
115
+	TotalSize int64
116
+
117
+	// Items holds detailed information about each build cache record.
118
+	Items []build.CacheRecord
119
+}
120
+
121
+// DiskUsage requests the current data usage from the daemon.
122
+func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (DiskUsageResult, error) {
123
+	query := url.Values{}
124
+
125
+	for _, t := range []struct {
126
+		flag   bool
127
+		sysObj system.DiskUsageObject
128
+	}{
129
+		{options.Containers, system.ContainerObject},
130
+		{options.Images, system.ImageObject},
131
+		{options.Volumes, system.VolumeObject},
132
+		{options.BuildCache, system.BuildCacheObject},
133
+	} {
134
+		if t.flag {
135
+			query.Add("type", string(t.sysObj))
19 136
 		}
20 137
 	}
21 138
 
139
+	if options.Verbose {
140
+		query.Set("verbose", "1")
141
+	}
142
+
22 143
 	resp, err := cli.get(ctx, "/system/df", query, nil)
23 144
 	defer ensureReaderClosed(resp)
24 145
 	if err != nil {
25
-		return system.DiskUsage{}, err
146
+		return DiskUsageResult{}, err
26 147
 	}
27 148
 
28 149
 	var du system.DiskUsage
29 150
 	if err := json.NewDecoder(resp.Body).Decode(&du); err != nil {
30
-		return system.DiskUsage{}, fmt.Errorf("Error retrieving disk usage: %v", err)
151
+		return DiskUsageResult{}, fmt.Errorf("Error retrieving disk usage: %v", err)
152
+	}
153
+
154
+	var (
155
+		r              DiskUsageResult
156
+		imagesFrom     = []*image.Summary{}
157
+		containersFrom = []*container.Summary{}
158
+		volumesFrom    = []*volume.Volume{}
159
+		buildCacheFrom = []*build.CacheRecord{}
160
+	)
161
+
162
+	if du.ImageUsage != nil {
163
+		r.Images = ImagesDiskUsage{
164
+			ActiveImages: du.ImageUsage.ActiveImages,
165
+			Reclaimable:  du.ImageUsage.Reclaimable,
166
+			TotalImages:  du.ImageUsage.TotalImages,
167
+			TotalSize:    du.ImageUsage.TotalSize,
168
+		}
169
+
170
+		if options.Verbose {
171
+			imagesFrom = du.ImageUsage.Items
172
+		}
173
+	} else {
174
+		// Fallback for legacy response.
175
+		r.Images = ImagesDiskUsage{
176
+			TotalSize: du.LayersSize,
177
+		}
178
+
179
+		if du.Images != nil && options.Verbose {
180
+			imagesFrom = du.Images
181
+		}
182
+	}
183
+
184
+	r.Images.Items = make([]image.Summary, len(imagesFrom))
185
+	for i, ii := range imagesFrom {
186
+		r.Images.Items[i] = *ii
187
+	}
188
+
189
+	if du.ContainerUsage != nil {
190
+		r.Containers = ContainersDiskUsage{
191
+			ActiveContainers: du.ContainerUsage.ActiveContainers,
192
+			Reclaimable:      du.ContainerUsage.Reclaimable,
193
+			TotalContainers:  du.ContainerUsage.TotalContainers,
194
+			TotalSize:        du.ContainerUsage.TotalSize,
195
+		}
196
+
197
+		if options.Verbose {
198
+			containersFrom = du.ContainerUsage.Items
199
+		}
200
+	} else if du.Containers != nil && options.Verbose {
201
+		// Fallback for legacy response.
202
+		containersFrom = du.Containers
31 203
 	}
32
-	return du, nil
204
+
205
+	r.Containers.Items = make([]container.Summary, len(containersFrom))
206
+	for i, c := range containersFrom {
207
+		r.Containers.Items[i] = *c
208
+	}
209
+
210
+	if du.BuildCacheUsage != nil {
211
+		r.BuildCache = BuildCacheDiskUsage{
212
+			ActiveBuildCacheRecords: du.BuildCacheUsage.ActiveBuildCacheRecords,
213
+			Reclaimable:             du.BuildCacheUsage.Reclaimable,
214
+			TotalBuildCacheRecords:  du.BuildCacheUsage.TotalBuildCacheRecords,
215
+			TotalSize:               du.BuildCacheUsage.TotalSize,
216
+		}
217
+
218
+		if options.Verbose {
219
+			buildCacheFrom = du.BuildCacheUsage.Items
220
+		}
221
+	} else if du.BuildCache != nil && options.Verbose {
222
+		// Fallback for legacy response.
223
+		buildCacheFrom = du.BuildCache
224
+	}
225
+
226
+	r.BuildCache.Items = make([]build.CacheRecord, len(buildCacheFrom))
227
+	for i, b := range buildCacheFrom {
228
+		r.BuildCache.Items[i] = *b
229
+	}
230
+
231
+	if du.VolumeUsage != nil {
232
+		r.Volumes = VolumesDiskUsage{
233
+			ActiveVolumes: du.VolumeUsage.ActiveVolumes,
234
+			Reclaimable:   du.VolumeUsage.Reclaimable,
235
+			TotalSize:     du.VolumeUsage.TotalSize,
236
+			TotalVolumes:  du.VolumeUsage.TotalVolumes,
237
+		}
238
+
239
+		if options.Verbose {
240
+			volumesFrom = du.VolumeUsage.Items
241
+		}
242
+	} else if du.Volumes != nil && options.Verbose {
243
+		// Fallback for legacy response.
244
+		volumesFrom = du.Volumes
245
+	}
246
+
247
+	r.Volumes.Items = make([]volume.Volume, len(volumesFrom))
248
+	for i, v := range volumesFrom {
249
+		r.Volumes.Items[i] = *v
250
+	}
251
+
252
+	return r, nil
33 253
 }
34 254
deleted file mode 100644
... ...
@@ -1,10 +0,0 @@
1
-package client
2
-
3
-import "github.com/moby/moby/api/types/system"
4
-
5
-// DiskUsageOptions holds parameters for system disk usage query.
6
-type DiskUsageOptions struct {
7
-	// Types specifies what object types to include in the response. If empty,
8
-	// all object types are returned.
9
-	Types []system.DiskUsageObject
10
-}