github.com/moby/docker@v26.1.3+incompatible/daemon/disk_usage.go (about)

     1  package daemon // import "github.com/docker/docker/daemon"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/docker/docker/api/server/router/system"
     8  	"github.com/docker/docker/api/types"
     9  	"github.com/docker/docker/api/types/container"
    10  	"github.com/docker/docker/api/types/filters"
    11  	"github.com/docker/docker/api/types/image"
    12  	"github.com/docker/docker/api/types/volume"
    13  	"github.com/pkg/errors"
    14  	"golang.org/x/sync/errgroup"
    15  )
    16  
    17  // containerDiskUsage obtains information about container data disk usage
    18  // and makes sure that only one calculation is performed at the same time.
    19  func (daemon *Daemon) containerDiskUsage(ctx context.Context) ([]*types.Container, error) {
    20  	res, _, err := daemon.usageContainers.Do(ctx, struct{}{}, func(ctx context.Context) ([]*types.Container, error) {
    21  		// Retrieve container list
    22  		containers, err := daemon.Containers(ctx, &container.ListOptions{
    23  			Size: true,
    24  			All:  true,
    25  		})
    26  		if err != nil {
    27  			return nil, fmt.Errorf("failed to retrieve container list: %v", err)
    28  		}
    29  		return containers, nil
    30  	})
    31  	return res, err
    32  }
    33  
    34  // imageDiskUsage obtains information about image data disk usage from image service
    35  // and makes sure that only one calculation is performed at the same time.
    36  func (daemon *Daemon) imageDiskUsage(ctx context.Context) ([]*image.Summary, error) {
    37  	imgs, _, err := daemon.usageImages.Do(ctx, struct{}{}, func(ctx context.Context) ([]*image.Summary, error) {
    38  		// Get all top images with extra attributes
    39  		imgs, err := daemon.imageService.Images(ctx, image.ListOptions{
    40  			Filters:        filters.NewArgs(),
    41  			SharedSize:     true,
    42  			ContainerCount: true,
    43  		})
    44  		if err != nil {
    45  			return nil, errors.Wrap(err, "failed to retrieve image list")
    46  		}
    47  		return imgs, nil
    48  	})
    49  
    50  	return imgs, err
    51  }
    52  
    53  // localVolumesSize obtains information about volume disk usage from volumes service
    54  // and makes sure that only one size calculation is performed at the same time.
    55  func (daemon *Daemon) localVolumesSize(ctx context.Context) ([]*volume.Volume, error) {
    56  	volumes, _, err := daemon.usageVolumes.Do(ctx, struct{}{}, func(ctx context.Context) ([]*volume.Volume, error) {
    57  		volumes, err := daemon.volumes.LocalVolumesSize(ctx)
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  		return volumes, nil
    62  	})
    63  	return volumes, err
    64  }
    65  
    66  // layerDiskUsage obtains information about layer disk usage from image service
    67  // and makes sure that only one size calculation is performed at the same time.
    68  func (daemon *Daemon) layerDiskUsage(ctx context.Context) (int64, error) {
    69  	usage, _, err := daemon.usageLayer.Do(ctx, struct{}{}, func(ctx context.Context) (int64, error) {
    70  		usage, err := daemon.imageService.LayerDiskUsage(ctx)
    71  		if err != nil {
    72  			return 0, err
    73  		}
    74  		return usage, nil
    75  	})
    76  	return usage, err
    77  }
    78  
    79  // SystemDiskUsage returns information about the daemon data disk usage.
    80  // Callers must not mutate contents of the returned fields.
    81  func (daemon *Daemon) SystemDiskUsage(ctx context.Context, opts system.DiskUsageOptions) (*types.DiskUsage, error) {
    82  	eg, ctx := errgroup.WithContext(ctx)
    83  
    84  	var containers []*types.Container
    85  	if opts.Containers {
    86  		eg.Go(func() error {
    87  			var err error
    88  			containers, err = daemon.containerDiskUsage(ctx)
    89  			return err
    90  		})
    91  	}
    92  
    93  	var (
    94  		images     []*image.Summary
    95  		layersSize int64
    96  	)
    97  	if opts.Images {
    98  		eg.Go(func() error {
    99  			var err error
   100  			images, err = daemon.imageDiskUsage(ctx)
   101  			return err
   102  		})
   103  		eg.Go(func() error {
   104  			var err error
   105  			layersSize, err = daemon.layerDiskUsage(ctx)
   106  			return err
   107  		})
   108  	}
   109  
   110  	var volumes []*volume.Volume
   111  	if opts.Volumes {
   112  		eg.Go(func() error {
   113  			var err error
   114  			volumes, err = daemon.localVolumesSize(ctx)
   115  			return err
   116  		})
   117  	}
   118  
   119  	if err := eg.Wait(); err != nil {
   120  		return nil, err
   121  	}
   122  	return &types.DiskUsage{
   123  		LayersSize: layersSize,
   124  		Containers: containers,
   125  		Volumes:    volumes,
   126  		Images:     images,
   127  	}, nil
   128  }