2018-02-05 21:05:59 +00:00
|
|
|
package daemon // import "github.com/docker/docker/daemon"
|
2016-08-23 23:24:15 +00:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2017-04-12 20:59:59 +00:00
|
|
|
"sync/atomic"
|
2016-08-23 23:24:15 +00:00
|
|
|
|
2017-04-12 20:59:31 +00:00
|
|
|
"golang.org/x/net/context"
|
|
|
|
|
2016-08-23 23:24:15 +00:00
|
|
|
"github.com/docker/docker/api/types"
|
2016-11-11 14:34:01 +00:00
|
|
|
"github.com/docker/docker/api/types/filters"
|
2016-08-23 23:24:15 +00:00
|
|
|
"github.com/docker/docker/pkg/directory"
|
|
|
|
"github.com/docker/docker/volume"
|
2017-07-26 21:42:13 +00:00
|
|
|
"github.com/sirupsen/logrus"
|
2016-08-23 23:24:15 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// SystemDiskUsage returns information about the daemon data disk usage
|
2017-04-12 20:59:31 +00:00
|
|
|
func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, error) {
|
2017-04-12 20:59:59 +00:00
|
|
|
if !atomic.CompareAndSwapInt32(&daemon.diskUsageRunning, 0, 1) {
|
|
|
|
return nil, fmt.Errorf("a disk usage operation is already running")
|
|
|
|
}
|
|
|
|
defer atomic.StoreInt32(&daemon.diskUsageRunning, 0)
|
|
|
|
|
2016-08-23 23:24:15 +00:00
|
|
|
// Retrieve container list
|
|
|
|
allContainers, err := daemon.Containers(&types.ContainerListOptions{
|
|
|
|
Size: true,
|
|
|
|
All: true,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to retrieve container list: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get all top images with extra attributes
|
2018-02-02 22:18:46 +00:00
|
|
|
allImages, err := daemon.imageService.Images(filters.NewArgs(), false, true)
|
2016-08-23 23:24:15 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to retrieve image list: %v", err)
|
|
|
|
}
|
|
|
|
|
2018-03-19 15:43:54 +00:00
|
|
|
volumes, err := daemon.volumes.FilterByDriver(volume.DefaultDriverName)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
var allVolumes []*types.Volume
|
|
|
|
for _, v := range volumes {
|
2017-04-12 20:59:31 +00:00
|
|
|
select {
|
|
|
|
case <-ctx.Done():
|
2018-03-19 15:43:54 +00:00
|
|
|
return nil, ctx.Err()
|
2017-04-12 20:59:31 +00:00
|
|
|
default:
|
2018-03-19 15:43:54 +00:00
|
|
|
}
|
|
|
|
if d, ok := v.(volume.DetailedVolume); ok {
|
|
|
|
if len(d.Options()) > 0 {
|
2017-06-09 22:25:05 +00:00
|
|
|
// skip local volumes with mount options since these could have external
|
|
|
|
// mounted filesystems that will be slow to enumerate.
|
2018-03-19 15:43:54 +00:00
|
|
|
continue
|
2017-06-09 22:25:05 +00:00
|
|
|
}
|
2016-08-23 23:24:15 +00:00
|
|
|
}
|
|
|
|
|
2018-03-19 15:43:54 +00:00
|
|
|
name := v.Name()
|
|
|
|
refs := daemon.volumes.Refs(v)
|
2016-08-23 23:24:15 +00:00
|
|
|
|
2018-03-19 15:43:54 +00:00
|
|
|
tv := volumeToAPIType(v)
|
|
|
|
sz, err := directory.Size(ctx, v.Path())
|
|
|
|
if err != nil {
|
|
|
|
logrus.Warnf("failed to determine size of volume %v", name)
|
|
|
|
sz = -1
|
|
|
|
}
|
|
|
|
tv.UsageData = &types.VolumeUsageData{Size: sz, RefCount: int64(len(refs))}
|
|
|
|
allVolumes = append(allVolumes, tv)
|
2016-08-23 23:24:15 +00:00
|
|
|
}
|
|
|
|
|
2018-02-02 22:18:46 +00:00
|
|
|
allLayersSize, err := daemon.imageService.LayerDiskUsage(ctx)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
2016-08-23 23:24:15 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return &types.DiskUsage{
|
|
|
|
LayersSize: allLayersSize,
|
|
|
|
Containers: allContainers,
|
|
|
|
Volumes: allVolumes,
|
|
|
|
Images: allImages,
|
|
|
|
}, nil
|
|
|
|
}
|