ctr: snapshots diff command
Signed-off-by: Jess Valarezo <valarezo.jessica@gmail.com>
This commit is contained in:
parent
b77fa49d20
commit
625eb5e661
@ -3,16 +3,22 @@ package snapshots
|
|||||||
import (
|
import (
|
||||||
gocontext "context"
|
gocontext "context"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"text/tabwriter"
|
"text/tabwriter"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/containerd/containerd/cmd/ctr/commands"
|
"github.com/containerd/containerd/cmd/ctr/commands"
|
||||||
|
"github.com/containerd/containerd/content"
|
||||||
|
"github.com/containerd/containerd/diff"
|
||||||
"github.com/containerd/containerd/log"
|
"github.com/containerd/containerd/log"
|
||||||
"github.com/containerd/containerd/mount"
|
"github.com/containerd/containerd/mount"
|
||||||
"github.com/containerd/containerd/progress"
|
"github.com/containerd/containerd/progress"
|
||||||
|
"github.com/containerd/containerd/rootfs"
|
||||||
"github.com/containerd/containerd/snapshots"
|
"github.com/containerd/containerd/snapshots"
|
||||||
digest "github.com/opencontainers/go-digest"
|
digest "github.com/opencontainers/go-digest"
|
||||||
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"github.com/urfave/cli"
|
"github.com/urfave/cli"
|
||||||
)
|
)
|
||||||
@ -25,6 +31,7 @@ var Command = cli.Command{
|
|||||||
Flags: commands.SnapshotterFlags,
|
Flags: commands.SnapshotterFlags,
|
||||||
Subcommands: cli.Commands{
|
Subcommands: cli.Commands{
|
||||||
commitCommand,
|
commitCommand,
|
||||||
|
diffCommand,
|
||||||
infoCommand,
|
infoCommand,
|
||||||
listCommand,
|
listCommand,
|
||||||
mountCommand,
|
mountCommand,
|
||||||
@ -67,6 +74,115 @@ var listCommand = cli.Command{
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var diffCommand = cli.Command{
|
||||||
|
Name: "diff",
|
||||||
|
Usage: "get the diff of two snapshots. the default second snapshot is the first snapshot's parent.",
|
||||||
|
ArgsUsage: "[flags] <idA> [<idB>]",
|
||||||
|
Flags: append([]cli.Flag{
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "media-type",
|
||||||
|
Usage: "media type to use for creating diff",
|
||||||
|
Value: ocispec.MediaTypeImageLayerGzip,
|
||||||
|
},
|
||||||
|
cli.StringFlag{
|
||||||
|
Name: "ref",
|
||||||
|
Usage: "content upload reference to use",
|
||||||
|
},
|
||||||
|
cli.BoolFlag{
|
||||||
|
Name: "keep",
|
||||||
|
Usage: "keep diff content. up to creator to delete it.",
|
||||||
|
},
|
||||||
|
}, commands.LabelFlag),
|
||||||
|
Action: func(context *cli.Context) error {
|
||||||
|
var (
|
||||||
|
idA = context.Args().First()
|
||||||
|
idB = context.Args().Get(1)
|
||||||
|
)
|
||||||
|
if idA == "" {
|
||||||
|
return errors.New("snapshot id must be provided")
|
||||||
|
}
|
||||||
|
client, ctx, cancel, err := commands.NewClient(context)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
ctx, done, err := client.WithLease(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer done()
|
||||||
|
|
||||||
|
var desc ocispec.Descriptor
|
||||||
|
labels := commands.LabelArgs(context.StringSlice("label"))
|
||||||
|
snapshotter := client.SnapshotService(context.GlobalString("snapshotter"))
|
||||||
|
|
||||||
|
fmt.Println(context.String("media-type"))
|
||||||
|
|
||||||
|
if context.Bool("keep") {
|
||||||
|
labels["containerd.io/gc.root"] = time.Now().UTC().Format(time.RFC3339)
|
||||||
|
}
|
||||||
|
opts := []diff.Opt{
|
||||||
|
diff.WithMediaType(context.String("media-type")),
|
||||||
|
diff.WithReference(context.String("ref")),
|
||||||
|
diff.WithLabels(labels),
|
||||||
|
}
|
||||||
|
|
||||||
|
if idB == "" {
|
||||||
|
desc, err = rootfs.Diff(ctx, idA, snapshotter, client.DiffService(), opts...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var a, b []mount.Mount
|
||||||
|
ds := client.DiffService()
|
||||||
|
|
||||||
|
a, err = getMounts(ctx, idA, snapshotter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
b, err = getMounts(ctx, idB, snapshotter)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
desc, err = ds.DiffMounts(ctx, a, b, opts...)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ra, err := client.ContentStore().ReaderAt(ctx, desc.Digest)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
_, err = io.Copy(os.Stdout, content.NewReader(ra))
|
||||||
|
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func getMounts(ctx gocontext.Context, id string, sn snapshots.Snapshotter) ([]mount.Mount, error) {
|
||||||
|
var mounts []mount.Mount
|
||||||
|
info, err := sn.Stat(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if info.Kind == snapshots.KindActive {
|
||||||
|
mounts, err = sn.Mounts(ctx, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
key := fmt.Sprintf("%s-view-key", id)
|
||||||
|
mounts, err = sn.View(ctx, key, id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer sn.Remove(ctx, key)
|
||||||
|
}
|
||||||
|
return mounts, nil
|
||||||
|
}
|
||||||
|
|
||||||
var usageCommand = cli.Command{
|
var usageCommand = cli.Command{
|
||||||
Name: "usage",
|
Name: "usage",
|
||||||
Usage: "usage snapshots",
|
Usage: "usage snapshots",
|
||||||
|
Loading…
Reference in New Issue
Block a user