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>
This commit is contained in:
Austin Vazquez
2025-10-20 15:11:53 -05:00
parent bb27db85fb
commit a69abdd90d
27 changed files with 1633 additions and 437 deletions

View File

@@ -71,6 +71,13 @@ keywords: "API, Docker, rcli, REST, documentation"
part of the `Resource` requirements.
* `GET /containers/{id}/stats` now returns an `os_type` field to allow platform-
specific handling of the stats.
* `GET /system/df` returns `ImagesUsage`, `ContainersUsage`, `VolumesUsage`, and
`BuildCacheUsage` fields with brief system disk usage data for each system object type.
The endpoint supports the `?verbose=1` query to return verbose system disk usage information.
* Deprecated: `GET /system/df` response fields `LayersSize`, `Images`, `Containers`,
`Volumes`, and `BuildCache` are deprecated in favor of the type specific usage fields.
The legacy fields will not be populated for new API versions that specify the `verbose`
query.
## v1.51 API changes

View File

@@ -2059,6 +2059,47 @@ definitions:
x-nullable: true
$ref: "#/definitions/OCIDescriptor"
ImagesDiskUsage:
type: "object"
description: |
ImagesDiskUsage represents system data usage for image resources.
properties:
ActiveImages:
description: |
Count of active images.
type: "integer"
format: "int64"
example: 1
TotalImages:
description: |
Count of all images.
type: "integer"
format: "int64"
example: 4
Reclaimable:
description: |
Disk space that can be reclaimed by removing unused images.
type: "integer"
format: "int64"
example: 12345678
TotalSize:
description: |
Disk space in use by images.
type: "integer"
format: "int64"
example: 98765432
Items:
description: |
List of image summaries.
type: "array"
x-omitempty: true
items:
x-nullable: true
x-go-type:
type: Summary
import:
package: github.com/moby/moby/api/types/image
AuthConfig:
type: "object"
properties:
@@ -2201,6 +2242,47 @@ definitions:
is set to `-1` if the reference-count is not available.
x-nullable: false
VolumesDiskUsage:
type: "object"
description: |
VolumesDiskUsage represents system data usage for volume resources.
properties:
ActiveVolumes:
description: |
Count of active volumes.
type: "integer"
format: "int64"
example: 1
TotalVolumes:
description: |
Count of all volumes.
type: "integer"
format: "int64"
example: 4
Reclaimable:
description: |
Disk space that can be reclaimed by removing inactive volumes.
type: "integer"
format: "int64"
example: 12345678
TotalSize:
description: |
Disk space in use by volumes.
type: "integer"
format: "int64"
example: 98765432
Items:
description: |
List of volumes.
type: "array"
x-omitempty: true
items:
x-nullable: true
x-go-type:
type: Volume
import:
package: github.com/moby/moby/api/types/volume
VolumeCreateRequest:
description: "Volume configuration"
type: "object"
@@ -2628,6 +2710,8 @@ definitions:
type: "string"
x-omitempty: false
example: "02:42:ac:13:00:02"
x-go-type:
type: HardwareAddr
IPv4Address:
type: "string"
x-omitempty: false
@@ -2772,6 +2856,47 @@ definitions:
type: "integer"
example: 26
BuildCacheDiskUsage:
type: "object"
description: |
BuildCacheDiskUsage represents system data usage for build cache resources.
properties:
ActiveBuildCacheRecords:
description: |
Count of active build cache records.
type: "integer"
format: "int64"
example: 1
TotalBuildCacheRecords:
description: |
Count of all build cache records.
type: "integer"
format: "int64"
example: 4
Reclaimable:
description: |
Disk space that can be reclaimed by removing inactive build cache records.
type: "integer"
format: "int64"
example: 12345678
TotalSize:
description: |
Disk space in use by build cache records.
type: "integer"
format: "int64"
example: 98765432
Items:
description: |
List of build cache records.
type: "array"
x-omitempty: true
items:
x-nullable: true
x-go-type:
type: CacheRecord
import:
package: github.com/moby/moby/api/types/build
ImageID:
type: "object"
description: "Image ID or Digest"
@@ -2914,6 +3039,8 @@ definitions:
MAC address for the endpoint on this network. The network driver might ignore this parameter.
type: "string"
example: "02:42:ac:11:00:04"
x-go-type:
type: HardwareAddr
Aliases:
type: "array"
items:
@@ -5453,6 +5580,47 @@ definitions:
type: "integer"
example: 0
ContainersDiskUsage:
type: "object"
description: |
ContainersDiskUsage provides system data usage information for container resources.
properties:
ActiveContainers:
description: |
Count of active containers.
type: "integer"
format: "int64"
example: 1
TotalContainers:
description: |
Count of all containers.
type: "integer"
format: "int64"
example: 4
Reclaimable:
description: |
Disk space that can be reclaimed by removing inactive containers.
type: "integer"
format: "int64"
example: 12345678
TotalSize:
description: |
Disk space in use by containers.
type: "integer"
format: "int64"
example: 98765432
Items:
description: |
List of container summaries.
type: "array"
x-omitempty: true
items:
x-nullable: true
x-go-type:
type: Summary
import:
package: github.com/moby/moby/api/types/container
Driver:
description: "Driver represents a driver (network, logging, secrets)."
type: "object"
@@ -10332,106 +10500,14 @@ paths:
type: "object"
title: "SystemDataUsageResponse"
properties:
LayersSize:
type: "integer"
format: "int64"
Images:
type: "array"
items:
$ref: "#/definitions/ImageSummary"
Containers:
type: "array"
items:
$ref: "#/definitions/ContainerSummary"
Volumes:
type: "array"
items:
$ref: "#/definitions/Volume"
BuildCache:
type: "array"
items:
$ref: "#/definitions/BuildCache"
example:
LayersSize: 1092588
Images:
-
Id: "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749"
ParentId: ""
RepoTags:
- "busybox:latest"
RepoDigests:
- "busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6"
Created: 1466724217
Size: 1092588
SharedSize: 0
Labels: {}
Containers: 1
Containers:
-
Id: "e575172ed11dc01bfce087fb27bee502db149e1a0fad7c296ad300bbff178148"
Names:
- "/top"
Image: "busybox"
ImageID: "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749"
Command: "top"
Created: 1472592424
Ports: []
SizeRootFs: 1092588
Labels: {}
State: "exited"
Status: "Exited (0) 56 minutes ago"
HostConfig:
NetworkMode: "default"
NetworkSettings:
Networks:
bridge:
IPAMConfig: null
Links: null
Aliases: null
NetworkID: "d687bc59335f0e5c9ee8193e5612e8aee000c8c62ea170cfb99c098f95899d92"
EndpointID: "8ed5115aeaad9abb174f68dcf135b49f11daf597678315231a32ca28441dec6a"
Gateway: "172.18.0.1"
IPAddress: "172.18.0.2"
IPPrefixLen: 16
IPv6Gateway: ""
GlobalIPv6Address: ""
GlobalIPv6PrefixLen: 0
MacAddress: "02:42:ac:12:00:02"
Mounts: []
Volumes:
-
Name: "my-volume"
Driver: "local"
Mountpoint: "/var/lib/docker/volumes/my-volume/_data"
Labels: null
Scope: "local"
Options: null
UsageData:
Size: 10920104
RefCount: 2
BuildCache:
-
ID: "hw53o5aio51xtltp5xjp8v7fx"
Parents: []
Type: "regular"
Description: "pulled from docker.io/library/debian@sha256:234cb88d3020898631af0ccbbcca9a66ae7306ecd30c9720690858c1b007d2a0"
InUse: false
Shared: true
Size: 0
CreatedAt: "2021-06-28T13:31:01.474619385Z"
LastUsedAt: "2021-07-07T22:02:32.738075951Z"
UsageCount: 26
-
ID: "ndlpt0hhvkqcdfkputsk4cq9c"
Parents: ["ndlpt0hhvkqcdfkputsk4cq9c"]
Type: "regular"
Description: "mount / from exec /bin/sh -c echo 'Binary::apt::APT::Keep-Downloaded-Packages \"true\";' > /etc/apt/apt.conf.d/keep-cache"
InUse: false
Shared: true
Size: 51
CreatedAt: "2021-06-28T13:31:03.002625487Z"
LastUsedAt: "2021-07-07T22:02:32.773909517Z"
UsageCount: 26
ImagesDiskUsage:
$ref: "#/definitions/ImagesDiskUsage"
ContainersDiskUsage:
$ref: "#/definitions/ContainersDiskUsage"
VolumesDiskUsage:
$ref: "#/definitions/VolumesDiskUsage"
BuildCacheDiskUsage:
$ref: "#/definitions/BuildCacheDiskUsage"
500:
description: "server error"
schema:
@@ -10446,6 +10522,12 @@ paths:
items:
type: "string"
enum: ["container", "image", "volume", "build-cache"]
- name: "verbose"
in: "query"
description: |
Show detailed information on space usage.
type: "boolean"
default: false
tags: ["System"]
/images/{name}/get:
get:

View File

