summaryrefslogtreecommitdiff
path: root/libpod/image/df.go
diff options
context:
space:
mode:
Diffstat (limited to 'libpod/image/df.go')
-rw-r--r--libpod/image/df.go126
1 files changed, 126 insertions, 0 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
+}