From 8d0dc6902788f36254bde052e867bdea98c4d42e Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Thu, 1 Sep 2022 10:30:34 +0200 Subject: [PATCH] implement docker system df Signed-off-by: Nicolas De Loof --- api/server/router/system/system_routes.go | 2 +- daemon/containerd/service.go | 51 +++++++++++++++++++++-- daemon/images/service.go | 7 ++-- 3 files changed, 52 insertions(+), 8 deletions(-) diff --git a/api/server/router/system/system_routes.go b/api/server/router/system/system_routes.go index 504da5cb69..e918215fdb 100644 --- a/api/server/router/system/system_routes.go +++ b/api/server/router/system/system_routes.go @@ -116,7 +116,7 @@ func (s *systemRouter) getDiskUsage(ctx context.Context, w http.ResponseWriter, var getContainers, getImages, getVolumes, getBuildCache bool typeStrs, ok := r.Form["type"] if versions.LessThan(version, "1.42") || !ok { - getContainers, getImages, getVolumes, getBuildCache = true, true, true, true + getContainers, getImages, getVolumes, getBuildCache = true, true, true, s.builder != nil } else { for _, typ := range typeStrs { switch types.DiskUsageObject(typ) { diff --git a/daemon/containerd/service.go b/daemon/containerd/service.go index 2f09cdfe8f..04960bcb55 100644 --- a/daemon/containerd/service.go +++ b/daemon/containerd/service.go @@ -2,22 +2,26 @@ package containerd import ( "context" - "errors" "github.com/containerd/containerd" "github.com/containerd/containerd/plugin" + "github.com/containerd/containerd/snapshots" "github.com/docker/docker/api/types" + "github.com/docker/docker/api/types/filters" "github.com/docker/docker/container" "github.com/docker/docker/daemon/images" "github.com/docker/docker/errdefs" "github.com/docker/docker/image" "github.com/docker/docker/layer" + "github.com/pkg/errors" + "golang.org/x/sync/singleflight" ) // ImageService implements daemon.ImageService type ImageService struct { client *containerd.Client snapshotter string + usage singleflight.Group } // NewService creates a new ImageService. @@ -101,12 +105,53 @@ func (i *ImageService) ReleaseLayer(rwlayer layer.RWLayer) error { // LayerDiskUsage returns the number of bytes used by layer stores // called from disk_usage.go func (i *ImageService) LayerDiskUsage(ctx context.Context) (int64, error) { - return 0, errdefs.NotImplemented(errors.New("not implemented")) + ch := i.usage.DoChan("LayerDiskUsage", func() (interface{}, error) { + var allLayersSize int64 + snapshotter := i.client.SnapshotService(i.snapshotter) + snapshotter.Walk(ctx, func(ctx context.Context, info snapshots.Info) error { + usage, err := snapshotter.Usage(ctx, info.Name) + if err != nil { + return err + } + allLayersSize += usage.Size + return nil + }) + return allLayersSize, nil + }) + select { + case <-ctx.Done(): + return 0, ctx.Err() + case res := <-ch: + if res.Err != nil { + return 0, res.Err + } + return res.Val.(int64), nil + } } // ImageDiskUsage returns information about image data disk usage. func (i *ImageService) ImageDiskUsage(ctx context.Context) ([]*types.ImageSummary, error) { - return nil, errdefs.NotImplemented(errors.New("not implemented")) + ch := i.usage.DoChan("ImageDiskUsage", func() (interface{}, error) { + // Get all top images with extra attributes + imgs, err := i.Images(ctx, types.ImageListOptions{ + Filters: filters.NewArgs(), + SharedSize: true, + ContainerCount: true, + }) + if err != nil { + return nil, errors.Wrap(err, "failed to retrieve image list") + } + return imgs, nil + }) + select { + case <-ctx.Done(): + return nil, ctx.Err() + case res := <-ch: + if res.Err != nil { + return nil, res.Err + } + return res.Val.([]*types.ImageSummary), nil + } } // UpdateConfig values diff --git a/daemon/images/service.go b/daemon/images/service.go index 474b75e42a..804492d8b8 100644 --- a/daemon/images/service.go +++ b/daemon/images/service.go @@ -2,7 +2,6 @@ package images // import "github.com/docker/docker/daemon/images" import ( "context" - "fmt" "os" "github.com/containerd/containerd/content" @@ -245,15 +244,15 @@ func (i *ImageService) getLayerRefs() map[layer.ChainID]int { func (i *ImageService) ImageDiskUsage(ctx context.Context) ([]*types.ImageSummary, error) { ch := i.usage.DoChan("ImageDiskUsage", func() (interface{}, error) { // Get all top images with extra attributes - images, err := i.Images(ctx, types.ImageListOptions{ + imgs, err := i.Images(ctx, types.ImageListOptions{ Filters: filters.NewArgs(), SharedSize: true, ContainerCount: true, }) if err != nil { - return nil, fmt.Errorf("failed to retrieve image list: %v", err) + return nil, errors.Wrap(err, "failed to retrieve image list") } - return images, nil + return imgs, nil }) select { case <-ctx.Done():