@@ -2059,6 +2059,47 @@ definitions:
x-nullable: true
$ref: "#/definitions/OCIDescriptor"
ImagesDiskUsage:
type: "object"
description: |
ImagesDiskUsage represents system data usage for image resources.
properties:
ActiveImages:
description: |
Count of active images.
type: "integer"
format: "int64"
example: 1
TotalImages:
description: |
Count of all images.
type: "integer"
format: "int64"
example: 4
Reclaimable:
description: |
Disk space that can be reclaimed by removing unused images.
type: "integer"
format: "int64"
example: 12345678
TotalSize:
description: |
Disk space in use by images.
type: "integer"
format: "int64"
example: 98765432
Items:
description: |
List of image summaries.
type: "array"
x-omitempty: true
items:
x-nullable: true
x-go-type:
type: Summary
import:
package: github.com/moby/moby/api/types/image
AuthConfig:
type: "object"
properties:
@@ -2201,6 +2242,47 @@ definitions:
is set to `-1` if the reference-count is not available.
x-nullable: false
VolumesDiskUsage:
type: "object"
description: |
VolumesDiskUsage represents system data usage for volume resources.
properties:
ActiveVolumes:
description: |
Count of active volumes.
type: "integer"
format: "int64"
example: 1
TotalVolumes:
description: |
Count of all volumes.
type: "integer"
format: "int64"
example: 4
Reclaimable:
description: |
Disk space that can be reclaimed by removing inactive volumes.
type: "integer"
format: "int64"
example: 12345678
TotalSize:
description: |
Disk space in use by volumes.
type: "integer"
format: "int64"
example: 98765432
Items:
description: |
List of volumes.
type: "array"
x-omitempty: true
items:
x-nullable: true
x-go-type:
type: Volume
import:
package: github.com/moby/moby/api/types/volume
VolumeCreateRequest:
description: "Volume configuration"
type: "object"
@@ -2774,6 +2856,47 @@ definitions:
type: "integer"
example: 26
BuildCacheDiskUsage:
type: "object"
description: |
BuildCacheDiskUsage represents system data usage for build cache resources.
properties:
ActiveBuildCacheRecords:
description: |
Count of active build cache records.
type: "integer"
format: "int64"
example: 1
TotalBuildCacheRecords:
description: |
Count of all build cache records.
type: "integer"
format: "int64"
example: 4
Reclaimable:
description: |
Disk space that can be reclaimed by removing inactive build cache records.
type: "integer"
format: "int64"
example: 12345678
TotalSize:
description: |
Disk space in use by build cache records.
type: "integer"
format: "int64"
example: 98765432
Items:
description: |
List of build cache records.
type: "array"
x-omitempty: true
items:
x-nullable: true
x-go-type:
type: CacheRecord
import:
package: github.com/moby/moby/api/types/build
ImageID:
type: "object"
description: "Image ID or Digest"
@@ -5457,6 +5580,47 @@ definitions:
type: "integer"
example: 0
ContainersDiskUsage:
type: "object"
description: |
ContainersDiskUsage provides system data usage information for container resources.
properties:
ActiveContainers:
description: |
Count of active containers.
type: "integer"
format: "int64"
example: 1
TotalContainers:
description: |
Count of all containers.
type: "integer"
format: "int64"
example: 4
Reclaimable:
description: |
Disk space that can be reclaimed by removing inactive containers.
type: "integer"
format: "int64"
example: 12345678
TotalSize:
description: |
Disk space in use by containers.
type: "integer"
format: "int64"
example: 98765432
Items:
description: |
List of container summaries.
type: "array"
x-omitempty: true
items:
x-nullable: true
x-go-type:
type: Summary
import:
package: github.com/moby/moby/api/types/container
Driver:
description: "Driver represents a driver (network, logging, secrets)."
type: "object"
@@ -10336,106 +10500,14 @@ paths:
type: "object"
title: "SystemDataUsageResponse"
properties:
LayersSize:
type: "integer"
format: "int64"
Images:
type: "array"
items:
$ref: "#/definitions/ImageSummary"
Containers:
type: "array"
items:
$ref: "#/definitions/ContainerSummary"
Volumes:
type: "array"
items:
$ref: "#/definitions/Volume"
BuildCache:
type: "array"
items:
$ref: "#/definitions/BuildCache"
example:
LayersSize: 1092588
Images:
-
Id: "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749"
ParentId: ""
RepoTags:
- "busybox:latest"
RepoDigests:
- "busybox@sha256:a59906e33509d14c036c8678d687bd4eec81ed7c4b8ce907b888c607f6a1e0e6"
Created: 1466724217
Size: 1092588
SharedSize: 0
Labels: {}
Containers: 1
Containers:
-
Id: "e575172ed11dc01bfce087fb27bee502db149e1a0fad7c296ad300bbff178148"
Names:
- "/top"
Image: "busybox"
ImageID: "sha256:2b8fd9751c4c0f5dd266fcae00707e67a2545ef34f9a29354585f93dac906749"
Command: "top"
Created: 1472592424
Ports: []
SizeRootFs: 1092588
Labels: {}
State: "exited"
Status: "Exited (0) 56 minutes ago"
HostConfig:
NetworkMode: "default"
NetworkSettings:
Networks:
bridge:
IPAMConfig: null
Links: null
Aliases: null
NetworkID: "d687bc59335f0e5c9ee8193e5612e8aee000c8c62ea170cfb99c098f95899d92"
EndpointID: "8ed5115aeaad9abb174f68dcf135b49f11daf597678315231a32ca28441dec6a"
Gateway: "172.18.0.1"
IPAddress: "172.18.0.2"
IPPrefixLen: 16
IPv6Gateway: ""
GlobalIPv6Address: ""
GlobalIPv6PrefixLen: 0
MacAddress: "02:42:ac:12:00:02"
Mounts: []
Volumes:
-
Name: "my-volume"
Driver: "local"
Mountpoint: "/var/lib/docker/volumes/my-volume/_data"
Labels: null
Scope: "local"
Options: null
UsageData:
Size: 10920104
RefCount: 2
BuildCache:
-
ID: "hw53o5aio51xtltp5xjp8v7fx"
Parents: []
Type: "regular"
Description: "pulled from docker.io/library/debian@sha256:234cb88d3020898631af0ccbbcca9a66ae7306ecd30c9720690858c1b007d2a0"
InUse: false
Shared: true
Size: 0
CreatedAt: "2021-06-28T13:31:01.474619385Z"
LastUsedAt: "2021-07-07T22:02:32.738075951Z"
UsageCount: 26
-
ID: "ndlpt0hhvkqcdfkputsk4cq9c"
Parents: ["ndlpt0hhvkqcdfkputsk4cq9c"]
Type: "regular"
Description: "mount / from exec /bin/sh -c echo 'Binary::apt::APT::Keep-Downloaded-Packages \"true\";' > /etc/apt/apt.conf.d/keep-cache"
InUse: false
Shared: true
Size: 51
CreatedAt: "2021-06-28T13:31:03.002625487Z"
LastUsedAt: "2021-07-07T22:02:32.773909517Z"
UsageCount: 26
ImagesDiskUsage:
$ref: "#/definitions/ImagesDiskUsage"
ContainersDiskUsage:
$ref: "#/definitions/ContainersDiskUsage"
VolumesDiskUsage:
$ref: "#/definitions/VolumesDiskUsage"
BuildCacheDiskUsage:
$ref: "#/definitions/BuildCacheDiskUsage"
500:
description: "server error"
schema:
@@ -10450,6 +10522,12 @@ paths:
items:
type: "string"
enum: ["container", "image", "volume", "build-cache"]
- name: "verbose"
in: "query"
description: |
Show detailed information on space usage.
type: "boolean"
default: false
tags: ["System"]
/images/{name}/get:
get:

View File

@@ -0,0 +1,40 @@
// Code generated by go-swagger; DO NOT EDIT.
package system
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/moby/moby/api/types/build"
)
// BuildCacheDiskUsage BuildCacheDiskUsage represents system data usage for build cache resources.
//
// swagger:model BuildCacheDiskUsage
type BuildCacheDiskUsage struct {
// Count of active build cache records.
//
// Example: 1
ActiveBuildCacheRecords int64 `json:"ActiveBuildCacheRecords,omitempty"`
// List of build cache records.
//
Items []*build.CacheRecord `json:"Items,omitempty"`
// Disk space that can be reclaimed by removing inactive build cache records.
//
// Example: 12345678
Reclaimable int64 `json:"Reclaimable,omitempty"`
// Count of all build cache records.
//
// Example: 4
TotalBuildCacheRecords int64 `json:"TotalBuildCacheRecords,omitempty"`
// Disk space in use by build cache records.
//
// Example: 98765432
TotalSize int64 `json:"TotalSize,omitempty"`
}

View File

@@ -0,0 +1,40 @@
// Code generated by go-swagger; DO NOT EDIT.
package system
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/moby/moby/api/types/container"
)
// ContainersDiskUsage ContainersDiskUsage provides system data usage information for container resources.
//
// swagger:model ContainersDiskUsage
type ContainersDiskUsage struct {
// Count of active containers.
//
// Example: 1
ActiveContainers int64 `json:"ActiveContainers,omitempty"`
// List of container summaries.
//
Items []*container.Summary `json:"Items,omitempty"`
// Disk space that can be reclaimed by removing inactive containers.
//
// Example: 12345678
Reclaimable int64 `json:"Reclaimable,omitempty"`
// Count of all containers.
//
// Example: 4
TotalContainers int64 `json:"TotalContainers,omitempty"`
// Disk space in use by containers.
//
// Example: 98765432
TotalSize int64 `json:"TotalSize,omitempty"`
}

