The `ctr image usage` can display the usage of snapshots with a given image ref. It's easy for user to get chain snapshot IDs and unpack usage. And according to the [discuss][1], this subcommand can be used to ensure if snapshot's pagecache has been discarded in a unexpected reboot. How to use it: ```bash $ bin/ctr image usage --snapshotter native docker.io/library/golang:1.19.3 ctr: image docker.io/library/golang:1.19.3 isn't unpacked in snapshotter native $ bin/ctr image usage --snapshotter overlayfs docker.io/library/golang:1.19.3 KEY SIZE INODES sha256:28114d8403bac6352c3e09cb23e37208138a0cd9d309edf3df38e57be8075a1d 16.0 KiB 4 sha256:f162c02ce6b9b594757cd76eda1c1dd119b88e69e882cb645bf7ad528b54f0d2 476.2 MiB 13660 sha256:a5b9faceaa495819b9ba7011b7276c4ffaffe6c7b9de0889e11abc1113f7b5ca 225.5 MiB 3683 sha256:412b2615d27d6b0090558d25b201b60a7dff2a40892a7e7ca868b80bf5e5de41 159.8 MiB 6196 sha256:dbce1593502d39c344ce089f98187999f294de5182a7106dcb6c9d04ce0c7265 19.4 MiB 502 sha256:8953bf5d24149e9b2236abc76bd0aa14b73828f1b63e816cb4b457249f6125bc 12.2 MiB 958 sha256:ccba29d6937047c719a6c048a7038d3907590fbb8556418d119469b2ad4f95bc 134.7 MiB 7245 $ bin/ctr image usage --snapshotter overlayfs docker.io/library/golang:1.19 ctr: failed to ensure if image docker.io/library/golang:1.19 exists: image "docker.io/library/golang:1.19": not found ``` [1]: <https://github.com/containerd/containerd/issues/5854#issuecomment-1415915765> Signed-off-by: Wei Fu <fuweid89@gmail.com>
		
			
				
	
	
		
			98 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			98 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
   Copyright The containerd Authors.
 | 
						|
 | 
						|
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
   you may not use this file except in compliance with the License.
 | 
						|
   You may obtain a copy of the License at
 | 
						|
 | 
						|
       http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 | 
						|
   Unless required by applicable law or agreed to in writing, software
 | 
						|
   distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
   See the License for the specific language governing permissions and
 | 
						|
   limitations under the License.
 | 
						|
*/
 | 
						|
 | 
						|
package images
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"os"
 | 
						|
	"text/tabwriter"
 | 
						|
 | 
						|
	"github.com/containerd/containerd"
 | 
						|
	"github.com/containerd/containerd/cmd/ctr/commands"
 | 
						|
	"github.com/containerd/containerd/pkg/progress"
 | 
						|
 | 
						|
	"github.com/opencontainers/image-spec/identity"
 | 
						|
	"github.com/urfave/cli"
 | 
						|
)
 | 
						|
 | 
						|
var usageCommand = cli.Command{
 | 
						|
	Name:      "usage",
 | 
						|
	Usage:     "Display usage of snapshots for a given image ref",
 | 
						|
	ArgsUsage: "[flags] <ref>",
 | 
						|
	Flags:     commands.SnapshotterFlags,
 | 
						|
	Action: func(context *cli.Context) error {
 | 
						|
		var ref = context.Args().First()
 | 
						|
		if ref == "" {
 | 
						|
			return fmt.Errorf("please provide an image reference to mount")
 | 
						|
		}
 | 
						|
 | 
						|
		client, ctx, cancel, err := commands.NewClient(context)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
		defer cancel()
 | 
						|
 | 
						|
		snapshotter := context.String("snapshotter")
 | 
						|
		if snapshotter == "" {
 | 
						|
			snapshotter = containerd.DefaultSnapshotter
 | 
						|
		}
 | 
						|
 | 
						|
		img, err := client.ImageService().Get(ctx, ref)
 | 
						|
		if err != nil {
 | 
						|
			return fmt.Errorf("failed to ensure if image %s exists: %w", ref, err)
 | 
						|
		}
 | 
						|
 | 
						|
		i := containerd.NewImage(client, img)
 | 
						|
		if ok, err := i.IsUnpacked(ctx, snapshotter); err != nil {
 | 
						|
			return fmt.Errorf("failed to ensure if image %s has been unpacked in snapshotter %s: %w",
 | 
						|
				ref, snapshotter, err)
 | 
						|
		} else if !ok {
 | 
						|
			return fmt.Errorf("image %s isn't unpacked in snapshotter %s", ref, snapshotter)
 | 
						|
		}
 | 
						|
 | 
						|
		diffIDs, err := i.RootFS(ctx)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
 | 
						|
		tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
 | 
						|
		fmt.Fprintln(tw, "KEY\tSIZE\tINODES\t")
 | 
						|
 | 
						|
		snSrv := client.SnapshotService(snapshotter)
 | 
						|
		snID := identity.ChainID(diffIDs).String()
 | 
						|
		for snID != "" {
 | 
						|
			usage, err := snSrv.Usage(ctx, snID)
 | 
						|
			if err != nil {
 | 
						|
				return fmt.Errorf("failed to get usage for snapshot %s: %w", snID, err)
 | 
						|
			}
 | 
						|
 | 
						|
			fmt.Fprintf(tw, "%v\t%s\t%d\t\n",
 | 
						|
				snID,
 | 
						|
				progress.Bytes(usage.Size).String(),
 | 
						|
				usage.Inodes,
 | 
						|
			)
 | 
						|
 | 
						|
			info, err := snSrv.Stat(ctx, snID)
 | 
						|
			if err != nil {
 | 
						|
				return fmt.Errorf("failed to ensure if snapshot %s has parent or not: %w", snID, err)
 | 
						|
			}
 | 
						|
			snID = info.Parent
 | 
						|
		}
 | 
						|
		return tw.Flush()
 | 
						|
	},
 | 
						|
}
 |