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 }