From 38a6f90f2b3d4d87a6c5bbc0bea15d9cbe19da21 Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Wed, 8 Mar 2017 22:04:44 -0800 Subject: [PATCH] Add rootfs command to dist Commands allows preparing a rootfs from a manifest hash Signed-off-by: Derek McGowan (github: dmcgowan) --- cmd/containerd/main.go | 3 ++ cmd/dist/main.go | 1 + cmd/dist/rootfs.go | 91 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) create mode 100644 cmd/dist/rootfs.go diff --git a/cmd/containerd/main.go b/cmd/containerd/main.go index 5b69c6a..bd2d27a 100644 --- a/cmd/containerd/main.go +++ b/cmd/containerd/main.go @@ -19,6 +19,7 @@ import ( "github.com/docker/containerd" contentapi "github.com/docker/containerd/api/services/content" api "github.com/docker/containerd/api/services/execution" + rootfsapi "github.com/docker/containerd/api/services/rootfs" "github.com/docker/containerd/content" "github.com/docker/containerd/log" "github.com/docker/containerd/plugin" @@ -366,6 +367,8 @@ func interceptor(ctx gocontext.Context, ctx = log.WithModule(ctx, "execution") case contentapi.ContentServer: ctx = log.WithModule(ctx, "content") + case rootfsapi.RootFSServer: + ctx = log.WithModule(ctx, "rootfs") default: fmt.Printf("unknown GRPC server type: %#v\n", info.Server) } diff --git a/cmd/dist/main.go b/cmd/dist/main.go index cf96ad5..f29af17 100644 --- a/cmd/dist/main.go +++ b/cmd/dist/main.go @@ -69,6 +69,7 @@ distribution tool deleteCommand, listCommand, applyCommand, + rootfsCommand, } app.Before = func(context *cli.Context) error { var ( diff --git a/cmd/dist/rootfs.go b/cmd/dist/rootfs.go new file mode 100644 index 0000000..e9075c8 --- /dev/null +++ b/cmd/dist/rootfs.go @@ -0,0 +1,91 @@ +package main + +import ( + "context" + "encoding/json" + "io/ioutil" + + contentapi "github.com/docker/containerd/api/services/content" + rootfsapi "github.com/docker/containerd/api/services/rootfs" + "github.com/docker/containerd/content" + "github.com/docker/containerd/log" + contentservice "github.com/docker/containerd/services/content" + rootfsservice "github.com/docker/containerd/services/rootfs" + 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{ + rootfsPrepareCommand, + }, +} + +var rootfsPrepareCommand = cli.Command{ + Name: "prepare", + Usage: "prepare applies layers from a manifest to a snapshot", + ArgsUsage: "[flags] ", + Flags: []cli.Flag{}, + Action: func(clicontext *cli.Context) error { + var ( + ctx = background + ) + + dgst, err := digest.Parse(clicontext.Args().First()) + if err != nil { + return err + } + + log.G(ctx).Infof("preparing manifest %s", dgst.String()) + + conn, err := connectGRPC(clicontext) + if err != nil { + return err + } + + provider := contentservice.NewProviderFromClient(contentapi.NewContentClient(conn)) + m, err := resolveManifest(ctx, provider, dgst) + if err != nil { + return err + } + + preparer := rootfsservice.NewPreparerFromClient(rootfsapi.NewRootFSClient(conn)) + chainID, err := preparer.Prepare(ctx, m.Layers) + if err != nil { + return err + } + + log.G(ctx).Infof("chain ID: %s", chainID.String()) + + return nil + }, +} + +func resolveManifest(ctx context.Context, provider content.Provider, dgst digest.Digest) (ocispec.Manifest, error) { + p, err := readAll(ctx, provider, dgst) + if err != nil { + return ocispec.Manifest{}, err + } + + // TODO(stevvooe): This assumption that we get a manifest is unfortunate. + // Need to provide way to resolve what the type of the target is. + var manifest ocispec.Manifest + if err := json.Unmarshal(p, &manifest); err != nil { + return ocispec.Manifest{}, err + } + + return manifest, nil +} + +func readAll(ctx context.Context, provider content.Provider, dgst digest.Digest) ([]byte, error) { + rc, err := provider.Reader(ctx, dgst) + if err != nil { + return nil, err + } + defer rc.Close() + + return ioutil.ReadAll(rc) +}