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 <stephen.day@docker.com>
This commit is contained in:
Stephen J Day 2017-06-16 14:08:31 -07:00
parent 9d155e8164
commit 5a124794ae
No known key found for this signature in database
GPG Key ID: 67B3DED84EDC823F
2 changed files with 37 additions and 24 deletions

View File

@ -6,6 +6,7 @@ import (
"fmt" "fmt"
"github.com/containerd/containerd/content" "github.com/containerd/containerd/content"
"github.com/containerd/containerd/log"
ocispec "github.com/opencontainers/image-spec/specs-go/v1" ocispec "github.com/opencontainers/image-spec/specs-go/v1"
"github.com/pkg/errors" "github.com/pkg/errors"
"golang.org/x/sync/errgroup" "golang.org/x/sync/errgroup"
@ -128,32 +129,43 @@ func Dispatch(ctx context.Context, handler Handler, descs ...ocispec.Descriptor)
// arbitrary types. // arbitrary types.
func ChildrenHandler(provider content.Provider) HandlerFunc { func ChildrenHandler(provider content.Provider) HandlerFunc {
return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) { return func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
var descs []ocispec.Descriptor
switch desc.MediaType { switch desc.MediaType {
case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest: 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, case MediaTypeDockerSchema2Layer, MediaTypeDockerSchema2LayerGzip,
MediaTypeDockerSchema2Config: MediaTypeDockerSchema2Config, ocispec.MediaTypeImageLayer,
ocispec.MediaTypeImageLayerGzip: // childless data types.
return nil, nil return nil, nil
default: 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 return descs, nil
} }
} }

View File

@ -20,10 +20,13 @@ func MakeRefKey(ctx context.Context, desc ocispec.Descriptor) string {
// product of the context, which may include information about the ongoing // product of the context, which may include information about the ongoing
// fetch process. // fetch process.
switch desc.MediaType { switch desc.MediaType {
case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest, case images.MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
return "manifest-" + desc.Digest.String() 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() return "layer-" + desc.Digest.String()
case images.MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig: case images.MediaTypeDockerSchema2Config, ocispec.MediaTypeImageConfig:
return "config-" + desc.Digest.String() return "config-" + desc.Digest.String()
@ -45,8 +48,6 @@ func FetchHandler(ingester content.Ingester, fetcher Fetcher) images.HandlerFunc
})) }))
switch desc.MediaType { switch desc.MediaType {
case images.MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
return nil, fmt.Errorf("%v not yet supported", desc.MediaType)
case images.MediaTypeDockerSchema1Manifest: case images.MediaTypeDockerSchema1Manifest:
return nil, fmt.Errorf("%v not supported", desc.MediaType) return nil, fmt.Errorf("%v not supported", desc.MediaType)
default: default: