disk_usage.go 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. package daemon // import "github.com/docker/docker/daemon"
  2. import (
  3. "fmt"
  4. "sync/atomic"
  5. "golang.org/x/net/context"
  6. "github.com/docker/docker/api/types"
  7. "github.com/docker/docker/api/types/filters"
  8. "github.com/docker/docker/pkg/directory"
  9. "github.com/docker/docker/volume"
  10. "github.com/sirupsen/logrus"
  11. )
  12. // SystemDiskUsage returns information about the daemon data disk usage
  13. func (daemon *Daemon) SystemDiskUsage(ctx context.Context) (*types.DiskUsage, error) {
  14. if !atomic.CompareAndSwapInt32(&daemon.diskUsageRunning, 0, 1) {
  15. return nil, fmt.Errorf("a disk usage operation is already running")
  16. }
  17. defer atomic.StoreInt32(&daemon.diskUsageRunning, 0)
  18. // Retrieve container list
  19. allContainers, err := daemon.Containers(&types.ContainerListOptions{
  20. Size: true,
  21. All: true,
  22. })
  23. if err != nil {
  24. return nil, fmt.Errorf("failed to retrieve container list: %v", err)
  25. }
  26. // Get all top images with extra attributes
  27. allImages, err := daemon.imageService.Images(filters.NewArgs(), false, true)
  28. if err != nil {
  29. return nil, fmt.Errorf("failed to retrieve image list: %v", err)
  30. }
  31. // Get all local volumes
  32. allVolumes := []*types.Volume{}
  33. getLocalVols := func(v volume.Volume) error {
  34. select {
  35. case <-ctx.Done():
  36. return ctx.Err()
  37. default:
  38. if d, ok := v.(volume.DetailedVolume); ok {
  39. // skip local volumes with mount options since these could have external
  40. // mounted filesystems that will be slow to enumerate.
  41. if len(d.Options()) > 0 {
  42. return nil
  43. }
  44. }
  45. name := v.Name()
  46. refs := daemon.volumes.Refs(v)
  47. tv := volumeToAPIType(v)
  48. sz, err := directory.Size(v.Path())
  49. if err != nil {
  50. logrus.Warnf("failed to determine size of volume %v", name)
  51. sz = -1
  52. }
  53. tv.UsageData = &types.VolumeUsageData{Size: sz, RefCount: int64(len(refs))}
  54. allVolumes = append(allVolumes, tv)
  55. }
  56. return nil
  57. }
  58. err = daemon.traverseLocalVolumes(getLocalVols)
  59. if err != nil {
  60. return nil, err
  61. }
  62. allLayersSize, err := daemon.imageService.LayerDiskUsage(ctx)
  63. if err != nil {
  64. return nil, err
  65. }
  66. return &types.DiskUsage{
  67. LayersSize: allLayersSize,
  68. Containers: allContainers,
  69. Volumes: allVolumes,
  70. Images: allImages,
  71. }, nil
  72. }