@@ -18,6 +18,7 @@ package containerd
1818
1919import (
2020 "context"
21+ "encoding/json"
2122 "fmt"
2223 "strings"
2324 "sync/atomic"
@@ -281,11 +282,22 @@ type UnpackConfig struct {
281282 ApplyOpts []diff.ApplyOpt
282283 // SnapshotOpts for configuring a snapshotter
283284 SnapshotOpts []snapshots.Opt
285+ // CheckPlatformSupported is whether to validate that a snapshotter
286+ // supports an image's platform before unpacking
287+ CheckPlatformSupported bool
284288}
285289
286290// UnpackOpt provides configuration for unpack
287291type UnpackOpt func (context.Context , * UnpackConfig ) error
288292
293+ // WithSnapshotterPlatformCheck sets `CheckPlatformSupported` on the UnpackConfig
294+ func WithSnapshotterPlatformCheck () UnpackOpt {
295+ return func (ctx context.Context , uc * UnpackConfig ) error {
296+ uc .CheckPlatformSupported = true
297+ return nil
298+ }
299+ }
300+
289301func (i * image ) Unpack (ctx context.Context , snapshotterName string , opts ... UnpackOpt ) error {
290302 ctx , done , err := i .client .WithLease (ctx )
291303 if err != nil {
@@ -300,7 +312,12 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string, opts ...Unpa
300312 }
301313 }
302314
303- layers , err := i .getLayers (ctx , i .platform )
315+ manifest , err := i .getManifest (ctx , i .platform )
316+ if err != nil {
317+ return err
318+ }
319+
320+ layers , err := i .getLayers (ctx , i .platform , manifest )
304321 if err != nil {
305322 return err
306323 }
@@ -320,6 +337,12 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string, opts ...Unpa
320337 if err != nil {
321338 return err
322339 }
340+ if config .CheckPlatformSupported {
341+ if err := i .checkSnapshotterSupport (ctx , snapshotterName , manifest ); err != nil {
342+ return err
343+ }
344+ }
345+
323346 for _ , layer := range layers {
324347 unpacked , err = rootfs .ApplyLayerWithOpts (ctx , layer , chain , sn , a , config .SnapshotOpts , config .ApplyOpts )
325348 if err != nil {
@@ -361,14 +384,17 @@ func (i *image) Unpack(ctx context.Context, snapshotterName string, opts ...Unpa
361384 return err
362385}
363386
364- func (i * image ) getLayers (ctx context.Context , platform platforms.MatchComparer ) ([]rootfs.Layer , error ) {
365- cs := i .client .ContentStore ()
366-
387+ func (i * image ) getManifest (ctx context.Context , platform platforms.MatchComparer ) (ocispec.Manifest , error ) {
388+ cs := i .ContentStore ()
367389 manifest , err := images .Manifest (ctx , cs , i .i .Target , platform )
368390 if err != nil {
369- return nil , err
391+ return ocispec. Manifest {} , err
370392 }
393+ return manifest , nil
394+ }
371395
396+ func (i * image ) getLayers (ctx context.Context , platform platforms.MatchComparer , manifest ocispec.Manifest ) ([]rootfs.Layer , error ) {
397+ cs := i .ContentStore ()
372398 diffIDs , err := i .i .RootFS (ctx , cs , platform )
373399 if err != nil {
374400 return nil , errors .Wrap (err , "failed to resolve rootfs" )
@@ -388,6 +414,37 @@ func (i *image) getLayers(ctx context.Context, platform platforms.MatchComparer)
388414 return layers , nil
389415}
390416
417+ func (i * image ) getManifestPlatform (ctx context.Context , manifest ocispec.Manifest ) (ocispec.Platform , error ) {
418+ cs := i .ContentStore ()
419+ p , err := content .ReadBlob (ctx , cs , manifest .Config )
420+ if err != nil {
421+ return ocispec.Platform {}, err
422+ }
423+
424+ var image ocispec.Image
425+ if err := json .Unmarshal (p , & image ); err != nil {
426+ return ocispec.Platform {}, err
427+ }
428+ return platforms .Normalize (ocispec.Platform {OS : image .OS , Architecture : image .Architecture }), nil
429+ }
430+
431+ func (i * image ) checkSnapshotterSupport (ctx context.Context , snapshotterName string , manifest ocispec.Manifest ) error {
432+ snapshotterPlatformMatcher , err := i .client .GetSnapshotterSupportedPlatforms (ctx , snapshotterName )
433+ if err != nil {
434+ return err
435+ }
436+
437+ manifestPlatform , err := i .getManifestPlatform (ctx , manifest )
438+ if err != nil {
439+ return err
440+ }
441+
442+ if snapshotterPlatformMatcher .Match (manifestPlatform ) {
443+ return nil
444+ }
445+ return fmt .Errorf ("snapshotter %s does not support platform %s for image %s" , snapshotterName , manifestPlatform , manifest .Config .Digest )
446+ }
447+
391448func (i * image ) ContentStore () content.Store {
392449 return i .client .ContentStore ()
393450}
0 commit comments