From eef47ffad309b19dc7d32b51c20121941e39123b Mon Sep 17 00:00:00 2001 From: Derek McGowan Date: Wed, 20 Sep 2017 14:23:26 -0700 Subject: [PATCH] Add platform filtering on children handler Fixes pulling of multi-arch images by limiting the expansion of the index by filtering to the current default platform. Signed-off-by: Derek McGowan --- client.go | 5 +++-- cmd/ctr/images.go | 2 +- export.go | 3 ++- image.go | 2 +- images/handlers.go | 19 +++++++++++++++++-- images/image.go | 6 +++--- 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/client.go b/client.go index 2c7227241..497ebb5cd 100644 --- a/client.go +++ b/client.go @@ -23,6 +23,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/errdefs" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/platforms" "github.com/containerd/containerd/plugin" "github.com/containerd/containerd/reference" "github.com/containerd/containerd/remotes" @@ -226,7 +227,7 @@ func (c *Client) Pull(ctx context.Context, ref string, opts ...RemoteOpts) (Imag } else { handler = images.Handlers(append(pullCtx.BaseHandlers, remotes.FetchHandler(store, fetcher), - images.ChildrenHandler(store))..., + images.ChildrenHandler(store, platforms.Default()))..., ) } @@ -307,7 +308,7 @@ func (c *Client) Push(ctx context.Context, ref string, desc ocispec.Descriptor, pushHandler := remotes.PushHandler(cs, pusher) handlers := append(pushCtx.BaseHandlers, - images.ChildrenHandler(cs), + images.ChildrenHandler(cs, platforms.Default()), filterHandler, pushHandler, ) diff --git a/cmd/ctr/images.go b/cmd/ctr/images.go index f64fbaeb4..ce12fb0d3 100644 --- a/cmd/ctr/images.go +++ b/cmd/ctr/images.go @@ -58,7 +58,7 @@ var imagesListCommand = cli.Command{ tw := tabwriter.NewWriter(os.Stdout, 1, 8, 1, ' ', 0) fmt.Fprintln(tw, "REF\tTYPE\tDIGEST\tSIZE\tPLATFORM\tLABELS\t") for _, image := range imageList { - size, err := image.Size(ctx, cs) + size, err := image.Size(ctx, cs, platforms.Default()) if err != nil { log.G(ctx).WithError(err).Errorf("failed calculating size for image %s", image.Name) } diff --git a/export.go b/export.go index 8cafa1675..76bebe3cd 100644 --- a/export.go +++ b/export.go @@ -9,6 +9,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/images" + "github.com/containerd/containerd/platforms" ocispecs "github.com/opencontainers/image-spec/specs-go" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" @@ -32,7 +33,7 @@ func (c *Client) exportToOCITar(ctx context.Context, desc ocispec.Descriptor, wr } handlers := images.Handlers( - images.ChildrenHandler(cs), + images.ChildrenHandler(cs, platforms.Default()), images.HandlerFunc(exportHandler), ) diff --git a/image.go b/image.go index 5390a6d6c..f46046d64 100644 --- a/image.go +++ b/image.go @@ -50,7 +50,7 @@ func (i *image) RootFS(ctx context.Context) ([]digest.Digest, error) { func (i *image) Size(ctx context.Context) (int64, error) { provider := i.client.ContentStore() - return i.i.Size(ctx, provider) + return i.i.Size(ctx, provider, platforms.Default()) } func (i *image) Config(ctx context.Context) (ocispec.Descriptor, error) { diff --git a/images/handlers.go b/images/handlers.go index 53248f018..d1c225ed9 100644 --- a/images/handlers.go +++ b/images/handlers.go @@ -7,6 +7,7 @@ import ( "github.com/containerd/containerd/content" "github.com/containerd/containerd/log" + "github.com/containerd/containerd/platforms" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "golang.org/x/sync/errgroup" @@ -127,7 +128,7 @@ func Dispatch(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) // // One can also replace this with another implementation to allow descending of // arbitrary types. -func ChildrenHandler(provider content.Provider) HandlerFunc { +func ChildrenHandler(provider content.Provider, platform string) HandlerFunc { return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { var descs []ocispec.Descriptor switch desc.MediaType { @@ -157,7 +158,21 @@ func ChildrenHandler(provider content.Provider) HandlerFunc { return nil, err } - descs = append(descs, index.Manifests...) + if platform != "" { + matcher, err := platforms.Parse(platform) + if err != nil { + return nil, err + } + + for _, d := range index.Manifests { + if d.Platform == nil || matcher.Match(*d.Platform) { + descs = append(descs, d) + } + } + } else { + descs = append(descs, index.Manifests...) + } + case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerGzip, MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig, ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerGzip: diff --git a/images/image.go b/images/image.go index 674cf0874..763db1517 100644 --- a/images/image.go +++ b/images/image.go @@ -58,7 +58,7 @@ func (image *Image) RootFS(ctx context.Context, provider content.Provider, platf } // Size returns the total size of an image's packed resources. -func (image *Image) Size(ctx context.Context, provider content.Provider) (int64, error) { +func (image *Image) Size(ctx context.Context, provider content.Provider, platform string) (int64, error) { var size int64 return size, Walk(ctx, Handlers(HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { if desc.Size < 0 { @@ -66,7 +66,7 @@ func (image *Image) Size(ctx context.Context, provider content.Provider) (int64, } size += desc.Size return nil, nil - }), ChildrenHandler(provider)), image.Target) + }), ChildrenHandler(provider, platform)), image.Target) } func Manifest(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform string) (ocispec.Manifest, error) { @@ -196,7 +196,7 @@ func Platforms(ctx context.Context, provider content.Provider, image ocispec.Des platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture})) } return nil, nil - }), ChildrenHandler(provider)), image) + }), ChildrenHandler(provider, "")), image) } // RootFS returns the unpacked diffids that make up and images rootfs.