content: unify provider and ingester
The split between provider and ingester was a long standing division reflecting the client-side use cases. For the most part, we were differentiating these for the algorithms that operate them, but it made instantation and use of the types challenging. On the server-side, this distinction is generally less important. This change unifies these types and in the process we get a few benefits. The first is that we now completely access the content store over GRPC. This was the initial intent and we have now satisfied this goal completely. There are a few issues around listing content and getting status, but we resolve these with simple streaming and regexp filters. More can probably be done to polish this but the result is clean. Several other content-oriented methods were polished in the process of unification. We have now properly seperated out the `Abort` method to cancel ongoing or stalled ingest processes. We have also replaced the `Active` method with a single status method. The transition went extremely smoothly. Once the clients were updated to use the new methods, every thing worked as expected on the first compile. Signed-off-by: Stephen J Day <stephen.day@docker.com>
This commit is contained in:
@@ -242,7 +242,7 @@ func serveDebugAPI() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func resolveContentStore() (*content.Store, error) {
|
||||
func resolveContentStore() (content.Store, error) {
|
||||
cp := filepath.Join(conf.Root, "content")
|
||||
return content.NewStore(cp)
|
||||
}
|
||||
@@ -315,7 +315,7 @@ func loadMonitor() (plugin.ContainerMonitor, error) {
|
||||
return plugin.NewMultiContainerMonitor(monitors...), nil
|
||||
}
|
||||
|
||||
func loadSnapshotter(store *content.Store) (snapshot.Snapshotter, error) {
|
||||
func loadSnapshotter(store content.Store) (snapshot.Snapshotter, error) {
|
||||
for name, sr := range plugin.Registrations() {
|
||||
if sr.Type != plugin.SnapshotPlugin {
|
||||
continue
|
||||
@@ -356,7 +356,7 @@ func newGRPCServer() *grpc.Server {
|
||||
return s
|
||||
}
|
||||
|
||||
func loadServices(runtimes map[string]containerd.Runtime, store *content.Store, sn snapshot.Snapshotter, meta *bolt.DB) ([]plugin.Service, error) {
|
||||
func loadServices(runtimes map[string]containerd.Runtime, store content.Store, sn snapshot.Snapshotter, meta *bolt.DB) ([]plugin.Service, error) {
|
||||
var o []plugin.Service
|
||||
for name, sr := range plugin.Registrations() {
|
||||
if sr.Type != plugin.GRPCPlugin {
|
||||
|
||||
@@ -78,7 +78,7 @@ var runCommand = cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
provider, err := getContentProvider(context)
|
||||
content, err := getContentStore(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -102,7 +102,7 @@ var runCommand = cli.Command{
|
||||
}
|
||||
// let's close out our db and tx so we don't hold the lock whilst running.
|
||||
|
||||
diffIDs, err := image.RootFS(ctx, provider)
|
||||
diffIDs, err := image.RootFS(ctx, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -123,13 +123,13 @@ var runCommand = cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
ic, err := image.Config(ctx, provider)
|
||||
ic, err := image.Config(ctx, content)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch ic.MediaType {
|
||||
case ocispec.MediaTypeImageConfig, images.MediaTypeDockerSchema2Config:
|
||||
r, err := provider.Reader(ctx, ic.Digest)
|
||||
r, err := content.Reader(ctx, ic.Digest)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -35,12 +35,12 @@ func getExecutionService(context *cli.Context) (execution.ContainerServiceClient
|
||||
return execution.NewContainerServiceClient(conn), nil
|
||||
}
|
||||
|
||||
func getContentProvider(context *cli.Context) (content.Provider, error) {
|
||||
func getContentStore(context *cli.Context) (content.Store, error) {
|
||||
conn, err := getGRPCConnection(context)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return contentservice.NewProviderFromClient(contentapi.NewContentClient(conn)), nil
|
||||
return contentservice.NewStoreFromClient(contentapi.NewContentClient(conn)), nil
|
||||
}
|
||||
|
||||
func getRootFSService(context *cli.Context) (rootfsapi.RootFSClient, error) {
|
||||
|
||||
11
cmd/dist/active.go
vendored
11
cmd/dist/active.go
vendored
@@ -13,7 +13,7 @@ import (
|
||||
var activeCommand = cli.Command{
|
||||
Name: "active",
|
||||
Usage: "display active transfers.",
|
||||
ArgsUsage: "[flags] [<key>, ...]",
|
||||
ArgsUsage: "[flags] [<regexp>]",
|
||||
Description: `Display the ongoing transfers.`,
|
||||
Flags: []cli.Flag{
|
||||
cli.DurationFlag{
|
||||
@@ -28,12 +28,19 @@ var activeCommand = cli.Command{
|
||||
},
|
||||
},
|
||||
Action: func(context *cli.Context) error {
|
||||
var (
|
||||
match = context.Args().First()
|
||||
)
|
||||
|
||||
ctx, cancel := appContext()
|
||||
defer cancel()
|
||||
|
||||
cs, err := resolveContentStore(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
active, err := cs.Active()
|
||||
active, err := cs.Status(ctx, match)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
11
cmd/dist/common.go
vendored
11
cmd/dist/common.go
vendored
@@ -12,11 +12,13 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/containerd/console"
|
||||
contentapi "github.com/containerd/containerd/api/services/content"
|
||||
imagesapi "github.com/containerd/containerd/api/services/images"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
"github.com/containerd/containerd/remotes/docker"
|
||||
contentservice "github.com/containerd/containerd/services/content"
|
||||
imagesservice "github.com/containerd/containerd/services/images"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
@@ -42,7 +44,7 @@ var registryFlags = []cli.Flag{
|
||||
},
|
||||
}
|
||||
|
||||
func resolveContentStore(context *cli.Context) (*content.Store, error) {
|
||||
func resolveContentStore(context *cli.Context) (content.Store, error) {
|
||||
root := filepath.Join(context.GlobalString("root"), "content")
|
||||
if !filepath.IsAbs(root) {
|
||||
var err error
|
||||
@@ -51,7 +53,12 @@ func resolveContentStore(context *cli.Context) (*content.Store, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return content.NewStore(root)
|
||||
conn, err := connectGRPC(context)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return contentservice.NewStoreFromClient(contentapi.NewContentClient(conn)), nil
|
||||
}
|
||||
|
||||
func resolveImageStore(clicontext *cli.Context) (images.Store, error) {
|
||||
|
||||
9
cmd/dist/edit.go
vendored
9
cmd/dist/edit.go
vendored
@@ -9,7 +9,7 @@ import (
|
||||
"os/exec"
|
||||
|
||||
contentapi "github.com/containerd/containerd/api/services/content"
|
||||
contentservice "github.com/containerd/containerd/services/content"
|
||||
"github.com/containerd/containerd/services/content"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
@@ -50,10 +50,9 @@ var editCommand = cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
provider := contentservice.NewProviderFromClient(contentapi.NewContentClient(conn))
|
||||
ingester := contentservice.NewIngesterFromClient(contentapi.NewContentClient(conn))
|
||||
content := content.NewStoreFromClient(contentapi.NewContentClient(conn))
|
||||
|
||||
rc, err := provider.Reader(ctx, dgst)
|
||||
rc, err := content.Reader(ctx, dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -65,7 +64,7 @@ var editCommand = cli.Command{
|
||||
}
|
||||
defer nrc.Close()
|
||||
|
||||
wr, err := ingester.Writer(ctx, "edit-"+object, 0, "") // TODO(stevvooe): Choose a better key?
|
||||
wr, err := content.Writer(ctx, "edit-"+object, 0, "") // TODO(stevvooe): Choose a better key?
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
9
cmd/dist/fetch.go
vendored
9
cmd/dist/fetch.go
vendored
@@ -59,8 +59,7 @@ Most of this is experimental and there are few leaps to make this work.`,
|
||||
|
||||
ongoing := newJobs()
|
||||
|
||||
ingester := contentservice.NewIngesterFromClient(contentapi.NewContentClient(conn))
|
||||
provider := contentservice.NewProviderFromClient(contentapi.NewContentClient(conn))
|
||||
content := contentservice.NewStoreFromClient(contentapi.NewContentClient(conn))
|
||||
|
||||
// TODO(stevvooe): Need to replace this with content store client.
|
||||
cs, err := resolveContentStore(clicontext)
|
||||
@@ -85,8 +84,8 @@ Most of this is experimental and there are few leaps to make this work.`,
|
||||
ongoing.add(remotes.MakeRefKey(ctx, desc))
|
||||
return nil, nil
|
||||
}),
|
||||
remotes.FetchHandler(ingester, fetcher),
|
||||
images.ChildrenHandler(provider),
|
||||
remotes.FetchHandler(content, fetcher),
|
||||
images.ChildrenHandler(content),
|
||||
),
|
||||
desc)
|
||||
})
|
||||
@@ -114,7 +113,7 @@ Most of this is experimental and there are few leaps to make this work.`,
|
||||
|
||||
activeSeen := map[string]struct{}{}
|
||||
if !done {
|
||||
active, err := cs.Active()
|
||||
active, err := cs.Status(ctx, "")
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Error("active check failed")
|
||||
continue
|
||||
|
||||
6
cmd/dist/get.go
vendored
6
cmd/dist/get.go
vendored
@@ -4,8 +4,6 @@ import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
contentapi "github.com/containerd/containerd/api/services/content"
|
||||
contentservice "github.com/containerd/containerd/services/content"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
@@ -25,13 +23,11 @@ var getCommand = cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
conn, err := connectGRPC(context)
|
||||
cs, err := resolveContentStore(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
cs := contentservice.NewProviderFromClient(contentapi.NewContentClient(conn))
|
||||
|
||||
rc, err := cs.Reader(ctx, dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
8
cmd/dist/images.go
vendored
8
cmd/dist/images.go
vendored
@@ -5,10 +5,8 @@ import (
|
||||
"os"
|
||||
"text/tabwriter"
|
||||
|
||||
contentapi "github.com/containerd/containerd/api/services/content"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/progress"
|
||||
contentservice "github.com/containerd/containerd/services/content"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
@@ -29,13 +27,11 @@ var imagesListCommand = cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
conn, err := connectGRPC(clicontext)
|
||||
cs, err := resolveContentStore(clicontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
provider := contentservice.NewProviderFromClient(contentapi.NewContentClient(conn))
|
||||
|
||||
images, err := imageStore.List(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to list images")
|
||||
@@ -44,7 +40,7 @@ var imagesListCommand = cli.Command{
|
||||
tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0)
|
||||
fmt.Fprintln(tw, "REF\tTYPE\tDIGEST\tSIZE\t")
|
||||
for _, image := range images {
|
||||
size, err := image.Size(ctx, provider)
|
||||
size, err := image.Size(ctx, cs)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Errorf("failed calculating size for image %s", image.Name)
|
||||
}
|
||||
|
||||
14
cmd/dist/ingest.go
vendored
14
cmd/dist/ingest.go
vendored
@@ -3,9 +3,7 @@ package main
|
||||
import (
|
||||
"os"
|
||||
|
||||
contentapi "github.com/containerd/containerd/api/services/content"
|
||||
"github.com/containerd/containerd/content"
|
||||
contentservice "github.com/containerd/containerd/services/content"
|
||||
"github.com/opencontainers/go-digest"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli"
|
||||
@@ -40,20 +38,18 @@ var ingestCommand = cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
conn, err := connectGRPC(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if ref == "" {
|
||||
return errors.New("must specify a transaction reference")
|
||||
}
|
||||
|
||||
ingester := contentservice.NewIngesterFromClient(contentapi.NewContentClient(conn))
|
||||
cs, err := resolveContentStore(context)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// TODO(stevvooe): Allow ingest to be reentrant. Currently, we expect
|
||||
// all data to be written in a single invocation. Allow multiple writes
|
||||
// to the same transaction key followed by a commit.
|
||||
return content.WriteBlob(ctx, ingester, ref, os.Stdin, expectedSize, expectedDigest)
|
||||
return content.WriteBlob(ctx, cs, ref, os.Stdin, expectedSize, expectedDigest)
|
||||
},
|
||||
}
|
||||
|
||||
15
cmd/dist/list.go
vendored
15
cmd/dist/list.go
vendored
@@ -9,7 +9,6 @@ import (
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/log"
|
||||
units "github.com/docker/go-units"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
"github.com/urfave/cli"
|
||||
)
|
||||
|
||||
@@ -46,8 +45,8 @@ var listCommand = cli.Command{
|
||||
|
||||
var walkFn content.WalkFunc
|
||||
if quiet {
|
||||
walkFn = func(path string, fi os.FileInfo, dgst digest.Digest) error {
|
||||
fmt.Println(dgst)
|
||||
walkFn = func(info content.Info) error {
|
||||
fmt.Println(info.Digest)
|
||||
return nil
|
||||
}
|
||||
} else {
|
||||
@@ -55,16 +54,16 @@ var listCommand = cli.Command{
|
||||
defer tw.Flush()
|
||||
|
||||
fmt.Fprintln(tw, "DIGEST\tSIZE\tAGE")
|
||||
walkFn = func(path string, fi os.FileInfo, dgst digest.Digest) error {
|
||||
walkFn = func(info content.Info) error {
|
||||
fmt.Fprintf(tw, "%s\t%s\t%s\n",
|
||||
dgst,
|
||||
units.HumanSize(float64(fi.Size())),
|
||||
units.HumanDuration(time.Since(fi.ModTime())))
|
||||
info.Digest,
|
||||
units.HumanSize(float64(info.Size)),
|
||||
units.HumanDuration(time.Since(info.CommittedAt)))
|
||||
return nil
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return cs.Walk(walkFn)
|
||||
return cs.Walk(ctx, walkFn)
|
||||
},
|
||||
}
|
||||
|
||||
29
cmd/dist/pull.go
vendored
29
cmd/dist/pull.go
vendored
@@ -7,14 +7,12 @@ import (
|
||||
"text/tabwriter"
|
||||
"time"
|
||||
|
||||
contentapi "github.com/containerd/containerd/api/services/content"
|
||||
rootfsapi "github.com/containerd/containerd/api/services/rootfs"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/images"
|
||||
"github.com/containerd/containerd/log"
|
||||
"github.com/containerd/containerd/progress"
|
||||
"github.com/containerd/containerd/remotes"
|
||||
contentservice "github.com/containerd/containerd/services/content"
|
||||
rootfsservice "github.com/containerd/containerd/services/rootfs"
|
||||
"github.com/opencontainers/image-spec/identity"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
@@ -44,7 +42,7 @@ command. As part of this process, we do the following:
|
||||
ctx, cancel := appContext()
|
||||
defer cancel()
|
||||
|
||||
conn, err := connectGRPC(clicontext)
|
||||
cs, err := resolveContentStore(clicontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -60,15 +58,6 @@ command. As part of this process, we do the following:
|
||||
}
|
||||
ongoing := newJobs()
|
||||
|
||||
// TODO(stevvooe): Must unify this type.
|
||||
ingester := contentservice.NewIngesterFromClient(contentapi.NewContentClient(conn))
|
||||
provider := contentservice.NewProviderFromClient(contentapi.NewContentClient(conn))
|
||||
|
||||
cs, err := resolveContentStore(clicontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
eg, ctx := errgroup.WithContext(ctx)
|
||||
|
||||
var resolvedImageName string
|
||||
@@ -93,8 +82,8 @@ command. As part of this process, we do the following:
|
||||
ongoing.add(remotes.MakeRefKey(ctx, desc))
|
||||
return nil, nil
|
||||
}),
|
||||
remotes.FetchHandler(ingester, fetcher),
|
||||
images.ChildrenHandler(provider)),
|
||||
remotes.FetchHandler(cs, fetcher),
|
||||
images.ChildrenHandler(cs)),
|
||||
desc)
|
||||
|
||||
})
|
||||
@@ -118,9 +107,7 @@ command. As part of this process, we do the following:
|
||||
log.G(ctx).Fatal(err)
|
||||
}
|
||||
|
||||
provider := contentservice.NewProviderFromClient(contentapi.NewContentClient(conn))
|
||||
|
||||
p, err := content.ReadBlob(ctx, provider, image.Target.Digest)
|
||||
p, err := content.ReadBlob(ctx, cs, image.Target.Digest)
|
||||
if err != nil {
|
||||
log.G(ctx).Fatal(err)
|
||||
}
|
||||
@@ -130,6 +117,10 @@ command. As part of this process, we do the following:
|
||||
log.G(ctx).Fatal(err)
|
||||
}
|
||||
|
||||
conn, err := connectGRPC(clicontext)
|
||||
if err != nil {
|
||||
log.G(ctx).Fatal(err)
|
||||
}
|
||||
rootfs := rootfsservice.NewUnpackerFromClient(rootfsapi.NewRootFSClient(conn))
|
||||
|
||||
log.G(ctx).Info("unpacking rootfs")
|
||||
@@ -138,7 +129,7 @@ command. As part of this process, we do the following:
|
||||
log.G(ctx).Fatal(err)
|
||||
}
|
||||
|
||||
diffIDs, err := image.RootFS(ctx, provider)
|
||||
diffIDs, err := image.RootFS(ctx, cs)
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Fatal("failed resolving rootfs")
|
||||
}
|
||||
@@ -168,7 +159,7 @@ command. As part of this process, we do the following:
|
||||
|
||||
activeSeen := map[string]struct{}{}
|
||||
if !done {
|
||||
active, err := cs.Active()
|
||||
active, err := cs.Status(ctx, "")
|
||||
if err != nil {
|
||||
log.G(ctx).WithError(err).Error("active check failed")
|
||||
continue
|
||||
|
||||
10
cmd/dist/rootfs.go
vendored
10
cmd/dist/rootfs.go
vendored
@@ -8,11 +8,9 @@ import (
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
contentapi "github.com/containerd/containerd/api/services/content"
|
||||
rootfsapi "github.com/containerd/containerd/api/services/rootfs"
|
||||
"github.com/containerd/containerd/content"
|
||||
"github.com/containerd/containerd/log"
|
||||
contentservice "github.com/containerd/containerd/services/content"
|
||||
rootfsservice "github.com/containerd/containerd/services/rootfs"
|
||||
digest "github.com/opencontainers/go-digest"
|
||||
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
||||
@@ -49,8 +47,12 @@ var rootfsUnpackCommand = cli.Command{
|
||||
return err
|
||||
}
|
||||
|
||||
provider := contentservice.NewProviderFromClient(contentapi.NewContentClient(conn))
|
||||
m, err := resolveManifest(ctx, provider, dgst)
|
||||
cs, err := resolveContentStore(clicontext)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
m, err := resolveManifest(ctx, cs, dgst)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user