
Remove rootfs service in place of snapshot service. Adds diff service for extracting and creating diffs. Diff creation is not yet implemented. This service allows pulling or creating images without needing root access to mount. Additionally in the future this will allow containerd to ensure extractions happen safely in a chroot if needed. Signed-off-by: Derek McGowan <derek@mcgstyle.net>
121 lines
2.9 KiB
Go
121 lines
2.9 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"strings"
|
|
|
|
diffapi "github.com/containerd/containerd/api/services/diff"
|
|
snapshotapi "github.com/containerd/containerd/api/services/snapshot"
|
|
"github.com/containerd/containerd/images"
|
|
"github.com/containerd/containerd/log"
|
|
"github.com/containerd/containerd/rootfs"
|
|
diffservice "github.com/containerd/containerd/services/diff"
|
|
snapshotservice "github.com/containerd/containerd/services/snapshot"
|
|
digest "github.com/opencontainers/go-digest"
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"github.com/urfave/cli"
|
|
)
|
|
|
|
var rootfsCommand = cli.Command{
|
|
Name: "rootfs",
|
|
Usage: "rootfs setups a rootfs",
|
|
Subcommands: []cli.Command{
|
|
rootfsUnpackCommand,
|
|
rootfsPrepareCommand,
|
|
},
|
|
}
|
|
|
|
var rootfsUnpackCommand = cli.Command{
|
|
Name: "unpack",
|
|
Usage: "unpack applies layers from a manifest to a snapshot",
|
|
ArgsUsage: "[flags] <digest>",
|
|
Flags: []cli.Flag{},
|
|
Action: func(clicontext *cli.Context) error {
|
|
ctx, cancel := appContext()
|
|
defer cancel()
|
|
|
|
dgst, err := digest.Parse(clicontext.Args().First())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.G(ctx).Infof("unpacking layers from manifest %s", dgst.String())
|
|
|
|
cs, err := resolveContentStore(clicontext)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
image := images.Image{
|
|
Target: ocispec.Descriptor{
|
|
MediaType: ocispec.MediaTypeImageManifest,
|
|
Digest: dgst,
|
|
},
|
|
}
|
|
|
|
layers, err := getImageLayers(ctx, image, cs)
|
|
if err != nil {
|
|
log.G(ctx).WithError(err).Fatal("Failed to get rootfs layers")
|
|
}
|
|
|
|
conn, err := connectGRPC(clicontext)
|
|
if err != nil {
|
|
log.G(ctx).Fatal(err)
|
|
}
|
|
|
|
snapshotter := snapshotservice.NewSnapshotterFromClient(snapshotapi.NewSnapshotClient(conn))
|
|
applier := diffservice.NewApplierFromClient(diffapi.NewDiffClient(conn))
|
|
|
|
chainID, err := rootfs.ApplyLayers(ctx, layers, snapshotter, applier)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.G(ctx).Infof("chain ID: %s", chainID.String())
|
|
|
|
return nil
|
|
},
|
|
}
|
|
|
|
var rootfsPrepareCommand = cli.Command{
|
|
Name: "prepare",
|
|
Usage: "prepare gets mount commands for digest",
|
|
ArgsUsage: "[flags] <digest> <target>",
|
|
Flags: []cli.Flag{},
|
|
Action: func(clicontext *cli.Context) error {
|
|
ctx, cancel := appContext()
|
|
defer cancel()
|
|
|
|
if clicontext.NArg() != 2 {
|
|
return cli.ShowSubcommandHelp(clicontext)
|
|
}
|
|
|
|
dgst, err := digest.Parse(clicontext.Args().Get(0))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
target := clicontext.Args().Get(1)
|
|
|
|
log.G(ctx).Infof("preparing mounts %s", dgst.String())
|
|
|
|
conn, err := connectGRPC(clicontext)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
snapshotter := snapshotservice.NewSnapshotterFromClient(snapshotapi.NewSnapshotClient(conn))
|
|
|
|
mounts, err := snapshotter.Prepare(ctx, target, dgst.String())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, m := range mounts {
|
|
fmt.Fprintf(os.Stdout, "mount -t %s %s %s -o %s\n", m.Type, m.Source, target, strings.Join(m.Options, ","))
|
|
}
|
|
|
|
return nil
|
|
},
|
|
}
|