summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libpod/image/df.go126
-rw-r--r--pkg/domain/infra/abi/system.go70
2 files changed, 141 insertions, 55 deletions
diff --git a/libpod/image/df.go b/libpod/image/df.go
new file mode 100644
index 000000000..84cf7af9e
--- /dev/null
+++ b/libpod/image/df.go
@@ -0,0 +1,126 @@
+package image
+
+import (
+ "context"
+ "time"
+
+ "github.com/containers/image/v5/docker/reference"
+)
+
+// DiskUsageStat gives disk-usage statistics for a specific image.
+type DiskUsageStat struct {
+ // ID of the image.
+ ID string
+ // Repository of the first recorded name of the image.
+ Repository string
+ // Tag of the first recorded name of the image.
+ Tag string
+ // Created is the creation time of the image.
+ Created time.Time
+ // SharedSize is the amount of space shared with another image.
+ SharedSize uint64
+ // UniqueSize is the amount of space used only by this image.
+ UniqueSize uint64
+ // Size is the total size of the image (i.e., the sum of the shared and
+ // unique size).
+ Size uint64
+ // Number of containers using the image.
+ Containers int
+}
+
+// DiskUsage returns disk-usage statistics for the specified slice of images.
+func (ir *Runtime) DiskUsage(ctx context.Context, images []*Image) ([]DiskUsageStat, error) {
+ stats := make([]DiskUsageStat, len(images))
+
+ // Build a layerTree to quickly compute (and cache!) parent/child
+ // relations.
+ tree, err := ir.layerTree()
+ if err != nil {
+ return nil, err
+ }
+
+ // Calculate the stats for each image.
+ for i, img := range images {
+ stat, err := diskUsageForImage(ctx, img, tree)
+ if err != nil {
+ return nil, err
+ }
+ stats[i] = *stat
+ }
+
+ return stats, nil
+}
+
+// diskUsageForImage returns the disk-usage statistics for the spcified image.
+func diskUsageForImage(ctx context.Context, image *Image, tree *layerTree) (*DiskUsageStat, error) {
+ stat := DiskUsageStat{
+ ID: image.ID(),
+ Created: image.Created(),
+ }
+
+ // Repository and tag.
+ var name, repository, tag string
+ for _, n := range image.Names() {
+ if len(n) > 0 {
+ name = n
+ break
+ }
+ }
+ if len(name) > 0 {
+ named, err := reference.ParseNormalizedNamed(name)
+ if err != nil {
+ return nil, err
+ }
+ repository = named.Name()
+ if tagged, isTagged := named.(reference.NamedTagged); isTagged {
+ tag = tagged.Tag()
+ }
+ } else {
+ repository = "<none>"
+ tag = "<none>"
+ }
+ stat.Repository = repository
+ stat.Tag = tag
+
+ // Shared, unique and total size.
+ parent, err := tree.parent(ctx, image)
+ if err != nil {
+ return nil, err
+ }
+ childIDs, err := tree.children(ctx, image, false)
+ if err != nil {
+ return nil, err
+ }
+ // Optimistically set unique size to the full size of the image.
+ size, err := image.Size(ctx)
+ if err != nil {
+ return nil, err
+ }
+ stat.UniqueSize = *size
+
+ if len(childIDs) > 0 {
+ // If we have children, we share everything.
+ stat.SharedSize = stat.UniqueSize
+ stat.UniqueSize = 0
+ } else if parent != nil {
+ // If we have no children but a parent, remove the parent
+ // (shared) size from the unique one.
+ size, err := parent.Size(ctx)
+ if err != nil {
+ return nil, err
+ }
+ stat.UniqueSize -= *size
+ stat.SharedSize = *size
+ }
+
+ stat.Size = stat.SharedSize + stat.UniqueSize
+
+ // Number of containers using the image.
+ containers, err := image.Containers()
+ if err != nil {
+ return nil, err
+ }
+ stat.Containers = len(containers)
+
+ return &stat, nil
+}
diff --git a/pkg/domain/infra/abi/system.go b/pkg/domain/infra/abi/system.go
index 914a7681d..57c098166 100644
--- a/pkg/domain/infra/abi/system.go
+++ b/pkg/domain/infra/abi/system.go
@@ -17,7 +17,6 @@ import (
"github.com/containers/podman/v2/pkg/rootless"
"github.com/containers/podman/v2/pkg/util"
"github.com/containers/podman/v2/utils"
- "github.com/docker/distribution/reference"
"github.com/pkg/errors"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
@@ -199,71 +198,32 @@ func (ic *ContainerEngine) SystemDf(ctx context.Context, options entities.System
dfImages = []*entities.SystemDfImageReport{}
)
- // Get Images and iterate them
+ // Compute disk-usage stats for all local images.
imgs, err := ic.Libpod.ImageRuntime().GetImages()
if err != nil {
return nil, err
}
- for _, i := range imgs {
- var sharedSize uint64
- cons, err := i.Containers()
- if err != nil {
- return nil, err
- }
- imageSize, err := i.Size(ctx)
- if err != nil {
- return nil, err
- }
- uniqueSize := *imageSize
- parent, err := i.GetParent(ctx)
- if err != nil {
- return nil, err
- }
- if parent != nil {
- parentSize, err := parent.Size(ctx)
- if err != nil {
- return nil, err
- }
- uniqueSize = *parentSize - *imageSize
- sharedSize = *imageSize - uniqueSize
- }
- var name, repository, tag string
- for _, n := range i.Names() {
- if len(n) > 0 {
- name = n
- break
- }
- }
-
- if len(name) > 0 {
- named, err := reference.ParseNormalizedNamed(name)
- if err != nil {
- return nil, err
- }
- repository = named.Name()
- if tagged, isTagged := named.(reference.NamedTagged); isTagged {
- tag = tagged.Tag()
- }
- } else {
- repository = "<none>"
- tag = "<none>"
- }
+ imageStats, err := ic.Libpod.ImageRuntime().DiskUsage(ctx, imgs)
+ if err != nil {
+ return nil, err
+ }
+ for _, stat := range imageStats {
report := entities.SystemDfImageReport{
- Repository: repository,
- Tag: tag,
- ImageID: i.ID(),
- Created: i.Created(),
- Size: int64(*imageSize),
- SharedSize: int64(sharedSize),
- UniqueSize: int64(uniqueSize),
- Containers: len(cons),
+ Repository: stat.Repository,
+ Tag: stat.Tag,
+ ImageID: stat.ID,
+ Created: stat.Created,
+ Size: int64(stat.Size),
+ SharedSize: int64(stat.SharedSize),
+ UniqueSize: int64(stat.UniqueSize),
+ Containers: stat.Containers,
}
dfImages = append(dfImages, &report)
}
- // GetContainers and iterate them
+ // Get Containers and iterate them
cons, err := ic.Libpod.GetAllContainers()
if err != nil {
return nil, err