View File

@@ -24,9 +24,27 @@ const (
// DiskUsage contains response of Engine API:
// GET "/system/df"
type DiskUsage struct {
LayersSize int64
Images []*image.Summary
Containers []*container.Summary
Volumes []*volume.Volume
BuildCache []*build.CacheRecord
LegacyDiskUsage
ImageUsage *ImagesDiskUsage `json:"ImageUsage,omitempty"`
ContainerUsage *ContainersDiskUsage `json:"ContainerUsage,omitempty"`
VolumeUsage *VolumesDiskUsage `json:"VolumeUsage,omitempty"`
BuildCacheUsage *BuildCacheDiskUsage `json:"BuildCacheUsage,omitempty"`
}
type LegacyDiskUsage struct {
// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.TotalSize] instead.
LayersSize int64 `json:"LayersSize,omitempty"`
// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.Items] instead.
Images []*image.Summary `json:"Images,omitempty"`
// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ContainersDiskUsage.Items] instead.
Containers []*container.Summary `json:"Containers,omitempty"`
// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [VolumesDiskUsage.Items] instead.
Volumes []*volume.Volume `json:"Volumes,omitempty"`
// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [BuildCacheDiskUsage.Items] instead.
BuildCache []*build.CacheRecord `json:"BuildCache,omitempty"`
}

View File

@@ -0,0 +1,40 @@
// Code generated by go-swagger; DO NOT EDIT.
package system
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/moby/moby/api/types/image"
)
// ImagesDiskUsage ImagesDiskUsage represents system data usage for image resources.
//
// swagger:model ImagesDiskUsage
type ImagesDiskUsage struct {
// Count of active images.
//
// Example: 1
ActiveImages int64 `json:"ActiveImages,omitempty"`
// List of image summaries.
//
Items []*image.Summary `json:"Items,omitempty"`
// Disk space that can be reclaimed by removing unused images.
//
// Example: 12345678
Reclaimable int64 `json:"Reclaimable,omitempty"`
// Count of all images.
//
// Example: 4
TotalImages int64 `json:"TotalImages,omitempty"`
// Disk space in use by images.
//
// Example: 98765432
TotalSize int64 `json:"TotalSize,omitempty"`
}

View File

@@ -0,0 +1,40 @@
// Code generated by go-swagger; DO NOT EDIT.
package system
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/moby/moby/api/types/volume"
)
// VolumesDiskUsage VolumesDiskUsage represents system data usage for volume resources.
//
// swagger:model VolumesDiskUsage
type VolumesDiskUsage struct {
// Count of active volumes.
//
// Example: 1
ActiveVolumes int64 `json:"ActiveVolumes,omitempty"`
// List of volumes.
//
Items []*volume.Volume `json:"Items,omitempty"`
// Disk space that can be reclaimed by removing inactive volumes.
//
// Example: 12345678
Reclaimable int64 `json:"Reclaimable,omitempty"`
// Disk space in use by volumes.
//
// Example: 98765432
TotalSize int64 `json:"TotalSize,omitempty"`
// Count of all volumes.
//
// Example: 4
TotalVolumes int64 `json:"TotalVolumes,omitempty"`
}

View File

@@ -4,8 +4,6 @@ import (
"context"
"io"
"net"
"github.com/moby/moby/api/types/system"
)
// APIClient is an interface that clients that talk with a docker server must implement.
@@ -173,7 +171,7 @@ type SystemAPIClient interface {
Events(ctx context.Context, options EventsListOptions) EventsResult
Info(ctx context.Context, options InfoOptions) (SystemInfoResult, error)
RegistryLogin(ctx context.Context, auth RegistryLoginOptions) (RegistryLoginResult, error)
DiskUsage(ctx context.Context, options DiskUsageOptions) (system.DiskUsage, error)
DiskUsage(ctx context.Context, options DiskUsageOptions) (DiskUsageResult, error)
Ping(ctx context.Context, options PingOptions) (PingResult, error)
}

View File

