From 5a124794ae123fdb8b8e37bf9cc89ca34fcf853e Mon Sep 17 00:00:00 2001 From: Stephen J Day Date: Fri, 16 Jun 2017 14:08:31 -0700 Subject: [PATCH] image: add support for pulling manifest lists/oci indexes This PR ensures that we can pull images with manifest lists, aka OCI indexes. After this change, when pulling such an image, the resources will all be available for creating the image. Further support is required to do platform based selection for rootfs creation, so such images may not yet be runnable. This is mostly useful for checkpoint transfers, which use an OCI index for assembling the component set. Signed-off-by: Stephen J Day --- images/handlers.go | 50 ++++++++++++++++++++++++++++----------------- remotes/handlers.go | 11 +++++----- 2 files changed, 37 insertions(+), 24 deletions(-) diff --git a/images/handlers.go b/images/handlers.go index bea61f31a..c87804633 100644 --- a/images/handlers.go +++ b/images/handlers.go @@ -6,6 +6,7 @@ import ( "fmt" "github.com/containerd/containerd/content" + "github.com/containerd/containerd/log" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "github.com/pkg/errors" "golang.org/x/sync/errgroup" @@ -128,32 +129,43 @@ func Dispatch(ctx context.Context, handler Handler, descs ...ocispec.Descriptor) // arbitrary types. func ChildrenHandler(provider content.Provider) HandlerFunc { return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { + var descs []ocispec.Descriptor switch desc.MediaType { case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: + p, err := content.ReadBlob(ctx, provider, desc.Digest) + if err != nil { + return nil, err + } + + // TODO(stevvooe): We just assume oci manifest, for now. There may be + // subtle differences from the docker version. + var manifest ocispec.Manifest + if err := json.Unmarshal(p, &manifest); err != nil { + return nil, err + } + + descs = append(descs, manifest.Config) + descs = append(descs, manifest.Layers...) + case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: + p, err := content.ReadBlob(ctx, provider, desc.Digest) + if err != nil { + return nil, err + } + + var index ocispec.Index + if err := json.Unmarshal(p, &index); err != nil { + return nil, err + } + + descs = append(descs, index.Manifests...) case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerGzip, - MediaTypeDockerSchema2Config: + MediaTypeDockerSchema2Config, ocispec.MediaTypeImageLayer, + ocispec.MediaTypeImageLayerGzip: // childless data types. return nil, nil default: - return nil, fmt.Errorf("%v not yet supported", desc.MediaType) + log.G(ctx).Warnf("encounted unknown type %v; children may not be fetched", desc.MediaType) } - p, err := content.ReadBlob(ctx, provider, desc.Digest) - if err != nil { - return nil, err - } - - // TODO(stevvooe): We just assume oci manifest, for now. There may be - // subtle differences from the docker version. - var manifest ocispec.Manifest - if err := json.Unmarshal(p, &manifest); err != nil { - return nil, err - } - - var descs []ocispec.Descriptor - - descs = append(descs, manifest.Config) - descs = append(descs, manifest.Layers...) - return descs, nil } } diff --git a/remotes/handlers.go b/remotes/handlers.go index a5d9baf73..a81177326 100644 --- a/remotes/handlers.go +++ b/remotes/handlers.go @@ -20,10 +20,13 @@ func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string { // product of the context, which may include information about the ongoing // fetch process. switch desc.MediaType { - case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest, - images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: + case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: return "manifest-" + desc.Digest.String() - case images.MediaTypeDockerSchema2Layer, images.MediaTypeDockerSchema2LayerGzip: + case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: + return "index-" + desc.Digest.String() + case images.MediaTypeDockerSchema2Layer, images.MediaTypeDockerSchema2LayerGzip, + ocispec.MediaTypeImageLayer, ocispec.MediaTypeImageLayerGzip, + ocispec.MediaTypeImageLayerNonDistributable, ocispec.MediaTypeImageLayerNonDistributableGzip: return "layer-" + desc.Digest.String() case images.MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig: return "config-" + desc.Digest.String() @@ -45,8 +48,6 @@ func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc })) switch desc.MediaType { - case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex: - return nil, fmt.Errorf("%v not yet supported", desc.MediaType) case images.MediaTypeDockerSchema1Manifest: return nil, fmt.Errorf("%v not supported", desc.MediaType) default: