containerd/cmd/ctr/snapshot.go
Derek McGowan a3d5a818f6
Update snapshot command in ctr
Move existing snapshot command to archive subcommand of snapshot.
Add list command for listing snapshots.
Add usage command for showing snapshot disk usage.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
2017-06-21 17:18:52 -07:00

168 lines
3.5 KiB
Go

package main
import (
"context"
"errors"
"fmt"
"os"
"text/tabwriter"
"github.com/containerd/containerd/progress"
"github.com/containerd/containerd/rootfs"
"github.com/containerd/containerd/snapshot"
"github.com/urfave/cli"
)
var snapshotCommand = cli.Command{
Name: "snapshot",
Usage: "snapshot management",
Subcommands: cli.Commands{
archiveSnapshotCommand,
listSnapshotCommand,
usageSnapshotCommand,
},
}
var archiveSnapshotCommand = cli.Command{
Name: "archive",
Usage: "Create an archive of a snapshot",
ArgsUsage: "[flags] id",
Flags: []cli.Flag{
cli.StringFlag{
Name: "id",
Usage: "id of the container or snapshot",
},
},
Action: func(clicontext *cli.Context) error {
ctx, cancel := appContext(clicontext)
defer cancel()
id := clicontext.String("id")
if id == "" {
return errors.New("container id must be provided")
}
snapshotter, err := getSnapshotter(clicontext)
if err != nil {
return err
}
differ, err := getDiffService(clicontext)
if err != nil {
return err
}
contentRef := fmt.Sprintf("diff-%s", id)
d, err := rootfs.Diff(ctx, id, contentRef, snapshotter, differ)
if err != nil {
return err
}
// TODO: Track progress
fmt.Printf("%s %s\n", d.MediaType, d.Digest)
return nil
},
}
var listSnapshotCommand = cli.Command{
Name: "list",
Aliases: []string{"ls"},
Usage: "List snapshots",
Action: func(clicontext *cli.Context) error {
ctx, cancel := appContext(clicontext)
defer cancel()
client, err := newClient(clicontext)
if err != nil {
return err
}
snapshotter := client.SnapshotService()
tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
fmt.Fprintln(tw, "ID\tParent\tState\tReadonly\t")
if err := snapshotter.Walk(ctx, func(ctx context.Context, info snapshot.Info) error {
fmt.Fprintf(tw, "%v\t%v\t%v\t%t\t\n", info.Name, info.Parent, state(info.Kind), info.Readonly)
return nil
}); err != nil {
return err
}
return tw.Flush()
},
}
func state(k snapshot.Kind) string {
switch k {
case snapshot.KindActive:
return "active"
case snapshot.KindCommitted:
return "committed"
default:
return ""
}
}
var usageSnapshotCommand = cli.Command{
Name: "usage",
Usage: "Usage snapshots",
ArgsUsage: "[flags] [id] ...",
Flags: []cli.Flag{
cli.BoolFlag{
Name: "b",
Usage: "display size in bytes",
},
},
Action: func(clicontext *cli.Context) error {
ctx, cancel := appContext(clicontext)
defer cancel()
client, err := newClient(clicontext)
if err != nil {
return err
}
var displaySize func(int64) string
if clicontext.Bool("b") {
displaySize = func(s int64) string {
return fmt.Sprintf("%d", s)
}
} else {
displaySize = func(s int64) string {
return progress.Bytes(s).String()
}
}
snapshotter := client.SnapshotService()
tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
fmt.Fprintln(tw, "ID\tSize\tInodes\t")
if clicontext.NArg() == 0 {
if err := snapshotter.Walk(ctx, func(ctx context.Context, info snapshot.Info) error {
usage, err := snapshotter.Usage(ctx, info.Name)
if err != nil {
return err
}
fmt.Fprintf(tw, "%v\t%s\t%d\t\n", info.Name, displaySize(usage.Size), usage.Inodes)
return nil
}); err != nil {
return err
}
} else {
for _, id := range clicontext.Args() {
usage, err := snapshotter.Usage(ctx, id)
if err != nil {
return err
}
fmt.Fprintf(tw, "%v\t%s\t%d\t\n", id, displaySize(usage.Size), usage.Inodes)
}
}
return tw.Flush()
},
}