@@ -29,6 +29,17 @@ func assertRequest(req *http.Request, expMethod string, expectedPath string) err
return nil
}
func assertRequestWithQuery(req *http.Request, expMethod string, expectedPath string, expectedQuery string) error {
if err := assertRequest(req, expMethod, expectedPath); err != nil {
return err
}
q := req.URL.Query().Encode()
if q != expectedQuery {
return fmt.Errorf("expected query '%s', got '%s'", expectedQuery, q)
}
return nil
}
// ensureBody makes sure the response has a Body, using [http.NoBody] if
// none is present, and returns it as a testRoundTripper.
func ensureBody(f func(req *http.Request) (*http.Response, error)) testRoundTripper {

View File

@@ -6,28 +6,248 @@ import (
"fmt"
"net/url"
"github.com/moby/moby/api/types/build"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/system"
"github.com/moby/moby/api/types/volume"
)
// DiskUsage requests the current data usage from the daemon
func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (system.DiskUsage, error) {
var query url.Values
if len(options.Types) > 0 {
query = url.Values{}
for _, t := range options.Types {
query.Add("type", string(t))
// DiskUsageOptions holds parameters for [Client.DiskUsage] operations.
type DiskUsageOptions struct {
// Containers controls whether container disk usage should be computed.
Containers bool
// Images controls whether image disk usage should be computed.
Images bool
// BuildCache controls whether build cache disk usage should be computed.
BuildCache bool
// Volumes controls whether volume disk usage should be computed.
Volumes bool
// Verbose enables more detailed disk usage information.
Verbose bool
}
// DiskUsageResult is the result of [Client.DiskUsage] operations.
type DiskUsageResult struct {
// Containers holds container disk usage information.
Containers ContainersDiskUsage
// Images holds image disk usage information.
Images ImagesDiskUsage
// BuildCache holds build cache disk usage information.
BuildCache BuildCacheDiskUsage
// Volumes holds volume disk usage information.
Volumes VolumesDiskUsage
}
// ContainersDiskUsage contains disk usage information for containers.
type ContainersDiskUsage struct {
// ActiveContainers is the number of active containers.
ActiveContainers int64
// TotalContainers is the total number of containers.
TotalContainers int64
// Reclaimable is the amount of disk space that can be reclaimed.
Reclaimable int64
// TotalSize is the total disk space used by all containers.
TotalSize int64
// Items holds detailed information about each container.
Items []container.Summary
}
// ImagesDiskUsage contains disk usage information for images.
type ImagesDiskUsage struct {
// ActiveImages is the number of active images.
ActiveImages int64
// TotalImages is the total number of images.
TotalImages int64
// Reclaimable is the amount of disk space that can be reclaimed.
Reclaimable int64
// TotalSize is the total disk space used by all images.
TotalSize int64
// Items holds detailed information about each image.
Items []image.Summary
}
// VolumesDiskUsage contains disk usage information for volumes.
type VolumesDiskUsage struct {
// ActiveVolumes is the number of active volumes.
ActiveVolumes int64
// TotalVolumes is the total number of volumes.
TotalVolumes int64
// Reclaimable is the amount of disk space that can be reclaimed.
Reclaimable int64
// TotalSize is the total disk space used by all volumes.
TotalSize int64
// Items holds detailed information about each volume.
Items []volume.Volume
}
// BuildCacheDiskUsage contains disk usage information for build cache.
type BuildCacheDiskUsage struct {
// ActiveBuildCacheRecords is the number of active build cache records.
ActiveBuildCacheRecords int64
// TotalBuildCacheRecords is the total number of build cache records.
TotalBuildCacheRecords int64
// Reclaimable is the amount of disk space that can be reclaimed.
Reclaimable int64
// TotalSize is the total disk space used by all build cache records.
TotalSize int64
// Items holds detailed information about each build cache record.
Items []build.CacheRecord
}
// DiskUsage requests the current data usage from the daemon.
func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (DiskUsageResult, error) {
query := url.Values{}
for _, t := range []struct {
flag bool
sysObj system.DiskUsageObject
}{
{options.Containers, system.ContainerObject},
{options.Images, system.ImageObject},
{options.Volumes, system.VolumeObject},
{options.BuildCache, system.BuildCacheObject},
} {
if t.flag {
query.Add("type", string(t.sysObj))
}
}
if options.Verbose {
query.Set("verbose", "1")
}
resp, err := cli.get(ctx, "/system/df", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return system.DiskUsage{}, err
return DiskUsageResult{}, err
}
var du system.DiskUsage
if err := json.NewDecoder(resp.Body).Decode(&du); err != nil {
return system.DiskUsage{}, fmt.Errorf("Error retrieving disk usage: %v", err)
return DiskUsageResult{}, fmt.Errorf("Error retrieving disk usage: %v", err)
}
return du, nil
var (
r DiskUsageResult
imagesFrom = []*image.Summary{}
containersFrom = []*container.Summary{}
volumesFrom = []*volume.Volume{}
buildCacheFrom = []*build.CacheRecord{}
)
if du.ImageUsage != nil {
r.Images = ImagesDiskUsage{
ActiveImages: du.ImageUsage.ActiveImages,
Reclaimable: du.ImageUsage.Reclaimable,
TotalImages: du.ImageUsage.TotalImages,
TotalSize: du.ImageUsage.TotalSize,
}
if options.Verbose {
imagesFrom = du.ImageUsage.Items
}
} else {
// Fallback for legacy response.
r.Images = ImagesDiskUsage{
TotalSize: du.LayersSize,
}
if du.Images != nil && options.Verbose {
imagesFrom = du.Images
}
}
r.Images.Items = make([]image.Summary, len(imagesFrom))
for i, ii := range imagesFrom {
r.Images.Items[i] = *ii
}
if du.ContainerUsage != nil {
r.Containers = ContainersDiskUsage{
ActiveContainers: du.ContainerUsage.ActiveContainers,
Reclaimable: du.ContainerUsage.Reclaimable,
TotalContainers: du.ContainerUsage.TotalContainers,
TotalSize: du.ContainerUsage.TotalSize,
}
if options.Verbose {
containersFrom = du.ContainerUsage.Items
}
} else if du.Containers != nil && options.Verbose {
// Fallback for legacy response.
containersFrom = du.Containers
}
r.Containers.Items = make([]container.Summary, len(containersFrom))
for i, c := range containersFrom {
r.Containers.Items[i] = *c
}
if du.BuildCacheUsage != nil {
r.BuildCache = BuildCacheDiskUsage{
ActiveBuildCacheRecords: du.BuildCacheUsage.ActiveBuildCacheRecords,
Reclaimable: du.BuildCacheUsage.Reclaimable,
TotalBuildCacheRecords: du.BuildCacheUsage.TotalBuildCacheRecords,
TotalSize: du.BuildCacheUsage.TotalSize,
}
if options.Verbose {
buildCacheFrom = du.BuildCacheUsage.Items
}
} else if du.BuildCache != nil && options.Verbose {
// Fallback for legacy response.
buildCacheFrom = du.BuildCache
}
r.BuildCache.Items = make([]build.CacheRecord, len(buildCacheFrom))
for i, b := range buildCacheFrom {
r.BuildCache.Items[i] = *b
}
if du.VolumeUsage != nil {
r.Volumes = VolumesDiskUsage{
ActiveVolumes: du.VolumeUsage.ActiveVolumes,
Reclaimable: du.VolumeUsage.Reclaimable,
TotalSize: du.VolumeUsage.TotalSize,
TotalVolumes: du.VolumeUsage.TotalVolumes,
}
if options.Verbose {
volumesFrom = du.VolumeUsage.Items
}
} else if du.Volumes != nil && options.Verbose {
// Fallback for legacy response.
volumesFrom = du.Volumes
}
r.Volumes.Items = make([]volume.Volume, len(volumesFrom))
for i, v := range volumesFrom {
r.Volumes.Items[i] = *v
}
return r, nil
}

View File

@@ -1,10 +0,0 @@
package client
import "github.com/moby/moby/api/types/system"
// DiskUsageOptions holds parameters for system disk usage query.
type DiskUsageOptions struct {
// Types specifies what object types to include in the response. If empty,
// all object types are returned.
Types []system.DiskUsageObject
}

View File

@@ -2,10 +2,12 @@ package client
import (
"context"
"fmt"
"net/http"
"testing"
cerrdefs "github.com/containerd/errdefs"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/system"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
@@ -26,13 +28,129 @@ func TestDiskUsage(t *testing.T) {
}
return mockJSONResponse(http.StatusOK, nil, system.DiskUsage{
LayersSize: int64(100),
Images: nil,
Containers: nil,
Volumes: nil,
ImageUsage: &system.ImagesDiskUsage{
ActiveImages: 0,
TotalImages: 0,
Reclaimable: 0,
TotalSize: 4096,
Items: []*image.Summary{},
},
})(req)
}))
assert.NilError(t, err)
_, err = client.DiskUsage(context.Background(), DiskUsageOptions{})
du, err := client.DiskUsage(context.Background(), DiskUsageOptions{})
assert.NilError(t, err)
assert.Equal(t, du.Images.ActiveImages, int64(0))
assert.Equal(t, du.Images.TotalImages, int64(0))
assert.Equal(t, du.Images.Reclaimable, int64(0))
assert.Equal(t, du.Images.TotalSize, int64(4096))
assert.Equal(t, len(du.Images.Items), 0)
}
func TestDiskUsageWithOptions(t *testing.T) {
const expectedURL = "/system/df"
tests := []struct {
options DiskUsageOptions
expectedQuery string
}{
{
options: DiskUsageOptions{
Containers: true,
},
expectedQuery: "type=container",
},
{
options: DiskUsageOptions{
Images: true,
},
expectedQuery: "type=image",
},
{
options: DiskUsageOptions{
Volumes: true,
},
expectedQuery: "type=volume",
},
{
options: DiskUsageOptions{
BuildCache: true,
},
expectedQuery: "type=build-cache",
},
{
options: DiskUsageOptions{
Containers: true,
Images: true,
},
expectedQuery: "type=container&type=image",
},
{
options: DiskUsageOptions{
Containers: true,
Images: true,
Volumes: true,
BuildCache: true,
},
expectedQuery: "type=container&type=image&type=volume&type=build-cache",
},
{
options: DiskUsageOptions{
Containers: true,
Verbose: true,
},
expectedQuery: "type=container&verbose=1",
},
{
options: DiskUsageOptions{
Containers: true,
Images: true,
Volumes: true,
BuildCache: true,
Verbose: true,
},
expectedQuery: "type=container&type=image&type=volume&type=build-cache&verbose=1",
},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("options=%+v", tt.options), func(t *testing.T) {
client, err := NewClientWithOpts(WithMockClient(func(req *http.Request) (*http.Response, error) {
if err := assertRequestWithQuery(req, http.MethodGet, expectedURL, tt.expectedQuery); err != nil {
return nil, err
}
return mockJSONResponse(http.StatusOK, nil, system.DiskUsage{})(req)
}))
assert.NilError(t, err)
_, err = client.DiskUsage(t.Context(), tt.options)
assert.NilError(t, err)
})
}
}
func TestLegacyDiskUsage(t *testing.T) {
const expectedURL = "/system/df"
client, err := NewClientWithOpts(WithMockClient(func(req *http.Request) (*http.Response, error) {
if err := assertRequest(req, http.MethodGet, expectedURL); err != nil {
return nil, err
}
return mockJSONResponse(http.StatusOK, nil, system.DiskUsage{
LegacyDiskUsage: system.LegacyDiskUsage{
LayersSize: 4096,
Images: []*image.Summary{},
},
})(req)
}))
assert.NilError(t, err)
du, err := client.DiskUsage(context.Background(), DiskUsageOptions{})
assert.NilError(t, err)
assert.Equal(t, du.Images.ActiveImages, int64(0))
assert.Equal(t, du.Images.TotalImages, int64(0))
assert.Equal(t, du.Images.Reclaimable, int64(0))
assert.Equal(t, du.Images.TotalSize, int64(4096))
assert.Equal(t, len(du.Images.Items), 0)
}

View File

