github.com/gravitational/moby@v1.13.1/daemon/disk_usage.go (about)

     1  package daemon
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/Sirupsen/logrus"
     7  	"github.com/docker/distribution/digest"
     8  	"github.com/docker/docker/api/types"
     9  	"github.com/docker/docker/api/types/filters"
    10  	"github.com/docker/docker/layer"
    11  	"github.com/docker/docker/pkg/directory"
    12  	"github.com/docker/docker/volume"
    13  )
    14  
    15  func (daemon *Daemon) getLayerRefs() map[layer.ChainID]int {
    16  	tmpImages := daemon.imageStore.Map()
    17  	layerRefs := map[layer.ChainID]int{}
    18  	for id, img := range tmpImages {
    19  		dgst := digest.Digest(id)
    20  		if len(daemon.referenceStore.References(dgst)) == 0 && len(daemon.imageStore.Children(id)) != 0 {
    21  			continue
    22  		}
    23  
    24  		rootFS := *img.RootFS
    25  		rootFS.DiffIDs = nil
    26  		for _, id := range img.RootFS.DiffIDs {
    27  			rootFS.Append(id)
    28  			chid := rootFS.ChainID()
    29  			layerRefs[chid]++
    30  		}
    31  	}
    32  
    33  	return layerRefs
    34  }
    35  
    36  // SystemDiskUsage returns information about the daemon data disk usage
    37  func (daemon *Daemon) SystemDiskUsage() (*types.DiskUsage, error) {
    38  	// Retrieve container list
    39  	allContainers, err := daemon.Containers(&types.ContainerListOptions{
    40  		Size: true,
    41  		All:  true,
    42  	})
    43  	if err != nil {
    44  		return nil, fmt.Errorf("failed to retrieve container list: %v", err)
    45  	}
    46  
    47  	// Get all top images with extra attributes
    48  	allImages, err := daemon.Images(filters.NewArgs(), false, true)
    49  	if err != nil {
    50  		return nil, fmt.Errorf("failed to retrieve image list: %v", err)
    51  	}
    52  
    53  	// Get all local volumes
    54  	allVolumes := []*types.Volume{}
    55  	getLocalVols := func(v volume.Volume) error {
    56  		name := v.Name()
    57  		refs := daemon.volumes.Refs(v)
    58  
    59  		tv := volumeToAPIType(v)
    60  		sz, err := directory.Size(v.Path())
    61  		if err != nil {
    62  			logrus.Warnf("failed to determine size of volume %v", name)
    63  			sz = -1
    64  		}
    65  		tv.UsageData = &types.VolumeUsageData{Size: sz, RefCount: int64(len(refs))}
    66  		allVolumes = append(allVolumes, tv)
    67  
    68  		return nil
    69  	}
    70  
    71  	err = daemon.traverseLocalVolumes(getLocalVols)
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	// Get total layers size on disk
    77  	layerRefs := daemon.getLayerRefs()
    78  	allLayers := daemon.layerStore.Map()
    79  	var allLayersSize int64
    80  	for _, l := range allLayers {
    81  		size, err := l.DiffSize()
    82  		if err == nil {
    83  			if _, ok := layerRefs[l.ChainID()]; ok {
    84  				allLayersSize += size
    85  			} else {
    86  				logrus.Warnf("found leaked image layer %v", l.ChainID())
    87  			}
    88  		} else {
    89  			logrus.Warnf("failed to get diff size for layer %v", l.ChainID())
    90  		}
    91  
    92  	}
    93  
    94  	return &types.DiskUsage{
    95  		LayersSize: allLayersSize,
    96  		Containers: allContainers,
    97  		Volumes:    allVolumes,
    98  		Images:     allImages,
    99  	}, nil
   100  }