add optional check that snapshotter supports the image platform when unpacking

Signed-off-by: Kathryn Baldauf <kabaldau@microsoft.com>
This commit is contained in:
Kathryn Baldauf
2019-08-29 15:57:12 -07:00
parent 1e624fa3de
commit f8992f451c
7 changed files with 150 additions and 6 deletions

View File

@@ -18,6 +18,7 @@ package containerd
import (
"context"
"encoding/json"
"fmt"
"strings"
"sync/atomic"
@@ -281,11 +282,22 @@ type UnpackConfig struct {
ApplyOpts []diff.ApplyOpt
// SnapshotOpts for configuring a snapshotter
SnapshotOpts []snapshots.Opt
// CheckPlatformSupported is whether to validate that a snapshotter
// supports an image's platform before unpacking
CheckPlatformSupported bool
}
// UnpackOpt provides configuration for unpack
type UnpackOpt func(context.Context, *UnpackConfig) error
// WithSnapshotterPlatformCheck sets `CheckPlatformSupported` on the UnpackConfig
func WithSnapshotterPlatformCheck() UnpackOpt {
return func(ctx context.Context, uc *UnpackConfig) error {
uc.CheckPlatformSupported = true
return nil
}
}
func (i *image) Unpack(ctx context.Context, snapshotterName string, opts ...UnpackOpt) error {
ctx, done, err := i.client.WithLease(ctx)
if err != nil {
@@ -300,7 +312,12 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string, opts ...Unpa
}
}
layers, err := i.getLayers(ctx, i.platform)
manifest, err := i.getManifest(ctx, i.platform)
if err != nil {
return err
}
layers, err := i.getLayers(ctx, i.platform, manifest)
if err != nil {
return err
}
@@ -320,6 +337,12 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string, opts ...Unpa
if err != nil {
return err
}
if config.CheckPlatformSupported {
if err := i.checkSnapshotterSupport(ctx, snapshotterName, manifest); err != nil {
return err
}
}
for _, layer := range layers {
unpacked, err = rootfs.ApplyLayerWithOpts(ctx, layer, chain, sn, a, config.SnapshotOpts, config.ApplyOpts)
if err != nil {
@@ -361,14 +384,17 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string, opts ...Unpa
return err
}
func (i *image) getLayers(ctx context.Context, platform platforms.MatchComparer) ([]rootfs.Layer, error) {
cs := i.client.ContentStore()
func (i *image) getManifest(ctx context.Context, platform platforms.MatchComparer) (ocispec.Manifest, error) {
cs := i.ContentStore()
manifest, err := images.Manifest(ctx, cs, i.i.Target, platform)
if err != nil {
return nil, err
return ocispec.Manifest{}, err
}
return manifest, nil
}
func (i *image) getLayers(ctx context.Context, platform platforms.MatchComparer, manifest ocispec.Manifest) ([]rootfs.Layer, error) {
cs := i.ContentStore()
diffIDs, err := i.i.RootFS(ctx, cs, platform)
if err != nil {
return nil, errors.Wrap(err, "failed to resolve rootfs")
@@ -388,6 +414,37 @@ func (i *image) getLayers(ctx context.Context, platform platforms.MatchComparer)
return layers, nil
}
func (i *image) getManifestPlatform(ctx context.Context, manifest ocispec.Manifest) (ocispec.Platform, error) {
cs := i.ContentStore()
p, err := content.ReadBlob(ctx, cs, manifest.Config)
if err != nil {
return ocispec.Platform{}, err
}
var image ocispec.Image
if err := json.Unmarshal(p, &image); err != nil {
return ocispec.Platform{}, err
}
return platforms.Normalize(ocispec.Platform{OS: image.OS, Architecture: image.Architecture}), nil
}
func (i *image) checkSnapshotterSupport(ctx context.Context, snapshotterName string, manifest ocispec.Manifest) error {
snapshotterPlatformMatcher, err := i.client.GetSnapshotterSupportedPlatforms(ctx, snapshotterName)
if err != nil {
return err
}
manifestPlatform, err := i.getManifestPlatform(ctx, manifest)
if err != nil {
return err
}
if snapshotterPlatformMatcher.Match(manifestPlatform) {
return nil
}
return fmt.Errorf("snapshotter %s does not support platform %s for image %s", snapshotterName, manifestPlatform, manifest.Config.Digest)
}
func (i *image) ContentStore() content.Store {
return i.client.ContentStore()
}