@@ -34,7 +34,6 @@ import (
"github.com/moby/buildkit/util/tracing"
"github.com/moby/locker"
containertypes "github.com/moby/moby/api/types/container"
imagetypes "github.com/moby/moby/api/types/image"
networktypes "github.com/moby/moby/api/types/network"
registrytypes "github.com/moby/moby/api/types/registry"
"github.com/moby/moby/api/types/swarm"
@@ -134,7 +133,7 @@ type Daemon struct {
seccompProfilePath string
usageContainers singleflight.Group[struct{}, *backend.ContainerDiskUsage]
usageImages singleflight.Group[struct{}, []*imagetypes.Summary]
usageImages singleflight.Group[struct{}, *backend.ImageDiskUsage]
usageVolumes singleflight.Group[struct{}, *backend.VolumeDiskUsage]
usageLayer singleflight.Group[struct{}, int64]

View File

@@ -5,7 +5,6 @@ import (
"fmt"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/v2/daemon/internal/filters"
"github.com/moby/moby/v2/daemon/server/backend"
"github.com/moby/moby/v2/daemon/server/imagebackend"
@@ -15,7 +14,7 @@ import (
// containerDiskUsage obtains information about container data disk usage
// and makes sure that only one calculation is performed at the same time.
func (daemon *Daemon) containerDiskUsage(ctx context.Context) (*backend.ContainerDiskUsage, error) {
func (daemon *Daemon) containerDiskUsage(ctx context.Context, verbose bool) (*backend.ContainerDiskUsage, error) {
res, _, err := daemon.usageContainers.Do(ctx, struct{}{}, func(ctx context.Context) (*backend.ContainerDiskUsage, error) {
// Retrieve container list
containers, err := daemon.Containers(ctx, &backend.ContainerListOptions{
@@ -38,13 +37,23 @@ func (daemon *Daemon) containerDiskUsage(ctx context.Context) (*backend.Containe
ctr.State == container.StateRestarting
}
du := &backend.ContainerDiskUsage{Items: containers}
for _, ctr := range du.Items {
activeCount := int64(len(containers))
du := &backend.ContainerDiskUsage{TotalCount: activeCount}
for _, ctr := range containers {
du.TotalSize += ctr.SizeRw
if !isActive(ctr) {
du.Reclaimable += ctr.SizeRw
activeCount--
}
}
du.ActiveCount = activeCount
if verbose {
du.Items = containers
}
return du, nil
})
return res, err
@@ -52,54 +61,83 @@ func (daemon *Daemon) containerDiskUsage(ctx context.Context) (*backend.Containe
// imageDiskUsage obtains information about image data disk usage from image service
// and makes sure that only one calculation is performed at the same time.
func (daemon *Daemon) imageDiskUsage(ctx context.Context) ([]*image.Summary, error) {
imgs, _, err := daemon.usageImages.Do(ctx, struct{}{}, func(ctx context.Context) ([]*image.Summary, error) {
func (daemon *Daemon) imageDiskUsage(ctx context.Context, verbose bool) (*backend.ImageDiskUsage, error) {
du, _, err := daemon.usageImages.Do(ctx, struct{}{}, func(ctx context.Context) (*backend.ImageDiskUsage, error) {
// Get all top images with extra attributes
imgs, err := daemon.imageService.Images(ctx, imagebackend.ListOptions{
images, err := daemon.imageService.Images(ctx, imagebackend.ListOptions{
Filters: filters.NewArgs(),
SharedSize: true,
})
if err != nil {
return nil, errors.Wrap(err, "failed to retrieve image list")
}
return imgs, nil
reclaimable, _, err := daemon.usageLayer.Do(ctx, struct{}{}, func(ctx context.Context) (int64, error) {
return daemon.imageService.ImageDiskUsage(ctx)
})
if err != nil {
return nil, errors.Wrap(err, "failed to calculate image disk usage")
}
activeCount := int64(len(images))
du := &backend.ImageDiskUsage{TotalCount: activeCount, TotalSize: reclaimable}
for _, i := range images {
if i.Containers == 0 {
activeCount--
if i.Size == -1 || i.SharedSize == -1 {
continue
}
reclaimable -= i.Size - i.SharedSize
}
}
du.Reclaimable = reclaimable
du.ActiveCount = activeCount
if verbose {
du.Items = images
}
return du, nil
})
return imgs, err
return du, err
}
// localVolumesSize obtains information about volume disk usage from volumes service
// and makes sure that only one size calculation is performed at the same time.
func (daemon *Daemon) localVolumesSize(ctx context.Context) (*backend.VolumeDiskUsage, error) {
func (daemon *Daemon) localVolumesSize(ctx context.Context, verbose bool) (*backend.VolumeDiskUsage, error) {
volumes, _, err := daemon.usageVolumes.Do(ctx, struct{}{}, func(ctx context.Context) (*backend.VolumeDiskUsage, error) {
volumes, err := daemon.volumes.LocalVolumesSize(ctx)
if err != nil {
return nil, err
}
du := &backend.VolumeDiskUsage{Items: volumes}
for _, v := range du.Items {
activeCount := int64(len(volumes))
du := &backend.VolumeDiskUsage{TotalCount: activeCount}
for _, v := range volumes {
if v.UsageData.Size != -1 {
if v.UsageData.RefCount == 0 {
du.Reclaimable += v.UsageData.Size
activeCount--
}
du.TotalSize += v.UsageData.Size
}
}
du.ActiveCount = activeCount
if verbose {
du.Items = volumes
}
return du, nil
})
return volumes, err
}
// layerDiskUsage obtains information about layer disk usage from image service
// and makes sure that only one size calculation is performed at the same time.
func (daemon *Daemon) layerDiskUsage(ctx context.Context) (int64, error) {
usage, _, err := daemon.usageLayer.Do(ctx, struct{}{}, func(ctx context.Context) (usage int64, err error) {
return daemon.imageService.ImageDiskUsage(ctx)
})
return usage, err
}
// SystemDiskUsage returns information about the daemon data disk usage.
// Callers must not mutate contents of the returned fields.
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
du := &backend.DiskUsage{}
if opts.Containers {
eg.Go(func() (err error) {
du.Containers, err = daemon.containerDiskUsage(ctx)
du.Containers, err = daemon.containerDiskUsage(ctx, opts.Verbose)
return err
})
}
var (
layersSize int64
images []*image.Summary
)
if opts.Images {
eg.Go(func() (err error) {
images, err = daemon.imageDiskUsage(ctx)
return err
})
eg.Go(func() (err error) {
layersSize, err = daemon.layerDiskUsage(ctx)
du.Images, err = daemon.imageDiskUsage(ctx, opts.Verbose)
return err
})
}
if opts.Volumes {
eg.Go(func() (err error) {
du.Volumes, err = daemon.localVolumesSize(ctx)
du.Volumes, err = daemon.localVolumesSize(ctx, opts.Verbose)
return err
})
}
@@ -139,22 +169,5 @@ func (daemon *Daemon) SystemDiskUsage(ctx context.Context, opts backend.DiskUsag
return nil, err
}
if opts.Images {
reclaimable := layersSize
for _, i := range images {
if i.Containers != 0 {
if i.Size == -1 || i.SharedSize == -1 {
continue
}
reclaimable -= i.Size - i.SharedSize
}
}
du.Images = &backend.ImageDiskUsage{
TotalSize: layersSize,
Reclaimable: reclaimable,
Items: images,
}
}
return du, nil
}

View File

@@ -17,6 +17,9 @@ type DiskUsageOptions struct {
// Volumes controls whether volume disk usage should be computed.
Volumes bool
// Verbose indicates whether to include detailed information.
Verbose bool
}
// DiskUsage contains the information returned by the backend for the
@@ -30,6 +33,8 @@ type DiskUsage struct {
// BuildCacheDiskUsage contains disk usage for the build cache.
type BuildCacheDiskUsage struct {
ActiveCount int64
TotalCount int64
TotalSize int64
Reclaimable int64
Items []*build.CacheRecord
@@ -37,6 +42,8 @@ type BuildCacheDiskUsage struct {
// ContainerDiskUsage contains disk usage for containers.
type ContainerDiskUsage struct {
ActiveCount int64
TotalCount int64
TotalSize int64
Reclaimable int64
Items []*container.Summary
@@ -44,6 +51,8 @@ type ContainerDiskUsage struct {
// ImageDiskUsage contains disk usage for images.
type ImageDiskUsage struct {
ActiveCount int64
TotalCount int64
TotalSize int64
Reclaimable int64
Items []*image.Summary
@@ -51,6 +60,8 @@ type ImageDiskUsage struct {
// VolumeDiskUsage contains disk usage for volumes.
type VolumeDiskUsage struct {
ActiveCount int64
TotalCount int64
TotalSize int64
Reclaimable int64
Items []*volume.Volume

View File

@@ -5,6 +5,7 @@ import (
"encoding/json"
"fmt"
"net/http"
"strconv"
"time"
"github.com/containerd/log"
@@ -161,6 +162,21 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
}
}
// To maintain backwards compatibility with older clients, when communicating with API versions prior to 1.52,
// verbose mode is always enabled. For API 1.52 and onwards, if the "verbose" query parameter is not set,
// assume legacy fields should be included.
var verbose, legacyFields bool
if v := r.Form.Get("verbose"); versions.GreaterThanOrEqualTo(version, "1.52") && v != "" {
var err error
verbose, err = strconv.ParseBool(v)
if err != nil {
return invalidRequestError{Err: fmt.Errorf("invalid value for verbose: %s", v)}
}
} else {
// In versions prior to 1.52, legacy fields were always included.
legacyFields, verbose = true, true
}
eg, ctx := errgroup.WithContext(ctx)
var systemDiskUsage *backend.DiskUsage
@@ -171,6 +187,7 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
Containers: getContainers,
Images: getImages,
Volumes: getVolumes,
Verbose: verbose,
})
return err
})
@@ -197,40 +214,80 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter,
return err
}
var builderSize int64
if versions.LessThan(version, "1.42") {
for _, b := range buildCache {
builderSize += b.Size
}
}
du := backend.DiskUsage{}
if getBuildCache {
du.BuildCache = &backend.BuildCacheDiskUsage{
TotalSize: builderSize,
Items: buildCache,
}
}
if systemDiskUsage != nil {
du.Images = systemDiskUsage.Images
du.Containers = systemDiskUsage.Containers
du.Volumes = systemDiskUsage.Volumes
}
// Use the old struct for the API return value.
var v system.DiskUsage
if du.Images != nil {
v.LayersSize = du.Images.TotalSize
v.Images = du.Images.Items
if systemDiskUsage != nil && systemDiskUsage.Images != nil {
v.ImageUsage = &system.ImagesDiskUsage{
ActiveImages: systemDiskUsage.Images.ActiveCount,
Reclaimable: systemDiskUsage.Images.Reclaimable,
TotalImages: systemDiskUsage.Images.TotalCount,
TotalSize: systemDiskUsage.Images.TotalSize,
}
if legacyFields {
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.
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.
} else if verbose {
v.ImageUsage.Items = systemDiskUsage.Images.Items
}
}
if du.Containers != nil {
v.Containers = du.Containers.Items
if systemDiskUsage != nil && systemDiskUsage.Containers != nil {
v.ContainerUsage = &system.ContainersDiskUsage{
ActiveContainers: systemDiskUsage.Containers.ActiveCount,
Reclaimable: systemDiskUsage.Containers.Reclaimable,
TotalContainers: systemDiskUsage.Containers.TotalCount,
TotalSize: systemDiskUsage.Containers.TotalSize,
}
if legacyFields {
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.
} else if verbose {
v.ContainerUsage.Items = systemDiskUsage.Containers.Items
}
}
if du.Volumes != nil {
v.Volumes = du.Volumes.Items
if systemDiskUsage != nil && systemDiskUsage.Volumes != nil {
v.VolumeUsage = &system.VolumesDiskUsage{
ActiveVolumes: systemDiskUsage.Volumes.ActiveCount,
TotalSize: systemDiskUsage.Volumes.TotalSize,
Reclaimable: systemDiskUsage.Volumes.Reclaimable,
TotalVolumes: systemDiskUsage.Volumes.TotalCount,
}
if legacyFields {
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.
} else if verbose {
v.VolumeUsage.Items = systemDiskUsage.Volumes.Items
}
}
if du.BuildCache != nil {
v.BuildCache = du.BuildCache.Items
if getBuildCache {
v.BuildCacheUsage = &system.BuildCacheDiskUsage{
TotalBuildCacheRecords: int64(len(buildCache)),
}
activeCount := v.BuildCacheUsage.TotalBuildCacheRecords
var totalSize, reclaimable int64
for _, b := range buildCache {
if versions.LessThan(version, "1.42") {
totalSize += b.Size
}
if !b.InUse {
activeCount--
}
if !b.InUse && !b.Shared {
reclaimable += b.Size
}
}
v.BuildCacheUsage.ActiveBuildCacheRecords = activeCount
v.BuildCacheUsage.TotalSize = totalSize
v.BuildCacheUsage.Reclaimable = reclaimable
if legacyFields {
v.BuildCache = buildCache //nolint: staticcheck,SA1019: v.BuildCache is deprecated: kept to maintain backwards compatibility with API < v1.52, use [BuildCacheDiskUsage.Items] instead.
} else if verbose {
v.BuildCacheUsage.Items = buildCache
}
}
return httputils.WriteJSON(w, http.StatusOK, v)
}

View File

@@ -95,6 +95,13 @@ generate_model types/storage <<- 'EOT'
Storage
EOT
generate_model types/system <<- 'EOT'
BuildCacheDiskUsage
ContainersDiskUsage
ImagesDiskUsage
VolumesDiskUsage
EOT
generate_model types/swarm <<- 'EOT'
ServiceCreateResponse
ServiceUpdateResponse

View File

@@ -8,7 +8,6 @@ import (
"github.com/moby/moby/api/types/build"
containertypes "github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/system"
"github.com/moby/moby/api/types/volume"
"github.com/moby/moby/client"
"github.com/moby/moby/v2/integration/internal/container"
@@ -30,78 +29,110 @@ func TestDiskUsage(t *testing.T) {
defer d.Stop(t)
apiClient := d.NewClientT(t)
var stepDU system.DiskUsage
var stepDU client.DiskUsageResult
for _, step := range []struct {
doc string
next func(t *testing.T, prev system.DiskUsage) system.DiskUsage
next func(t *testing.T, prev client.DiskUsageResult) client.DiskUsageResult
}{
{
doc: "empty",
next: func(t *testing.T, _ system.DiskUsage) system.DiskUsage {
du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{})
next: func(t *testing.T, _ client.DiskUsageResult) client.DiskUsageResult {
du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{
Images: true,
Containers: true,
BuildCache: true,
Volumes: true,
Verbose: true,
})
assert.NilError(t, err)
expectedLayersSize := int64(0)
// TODO: Investigate https://github.com/moby/moby/issues/47119
// Make 4096 (block size) also a valid value for zero usage.
if testEnv.UsingSnapshotter() && testEnv.IsRootless() {
if du.LayersSize == 4096 {
expectedLayersSize = du.LayersSize
if du.Images.TotalSize == 4096 {
expectedLayersSize = 4096
}
}
assert.DeepEqual(t, du, system.DiskUsage{
LayersSize: expectedLayersSize,
Images: []*image.Summary{},
Containers: []*containertypes.Summary{},
Volumes: []*volume.Volume{},
BuildCache: []*build.CacheRecord{},
assert.DeepEqual(t, du, client.DiskUsageResult{
Containers: client.ContainersDiskUsage{
Items: []containertypes.Summary{},
},
Images: client.ImagesDiskUsage{
TotalSize: expectedLayersSize,
Items: []image.Summary{},
},
BuildCache: client.BuildCacheDiskUsage{
Items: []build.CacheRecord{},
},
Volumes: client.VolumesDiskUsage{
Items: []volume.Volume{},
},
})
return du
},
},
{
doc: "after LoadBusybox",
next: func(t *testing.T, _ system.DiskUsage) system.DiskUsage {
next: func(t *testing.T, _ client.DiskUsageResult) client.DiskUsageResult {
d.LoadBusybox(ctx, t)
du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{})
du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{
Images: true,
Containers: true,
BuildCache: true,
Volumes: true,
Verbose: true,
})
assert.NilError(t, err)
assert.Assert(t, du.LayersSize > 0)
assert.Equal(t, len(du.Images), 1)
assert.Equal(t, len(du.Images[0].RepoTags), 1)
assert.Check(t, is.Equal(du.Images[0].RepoTags[0], "busybox:latest"))
assert.Assert(t, du.Images.TotalSize > 0)
assert.Equal(t, len(du.Images.Items), 1)
assert.Equal(t, len(du.Images.Items[0].RepoTags), 1)
assert.Check(t, is.Equal(du.Images.Items[0].RepoTags[0], "busybox:latest"))
// Image size is layer size + content size. Content size is included in layers size.
assert.Equal(t, du.Images[0].Size, du.LayersSize)
assert.Equal(t, du.Images.Items[0].Size, du.Images.TotalSize)
return du
},
},
{
doc: "after container.Run",
next: func(t *testing.T, prev system.DiskUsage) system.DiskUsage {
next: func(t *testing.T, prev client.DiskUsageResult) client.DiskUsageResult {
cID := container.Run(ctx, t, apiClient)
du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{})
du, err := apiClient.DiskUsage(ctx, client.DiskUsageOptions{
Images: true,
Containers: true,
BuildCache: true,
Volumes: true,
Verbose: true,
})
assert.NilError(t, err)
assert.Equal(t, len(du.Containers), 1)
assert.Equal(t, len(du.Containers[0].Names), 1)
assert.Assert(t, len(prev.Images) > 0)
assert.Check(t, du.Containers[0].Created >= prev.Images[0].Created)
assert.Equal(t, du.Containers.ActiveContainers, int64(1))
assert.Equal(t, du.Containers.TotalContainers, int64(1))
assert.Equal(t, len(du.Containers.Items), 1)
assert.Equal(t, len(du.Containers.Items[0].Names), 1)
assert.Assert(t, len(prev.Images.Items) > 0)
assert.Check(t, du.Containers.Items[0].Created >= prev.Images.Items[0].Created)
// Additional container layer could add to the size
assert.Check(t, du.LayersSize >= prev.LayersSize)
assert.Check(t, du.Images.TotalSize >= prev.Images.TotalSize)
assert.Equal(t, len(du.Images), 1)
assert.Equal(t, du.Images[0].Containers, prev.Images[0].Containers+1)
assert.Equal(t, du.Images.ActiveImages, int64(1))
assert.Equal(t, du.Images.TotalImages, int64(1))
assert.Equal(t, len(du.Images.Items), 1)
assert.Equal(t, du.Images.Items[0].Containers, prev.Images.Items[0].Containers+1)
assert.Check(t, is.Equal(du.Containers[0].ID, cID))
assert.Check(t, is.Equal(du.Containers[0].Image, "busybox"))
assert.Check(t, is.Equal(du.Containers[0].ImageID, prev.Images[0].ID))
assert.Check(t, is.Equal(du.Containers.Items[0].ID, cID))
assert.Check(t, is.Equal(du.Containers.Items[0].Image, "busybox"))
assert.Check(t, is.Equal(du.Containers.Items[0].ImageID, prev.Images.Items[0].ID))
// ImageManifestDescriptor should NOT be populated.
assert.Check(t, is.Nil(du.Containers[0].ImageManifestDescriptor))
assert.Check(t, is.Nil(du.Containers.Items[0].ImageManifestDescriptor))
return du
},
@@ -114,143 +145,153 @@ func TestDiskUsage(t *testing.T) {
for _, tc := range []struct {
doc string
options client.DiskUsageOptions
expected system.DiskUsage
expected client.DiskUsageResult
}{
{
doc: "container types",
options: client.DiskUsageOptions{
Types: []system.DiskUsageObject{
system.ContainerObject,
},
Containers: true,
Verbose: true,
},
expected: system.DiskUsage{
expected: client.DiskUsageResult{
Containers: stepDU.Containers,
Images: client.ImagesDiskUsage{Items: []image.Summary{}},
BuildCache: client.BuildCacheDiskUsage{Items: []build.CacheRecord{}},
Volumes: client.VolumesDiskUsage{Items: []volume.Volume{}},
},
},
{
doc: "image types",
options: client.DiskUsageOptions{
Types: []system.DiskUsageObject{
system.ImageObject,
},
Images: true,
Verbose: true,
},
expected: system.DiskUsage{
LayersSize: stepDU.LayersSize,
expected: client.DiskUsageResult{
Containers: client.ContainersDiskUsage{Items: []containertypes.Summary{}},
Images: stepDU.Images,
BuildCache: client.BuildCacheDiskUsage{Items: []build.CacheRecord{}},
Volumes: client.VolumesDiskUsage{Items: []volume.Volume{}},
},
},
{
doc: "volume types",
options: client.DiskUsageOptions{
Types: []system.DiskUsageObject{
system.VolumeObject,
},
Volumes: true,
Verbose: true,
},
expected: system.DiskUsage{
Volumes: stepDU.Volumes,
expected: client.DiskUsageResult{
Containers: client.ContainersDiskUsage{Items: []containertypes.Summary{}},
Images: client.ImagesDiskUsage{Items: []image.Summary{}},
BuildCache: client.BuildCacheDiskUsage{Items: []build.CacheRecord{}},
Volumes: stepDU.Volumes,
},
},
{
doc: "build-cache types",
options: client.DiskUsageOptions{
Types: []system.DiskUsageObject{
system.BuildCacheObject,
},
BuildCache: true,
Verbose: true,
},
expected: system.DiskUsage{
expected: client.DiskUsageResult{
Containers: client.ContainersDiskUsage{Items: []containertypes.Summary{}},
Images: client.ImagesDiskUsage{Items: []image.Summary{}},
BuildCache: stepDU.BuildCache,
Volumes: client.VolumesDiskUsage{Items: []volume.Volume{}},
},
},
{
doc: "container, volume types",
options: client.DiskUsageOptions{
Types: []system.DiskUsageObject{
system.ContainerObject,
system.VolumeObject,
},
Containers: true,
Volumes: true,
Verbose: true,
},
expected: system.DiskUsage{
expected: client.DiskUsageResult{
Containers: stepDU.Containers,
Images: client.ImagesDiskUsage{Items: []image.Summary{}},
BuildCache: client.BuildCacheDiskUsage{Items: []build.CacheRecord{}},
Volumes: stepDU.Volumes,
},
},
{
doc: "image, build-cache types",
options: client.DiskUsageOptions{
Types: []system.DiskUsageObject{
system.ImageObject,
system.BuildCacheObject,
},
Images: true,
BuildCache: true,
Verbose: true,
},
expected: system.DiskUsage{
LayersSize: stepDU.LayersSize,
expected: client.DiskUsageResult{
Containers: client.ContainersDiskUsage{Items: []containertypes.Summary{}},
Images: stepDU.Images,
BuildCache: stepDU.BuildCache,
Volumes: client.VolumesDiskUsage{Items: []volume.Volume{}},
},
},
{
doc: "container, volume, build-cache types",
options: client.DiskUsageOptions{
Types: []system.DiskUsageObject{
system.ContainerObject,
system.VolumeObject,
system.BuildCacheObject,
},
Containers: true,
BuildCache: true,
Volumes: true,
Verbose: true,
},
expected: system.DiskUsage{
expected: client.DiskUsageResult{
Containers: stepDU.Containers,
Volumes: stepDU.Volumes,
Images: client.ImagesDiskUsage{
Items: []image.Summary{},
},
BuildCache: stepDU.BuildCache,
Volumes: stepDU.Volumes,
},
},
{
doc: "image, volume, build-cache types",
options: client.DiskUsageOptions{
Types: []system.DiskUsageObject{
system.ImageObject,
system.VolumeObject,
system.BuildCacheObject,
},
Images: true,
BuildCache: true,
Volumes: true,
Verbose: true,
},
expected: system.DiskUsage{
LayersSize: stepDU.LayersSize,
expected: client.DiskUsageResult{
Containers: client.ContainersDiskUsage{
Items: []containertypes.Summary{},
},
Images: stepDU.Images,
Volumes: stepDU.Volumes,
BuildCache: stepDU.BuildCache,
Volumes: stepDU.Volumes,
},
},
{
doc: "container, image, volume types",
options: client.DiskUsageOptions{
Types: []system.DiskUsageObject{
system.ContainerObject,
system.ImageObject,
system.VolumeObject,
},
Containers: true,
Images: true,
Volumes: true,
Verbose: true,
},
expected: system.DiskUsage{
LayersSize: stepDU.LayersSize,
expected: client.DiskUsageResult{
Containers: stepDU.Containers,
Images: stepDU.Images,
Volumes: stepDU.Volumes,
BuildCache: client.BuildCacheDiskUsage{
Items: []build.CacheRecord{},
},
Volumes: stepDU.Volumes,
},
},
{
doc: "container, image, volume, build-cache types",
options: client.DiskUsageOptions{
Types: []system.DiskUsageObject{
system.ContainerObject,
system.ImageObject,
system.VolumeObject,
system.BuildCacheObject,
},
Containers: true,
Images: true,
BuildCache: true,
Volumes: true,
Verbose: true,
},
expected: system.DiskUsage{
LayersSize: stepDU.LayersSize,
expected: client.DiskUsageResult{
Containers: stepDU.Containers,
Images: stepDU.Images,
Volumes: stepDU.Volumes,
BuildCache: stepDU.BuildCache,
Volumes: stepDU.Volumes,
},
},
} {

View File

@@ -0,0 +1,40 @@
// Code generated by go-swagger; DO NOT EDIT.
package system
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/moby/moby/api/types/build"
)
// BuildCacheDiskUsage BuildCacheDiskUsage represents system data usage for build cache resources.
//
// swagger:model BuildCacheDiskUsage
type BuildCacheDiskUsage struct {
// Count of active build cache records.
//
// Example: 1
ActiveBuildCacheRecords int64 `json:"ActiveBuildCacheRecords,omitempty"`
// List of build cache records.
//
Items []*build.CacheRecord `json:"Items,omitempty"`
// Disk space that can be reclaimed by removing inactive build cache records.
//
// Example: 12345678
Reclaimable int64 `json:"Reclaimable,omitempty"`
// Count of all build cache records.
//
// Example: 4
TotalBuildCacheRecords int64 `json:"TotalBuildCacheRecords,omitempty"`
// Disk space in use by build cache records.
//
// Example: 98765432
TotalSize int64 `json:"TotalSize,omitempty"`
}

View File

@@ -0,0 +1,40 @@
// Code generated by go-swagger; DO NOT EDIT.
package system
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/moby/moby/api/types/container"
)
// ContainersDiskUsage ContainersDiskUsage provides system data usage information for container resources.
//
// swagger:model ContainersDiskUsage
type ContainersDiskUsage struct {
// Count of active containers.
//
// Example: 1
ActiveContainers int64 `json:"ActiveContainers,omitempty"`
// List of container summaries.
//
Items []*container.Summary `json:"Items,omitempty"`
// Disk space that can be reclaimed by removing inactive containers.
//
// Example: 12345678
Reclaimable int64 `json:"Reclaimable,omitempty"`
// Count of all containers.
//
// Example: 4
TotalContainers int64 `json:"TotalContainers,omitempty"`
// Disk space in use by containers.
//
// Example: 98765432
TotalSize int64 `json:"TotalSize,omitempty"`
}

View File

@@ -24,9 +24,27 @@ const (
// DiskUsage contains response of Engine API:
// GET "/system/df"
type DiskUsage struct {
LayersSize int64
Images []*image.Summary
Containers []*container.Summary
Volumes []*volume.Volume
BuildCache []*build.CacheRecord
LegacyDiskUsage
ImageUsage *ImagesDiskUsage `json:"ImageUsage,omitempty"`
ContainerUsage *ContainersDiskUsage `json:"ContainerUsage,omitempty"`
VolumeUsage *VolumesDiskUsage `json:"VolumeUsage,omitempty"`
BuildCacheUsage *BuildCacheDiskUsage `json:"BuildCacheUsage,omitempty"`
}
type LegacyDiskUsage struct {
// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.TotalSize] instead.
LayersSize int64 `json:"LayersSize,omitempty"`
// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ImagesDiskUsage.Items] instead.
Images []*image.Summary `json:"Images,omitempty"`
// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [ContainersDiskUsage.Items] instead.
Containers []*container.Summary `json:"Containers,omitempty"`
// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [VolumesDiskUsage.Items] instead.
Volumes []*volume.Volume `json:"Volumes,omitempty"`
// Deprecated: kept to maintain backwards compatibility with API < v1.52, use [BuildCacheDiskUsage.Items] instead.
BuildCache []*build.CacheRecord `json:"BuildCache,omitempty"`
}

View File

@@ -0,0 +1,40 @@
// Code generated by go-swagger; DO NOT EDIT.
package system
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/moby/moby/api/types/image"
)
// ImagesDiskUsage ImagesDiskUsage represents system data usage for image resources.
//
// swagger:model ImagesDiskUsage
type ImagesDiskUsage struct {
// Count of active images.
//
// Example: 1
ActiveImages int64 `json:"ActiveImages,omitempty"`
// List of image summaries.
//
Items []*image.Summary `json:"Items,omitempty"`
// Disk space that can be reclaimed by removing unused images.
//
// Example: 12345678
Reclaimable int64 `json:"Reclaimable,omitempty"`
// Count of all images.
//
// Example: 4
TotalImages int64 `json:"TotalImages,omitempty"`
// Disk space in use by images.
//
// Example: 98765432
TotalSize int64 `json:"TotalSize,omitempty"`
}

View File

@@ -0,0 +1,40 @@
// Code generated by go-swagger; DO NOT EDIT.
package system
// This file was generated by the swagger tool.
// Editing this file might prove futile when you re-run the swagger generate command
import (
"github.com/moby/moby/api/types/volume"
)
// VolumesDiskUsage VolumesDiskUsage represents system data usage for volume resources.
//
// swagger:model VolumesDiskUsage
type VolumesDiskUsage struct {
// Count of active volumes.
//
// Example: 1
ActiveVolumes int64 `json:"ActiveVolumes,omitempty"`
// List of volumes.
//
Items []*volume.Volume `json:"Items,omitempty"`
// Disk space that can be reclaimed by removing inactive volumes.
//
// Example: 12345678
Reclaimable int64 `json:"Reclaimable,omitempty"`
// Disk space in use by volumes.
//
// Example: 98765432
TotalSize int64 `json:"TotalSize,omitempty"`
// Count of all volumes.
//
// Example: 4
TotalVolumes int64 `json:"TotalVolumes,omitempty"`
}

View File

@@ -4,8 +4,6 @@ import (
"context"
"io"
"net"
"github.com/moby/moby/api/types/system"
)
// APIClient is an interface that clients that talk with a docker server must implement.
@@ -173,7 +171,7 @@ type SystemAPIClient interface {
Events(ctx context.Context, options EventsListOptions) EventsResult
Info(ctx context.Context, options InfoOptions) (SystemInfoResult, error)
RegistryLogin(ctx context.Context, auth RegistryLoginOptions) (RegistryLoginResult, error)
DiskUsage(ctx context.Context, options DiskUsageOptions) (system.DiskUsage, error)
DiskUsage(ctx context.Context, options DiskUsageOptions) (DiskUsageResult, error)
Ping(ctx context.Context, options PingOptions) (PingResult, error)
}

View File

@@ -6,28 +6,248 @@ import (
"fmt"
"net/url"
"github.com/moby/moby/api/types/build"
"github.com/moby/moby/api/types/container"
"github.com/moby/moby/api/types/image"
"github.com/moby/moby/api/types/system"
"github.com/moby/moby/api/types/volume"
)
// DiskUsage requests the current data usage from the daemon
func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (system.DiskUsage, error) {
var query url.Values
if len(options.Types) > 0 {
query = url.Values{}
for _, t := range options.Types {
query.Add("type", string(t))
// DiskUsageOptions holds parameters for [Client.DiskUsage] operations.
type DiskUsageOptions struct {
// Containers controls whether container disk usage should be computed.
Containers bool
// Images controls whether image disk usage should be computed.
Images bool
// BuildCache controls whether build cache disk usage should be computed.
BuildCache bool
// Volumes controls whether volume disk usage should be computed.
Volumes bool
// Verbose enables more detailed disk usage information.
Verbose bool
}
// DiskUsageResult is the result of [Client.DiskUsage] operations.
type DiskUsageResult struct {
// Containers holds container disk usage information.
Containers ContainersDiskUsage
// Images holds image disk usage information.
Images ImagesDiskUsage
// BuildCache holds build cache disk usage information.
BuildCache BuildCacheDiskUsage
// Volumes holds volume disk usage information.
Volumes VolumesDiskUsage
}
// ContainersDiskUsage contains disk usage information for containers.
type ContainersDiskUsage struct {
// ActiveContainers is the number of active containers.
ActiveContainers int64
// TotalContainers is the total number of containers.
TotalContainers int64
// Reclaimable is the amount of disk space that can be reclaimed.
Reclaimable int64
// TotalSize is the total disk space used by all containers.
TotalSize int64
// Items holds detailed information about each container.
Items []container.Summary
}
// ImagesDiskUsage contains disk usage information for images.
type ImagesDiskUsage struct {
// ActiveImages is the number of active images.
ActiveImages int64
// TotalImages is the total number of images.
TotalImages int64
// Reclaimable is the amount of disk space that can be reclaimed.
Reclaimable int64
// TotalSize is the total disk space used by all images.
TotalSize int64
// Items holds detailed information about each image.
Items []image.Summary
}
// VolumesDiskUsage contains disk usage information for volumes.
type VolumesDiskUsage struct {
// ActiveVolumes is the number of active volumes.
ActiveVolumes int64
// TotalVolumes is the total number of volumes.
TotalVolumes int64
// Reclaimable is the amount of disk space that can be reclaimed.
Reclaimable int64
// TotalSize is the total disk space used by all volumes.
TotalSize int64
// Items holds detailed information about each volume.
Items []volume.Volume
}
// BuildCacheDiskUsage contains disk usage information for build cache.
type BuildCacheDiskUsage struct {
// ActiveBuildCacheRecords is the number of active build cache records.
ActiveBuildCacheRecords int64
// TotalBuildCacheRecords is the total number of build cache records.
TotalBuildCacheRecords int64
// Reclaimable is the amount of disk space that can be reclaimed.
Reclaimable int64
// TotalSize is the total disk space used by all build cache records.
TotalSize int64
// Items holds detailed information about each build cache record.
Items []build.CacheRecord
}
// DiskUsage requests the current data usage from the daemon.
func (cli *Client) DiskUsage(ctx context.Context, options DiskUsageOptions) (DiskUsageResult, error) {
query := url.Values{}
for _, t := range []struct {
flag bool
sysObj system.DiskUsageObject
}{
{options.Containers, system.ContainerObject},
{options.Images, system.ImageObject},
{options.Volumes, system.VolumeObject},
{options.BuildCache, system.BuildCacheObject},
} {
if t.flag {
query.Add("type", string(t.sysObj))
}
}
if options.Verbose {
query.Set("verbose", "1")
}
resp, err := cli.get(ctx, "/system/df", query, nil)
defer ensureReaderClosed(resp)
if err != nil {
return system.DiskUsage{}, err
return DiskUsageResult{}, err
}
var du system.DiskUsage
if err := json.NewDecoder(resp.Body).Decode(&du); err != nil {
return system.DiskUsage{}, fmt.Errorf("Error retrieving disk usage: %v", err)
return DiskUsageResult{}, fmt.Errorf("Error retrieving disk usage: %v", err)
}
return du, nil
var (
r DiskUsageResult
imagesFrom = []*image.Summary{}
containersFrom = []*container.Summary{}
volumesFrom = []*volume.Volume{}
buildCacheFrom = []*build.CacheRecord{}
)
if du.ImageUsage != nil {
r.Images = ImagesDiskUsage{
ActiveImages: du.ImageUsage.ActiveImages,
Reclaimable: du.ImageUsage.Reclaimable,
TotalImages: du.ImageUsage.TotalImages,
TotalSize: du.ImageUsage.TotalSize,
}
if options.Verbose {
imagesFrom = du.ImageUsage.Items
}
} else {
// Fallback for legacy response.
r.Images = ImagesDiskUsage{
TotalSize: du.LayersSize,
}
if du.Images != nil && options.Verbose {
imagesFrom = du.Images
}
}
r.Images.Items = make([]image.Summary, len(imagesFrom))
for i, ii := range imagesFrom {
r.Images.Items[i] = *ii
}
if du.ContainerUsage != nil {
r.Containers = ContainersDiskUsage{
ActiveContainers: du.ContainerUsage.ActiveContainers,
Reclaimable: du.ContainerUsage.Reclaimable,
TotalContainers: du.ContainerUsage.TotalContainers,
TotalSize: du.ContainerUsage.TotalSize,
}
if options.Verbose {
containersFrom = du.ContainerUsage.Items
}
} else if du.Containers != nil && options.Verbose {
// Fallback for legacy response.
containersFrom = du.Containers
}
r.Containers.Items = make([]container.Summary, len(containersFrom))
for i, c := range containersFrom {
r.Containers.Items[i] = *c
}
if du.BuildCacheUsage != nil {
r.BuildCache = BuildCacheDiskUsage{
ActiveBuildCacheRecords: du.BuildCacheUsage.ActiveBuildCacheRecords,
Reclaimable: du.BuildCacheUsage.Reclaimable,
TotalBuildCacheRecords: du.BuildCacheUsage.TotalBuildCacheRecords,
TotalSize: du.BuildCacheUsage.TotalSize,
}
if options.Verbose {
buildCacheFrom = du.BuildCacheUsage.Items
}
} else if du.BuildCache != nil && options.Verbose {
// Fallback for legacy response.
buildCacheFrom = du.BuildCache
}
r.BuildCache.Items = make([]build.CacheRecord, len(buildCacheFrom))
for i, b := range buildCacheFrom {
r.BuildCache.Items[i] = *b
}
if du.VolumeUsage != nil {
r.Volumes = VolumesDiskUsage{
ActiveVolumes: du.VolumeUsage.ActiveVolumes,
Reclaimable: du.VolumeUsage.Reclaimable,
TotalSize: du.VolumeUsage.TotalSize,
TotalVolumes: du.VolumeUsage.TotalVolumes,
}
if options.Verbose {
volumesFrom = du.VolumeUsage.Items
}
} else if du.Volumes != nil && options.Verbose {
// Fallback for legacy response.
volumesFrom = du.Volumes
}
r.Volumes.Items = make([]volume.Volume, len(volumesFrom))
for i, v := range volumesFrom {
r.Volumes.Items[i] = *v
}
return r, nil
}

View File

@@ -1,10 +0,0 @@
package client
import "github.com/moby/moby/api/types/system"
// DiskUsageOptions holds parameters for system disk usage query.
type DiskUsageOptions struct {
// Types specifies what object types to include in the response. If empty,
// all object types are returned.
Types []system.DiskUsageObject
}