mirror of
https://github.com/moby/moby.git
synced 2026-01-11 18:51:37 +00:00
client/system_disk_usage.go:275:3: missing cases in switch of type container.ContainerState: container.StateCreated, container.StateRemoving, container.StateExited, container.StateDead (exhaustive)
switch c.State {
^
Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
335 lines
8.1 KiB
Go
335 lines
8.1 KiB
Go
package client
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/url"
|
|
"slices"
|
|
|
|
"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"
|
|
"github.com/moby/moby/client/pkg/versions"
|
|
)
|
|
|
|
// 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 {
|
|
// ActiveCount is the number of active containers.
|
|
ActiveCount int64
|
|
|
|
// TotalCount is the total number of containers.
|
|
TotalCount 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 {
|
|
// ActiveCount is the number of active images.
|
|
ActiveCount int64
|
|
|
|
// TotalCount is the total number of images.
|
|
TotalCount 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 {
|
|
// ActiveCount is the number of active volumes.
|
|
ActiveCount int64
|
|
|
|
// TotalCount is the total number of volumes.
|
|
TotalCount 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 {
|
|
// ActiveCount is the number of active build cache records.
|
|
ActiveCount int64
|
|
|
|
// TotalCount is the total number of build cache records.
|
|
TotalCount 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 DiskUsageResult{}, err
|
|
}
|
|
|
|
if versions.LessThan(cli.version, "1.52") {
|
|
// Generate result from a legacy response.
|
|
var du legacyDiskUsage
|
|
if err := json.NewDecoder(resp.Body).Decode(&du); err != nil {
|
|
return DiskUsageResult{}, fmt.Errorf("retrieving disk usage: %v", err)
|
|
}
|
|
|
|
return diskUsageResultFromLegacyAPI(&du), nil
|
|
}
|
|
|
|
var du system.DiskUsage
|
|
if err := json.NewDecoder(resp.Body).Decode(&du); err != nil {
|
|
return DiskUsageResult{}, fmt.Errorf("retrieving disk usage: %v", err)
|
|
}
|
|
|
|
var r DiskUsageResult
|
|
if idu := du.ImageUsage; idu != nil {
|
|
r.Images = ImagesDiskUsage{
|
|
ActiveCount: idu.ActiveCount,
|
|
Reclaimable: idu.Reclaimable,
|
|
TotalCount: idu.TotalCount,
|
|
TotalSize: idu.TotalSize,
|
|
}
|
|
|
|
if options.Verbose {
|
|
r.Images.Items = slices.Clone(idu.Items)
|
|
}
|
|
}
|
|
|
|
if cdu := du.ContainerUsage; cdu != nil {
|
|
r.Containers = ContainersDiskUsage{
|
|
ActiveCount: cdu.ActiveCount,
|
|
Reclaimable: cdu.Reclaimable,
|
|
TotalCount: cdu.TotalCount,
|
|
TotalSize: cdu.TotalSize,
|
|
}
|
|
|
|
if options.Verbose {
|
|
r.Containers.Items = slices.Clone(cdu.Items)
|
|
}
|
|
}
|
|
|
|
if bdu := du.BuildCacheUsage; bdu != nil {
|
|
r.BuildCache = BuildCacheDiskUsage{
|
|
ActiveCount: bdu.ActiveCount,
|
|
Reclaimable: bdu.Reclaimable,
|
|
TotalCount: bdu.TotalCount,
|
|
TotalSize: bdu.TotalSize,
|
|
}
|
|
|
|
if options.Verbose {
|
|
r.BuildCache.Items = slices.Clone(bdu.Items)
|
|
}
|
|
}
|
|
|
|
if vdu := du.VolumeUsage; vdu != nil {
|
|
r.Volumes = VolumesDiskUsage{
|
|
ActiveCount: vdu.ActiveCount,
|
|
Reclaimable: vdu.Reclaimable,
|
|
TotalCount: vdu.TotalCount,
|
|
TotalSize: vdu.TotalSize,
|
|
}
|
|
|
|
if options.Verbose {
|
|
r.Volumes.Items = slices.Clone(vdu.Items)
|
|
}
|
|
}
|
|
|
|
return r, nil
|
|
}
|
|
|
|
// legacyDiskUsage is the response as was used by API < v1.52.
|
|
type legacyDiskUsage struct {
|
|
LayersSize int64 `json:"LayersSize,omitempty"`
|
|
Images []image.Summary `json:"Images,omitzero"`
|
|
Containers []container.Summary `json:"Containers,omitzero"`
|
|
Volumes []volume.Volume `json:"Volumes,omitzero"`
|
|
BuildCache []build.CacheRecord `json:"BuildCache,omitzero"`
|
|
}
|
|
|
|
func diskUsageResultFromLegacyAPI(du *legacyDiskUsage) DiskUsageResult {
|
|
return DiskUsageResult{
|
|
Images: imageDiskUsageFromLegacyAPI(du),
|
|
Containers: containerDiskUsageFromLegacyAPI(du),
|
|
BuildCache: buildCacheDiskUsageFromLegacyAPI(du),
|
|
Volumes: volumeDiskUsageFromLegacyAPI(du),
|
|
}
|
|
}
|
|
|
|
func imageDiskUsageFromLegacyAPI(du *legacyDiskUsage) ImagesDiskUsage {
|
|
idu := ImagesDiskUsage{
|
|
TotalSize: du.LayersSize,
|
|
TotalCount: int64(len(du.Images)),
|
|
Items: du.Images,
|
|
}
|
|
|
|
var used int64
|
|
for _, i := range idu.Items {
|
|
if i.Containers > 0 {
|
|
idu.ActiveCount++
|
|
|
|
if i.Size == -1 || i.SharedSize == -1 {
|
|
continue
|
|
}
|
|
used += (i.Size - i.SharedSize)
|
|
}
|
|
}
|
|
|
|
if idu.TotalCount > 0 {
|
|
idu.Reclaimable = idu.TotalSize - used
|
|
}
|
|
|
|
return idu
|
|
}
|
|
|
|
func containerDiskUsageFromLegacyAPI(du *legacyDiskUsage) ContainersDiskUsage {
|
|
cdu := ContainersDiskUsage{
|
|
TotalCount: int64(len(du.Containers)),
|
|
Items: du.Containers,
|
|
}
|
|
|
|
var used int64
|
|
for _, c := range cdu.Items {
|
|
cdu.TotalSize += c.SizeRw
|
|
switch c.State {
|
|
case container.StateRunning, container.StatePaused, container.StateRestarting:
|
|
cdu.ActiveCount++
|
|
used += c.SizeRw
|
|
case container.StateCreated, container.StateRemoving, container.StateExited, container.StateDead:
|
|
// not active
|
|
}
|
|
}
|
|
|
|
cdu.Reclaimable = cdu.TotalSize - used
|
|
return cdu
|
|
}
|
|
|
|
func buildCacheDiskUsageFromLegacyAPI(du *legacyDiskUsage) BuildCacheDiskUsage {
|
|
bdu := BuildCacheDiskUsage{
|
|
TotalCount: int64(len(du.BuildCache)),
|
|
Items: du.BuildCache,
|
|
}
|
|
|
|
var used int64
|
|
for _, b := range du.BuildCache {
|
|
if !b.Shared {
|
|
bdu.TotalSize += b.Size
|
|
}
|
|
|
|
if b.InUse {
|
|
bdu.ActiveCount++
|
|
if !b.Shared {
|
|
used += b.Size
|
|
}
|
|
}
|
|
}
|
|
|
|
bdu.Reclaimable = bdu.TotalSize - used
|
|
return bdu
|
|
}
|
|
|
|
func volumeDiskUsageFromLegacyAPI(du *legacyDiskUsage) VolumesDiskUsage {
|
|
vdu := VolumesDiskUsage{
|
|
TotalCount: int64(len(du.Volumes)),
|
|
Items: du.Volumes,
|
|
}
|
|
|
|
var used int64
|
|
for _, v := range vdu.Items {
|
|
// Ignore volumes with no usage data
|
|
if v.UsageData != nil {
|
|
if v.UsageData.RefCount > 0 {
|
|
vdu.ActiveCount++
|
|
used += v.UsageData.Size
|
|
}
|
|
if v.UsageData.Size > 0 {
|
|
vdu.TotalSize += v.UsageData.Size
|
|
}
|
|
}
|
|
}
|
|
|
|
vdu.Reclaimable = vdu.TotalSize - used
|
|
return vdu
|
|
}
|