add optional check that snapshotter supports the image platform when unpacking
Signed-off-by: Kathryn Baldauf <kabaldau@microsoft.com>
This commit is contained in:
67
image.go
67
image.go
@@ -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()
|
||||
}
|
||||
|
Reference in New Issue
Block a user