github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/libpod/image/df.go (about)

     1  package image
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/containers/image/v5/docker/reference"
     8  )
     9  
    10  // DiskUsageStat gives disk-usage statistics for a specific image.
    11  type DiskUsageStat struct {
    12  	// ID of the image.
    13  	ID string
    14  	// Repository of the first recorded name of the image.
    15  	Repository string
    16  	// Tag of the first recorded name of the image.
    17  	Tag string
    18  	// Created is the creation time of the image.
    19  	Created time.Time
    20  	// SharedSize is the amount of space shared with another image.
    21  	SharedSize uint64
    22  	// UniqueSize is the amount of space used only by this image.
    23  	UniqueSize uint64
    24  	// Size is the total size of the image (i.e., the sum of the shared and
    25  	// unique size).
    26  	Size uint64
    27  	// Number of containers using the image.
    28  	Containers int
    29  }
    30  
    31  // DiskUsage returns disk-usage statistics for the specified slice of images.
    32  func (ir *Runtime) DiskUsage(ctx context.Context, images []*Image) ([]DiskUsageStat, error) {
    33  	stats := make([]DiskUsageStat, len(images))
    34  
    35  	// Build a layerTree to quickly compute (and cache!) parent/child
    36  	// relations.
    37  	tree, err := ir.layerTree()
    38  	if err != nil {
    39  		return nil, err
    40  	}
    41  
    42  	// Calculate the stats for each image.
    43  	for i, img := range images {
    44  		stat, err := diskUsageForImage(ctx, img, tree)
    45  		if err != nil {
    46  			return nil, err
    47  		}
    48  		stats[i] = *stat
    49  	}
    50  
    51  	return stats, nil
    52  }
    53  
    54  // diskUsageForImage returns the disk-usage statistics for the spcified image.
    55  func diskUsageForImage(ctx context.Context, image *Image, tree *layerTree) (*DiskUsageStat, error) {
    56  	stat := DiskUsageStat{
    57  		ID:      image.ID(),
    58  		Created: image.Created(),
    59  	}
    60  
    61  	// Repository and tag.
    62  	var name, repository, tag string
    63  	for _, n := range image.Names() {
    64  		if len(n) > 0 {
    65  			name = n
    66  			break
    67  		}
    68  	}
    69  	if len(name) > 0 {
    70  		named, err := reference.ParseNormalizedNamed(name)
    71  		if err != nil {
    72  			return nil, err
    73  		}
    74  		repository = named.Name()
    75  		if tagged, isTagged := named.(reference.NamedTagged); isTagged {
    76  			tag = tagged.Tag()
    77  		}
    78  	} else {
    79  		repository = "<none>"
    80  		tag = "<none>"
    81  	}
    82  	stat.Repository = repository
    83  	stat.Tag = tag
    84  
    85  	// Shared, unique and total size.
    86  	parent, err := tree.parent(ctx, image)
    87  	if err != nil {
    88  		return nil, err
    89  	}
    90  	childIDs, err := tree.children(ctx, image, false)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  	// Optimistically set unique size to the full size of the image.
    95  	size, err := image.Size(ctx)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  	stat.UniqueSize = *size
   100  
   101  	if len(childIDs) > 0 {
   102  		// If we have children, we share everything.
   103  		stat.SharedSize = stat.UniqueSize
   104  		stat.UniqueSize = 0
   105  	} else if parent != nil {
   106  		// If we have no children but a parent, remove the parent
   107  		// (shared) size from the unique one.
   108  		size, err := parent.Size(ctx)
   109  		if err != nil {
   110  			return nil, err
   111  		}
   112  		stat.UniqueSize -= *size
   113  		stat.SharedSize = *size
   114  	}
   115  
   116  	stat.Size = stat.SharedSize + stat.UniqueSize
   117  
   118  	// Number of containers using the image.
   119  	containers, err := image.Containers()
   120  	if err != nil {
   121  		return nil, err
   122  	}
   123  	stat.Containers = len(containers)
   124  
   125  	return &stat, nil
   126  }