Support for multi-arch image unpacking

Resolves the platform on multi-arch manifests during unpack and config resolving.

Signed-off-by: Derek McGowan <derek@mcgstyle.net>
This commit is contained in:
Derek McGowan
2017-09-13 15:42:05 -07:00
parent 49437711c3
commit 46ded63f2d
7 changed files with 112 additions and 39 deletions

View File

@@ -6,6 +6,7 @@ import (
"time"
"github.com/containerd/containerd/content"
"github.com/containerd/containerd/errdefs"
"github.com/containerd/containerd/platforms"
digest "github.com/opencontainers/go-digest"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
@@ -40,16 +41,16 @@ type Store interface {
//
// The caller can then use the descriptor to resolve and process the
// configuration of the image.
func (image *Image) Config(ctx context.Context, provider content.Provider) (ocispec.Descriptor, error) {
return Config(ctx, provider, image.Target)
func (image *Image) Config(ctx context.Context, provider content.Provider, platform string) (ocispec.Descriptor, error) {
return Config(ctx, provider, image.Target, platform)
}
// RootFS returns the unpacked diffids that make up and images rootfs.
//
// These are used to verify that a set of layers unpacked to the expected
// values.
func (image *Image) RootFS(ctx context.Context, provider content.Provider) ([]digest.Digest, error) {
desc, err := image.Config(ctx, provider)
func (image *Image) RootFS(ctx context.Context, provider content.Provider, platform string) ([]digest.Digest, error) {
desc, err := image.Config(ctx, provider, platform)
if err != nil {
return nil, err
}
@@ -68,17 +69,23 @@ func (image *Image) Size(ctx context.Context, provider content.Provider) (int64,
}), ChildrenHandler(provider)), image.Target)
}
// Config resolves the image configuration descriptor using a content provided
// to resolve child resources on the image.
//
// The caller can then use the descriptor to resolve and process the
// configuration of the image.
func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor) (ocispec.Descriptor, error) {
var configDesc ocispec.Descriptor
return configDesc, Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
func Manifest(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform string) (ocispec.Manifest, error) {
var (
matcher platforms.Matcher
m *ocispec.Manifest
err error
)
if platform != "" {
matcher, err = platforms.Parse(platform)
if err != nil {
return ocispec.Manifest{}, err
}
}
if err := Walk(ctx, HandlerFunc(func(ctx context.Context, desc ocispec.Descriptor) ([]ocispec.Descriptor, error) {
switch desc.MediaType {
case MediaTypeDockerSchema2Manifest, ocispec.MediaTypeImageManifest:
p, err := content.ReadBlob(ctx, provider, image.Digest)
p, err := content.ReadBlob(ctx, provider, desc.Digest)
if err != nil {
return nil, err
}
@@ -88,14 +95,80 @@ func Config(ctx context.Context, provider content.Provider, image ocispec.Descri
return nil, err
}
configDesc = manifest.Config
if platform != "" {
if desc.Platform != nil && !matcher.Match(*desc.Platform) {
return nil, nil
}
if desc.Platform == nil {
p, err := content.ReadBlob(ctx, provider, manifest.Config.Digest)
if err != nil {
return nil, err
}
var image ocispec.Image
if err := json.Unmarshal(p, &image); err != nil {
return nil, err
}
if !matcher.Match(platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture})) {
return nil, nil
}
}
}
m = &manifest
return nil, nil
default:
return nil, errors.New("could not resolve config")
}
case MediaTypeDockerSchema2ManifestList, ocispec.MediaTypeImageIndex:
p, err := content.ReadBlob(ctx, provider, desc.Digest)
if err != nil {
return nil, err
}
}), image)
var idx ocispec.Index
if err := json.Unmarshal(p, &idx); err != nil {
return nil, err
}
if platform == "" {
return idx.Manifests, nil
}
var descs []ocispec.Descriptor
for _, d := range idx.Manifests {
if d.Platform == nil || matcher.Match(*d.Platform) {
descs = append(descs, d)
}
}
return descs, nil
}
return nil, errors.New("could not resolve manifest")
}), image); err != nil {
return ocispec.Manifest{}, err
}
if m == nil {
return ocispec.Manifest{}, errors.Wrap(errdefs.ErrNotFound, "manifest not found")
}
return *m, nil
}
// Config resolves the image configuration descriptor using a content provided
// to resolve child resources on the image.
//
// The caller can then use the descriptor to resolve and process the
// configuration of the image.
func Config(ctx context.Context, provider content.Provider, image ocispec.Descriptor, platform string) (ocispec.Descriptor, error) {
manifest, err := Manifest(ctx, provider, image, platform)
if err != nil {
return ocispec.Descriptor{}, err
}
return manifest.Config, err
}
// Platforms returns one or more platforms supported by the image.