1515package cmd
1616
1717import (
18+ "errors"
1819 "fmt"
1920 "io"
2021 "os"
2122 "runtime"
23+ "strings"
2224
2325 "github.com/GoogleContainerTools/container-structure-test/cmd/container-structure-test/app/cmd/test"
2426 v1 "github.com/opencontainers/image-spec/specs-go/v1"
@@ -32,6 +34,7 @@ import (
3234
3335 docker "github.com/fsouza/go-dockerclient"
3436 "github.com/google/go-containerregistry/pkg/name"
37+ gcrv1 "github.com/google/go-containerregistry/pkg/v1"
3538 "github.com/google/go-containerregistry/pkg/v1/daemon"
3639 "github.com/google/go-containerregistry/pkg/v1/layout"
3740 "github.com/sirupsen/logrus"
@@ -44,13 +47,60 @@ Be sure you know what you're doing before continuing!
4447
4548Continue? (y/n)`
4649
50+ const maxSubIndexes = 5
51+
4752var (
4853 opts = & config.StructureTestOptions {}
4954
5055 args * drivers.DriverConfig
5156 driverImpl func (drivers.DriverConfig ) (drivers.Driver , error )
57+
58+ errNoImageFound = errors .New ("no compatible image found" )
5259)
5360
61+ func parsePlatform (s string ) (* gcrv1.Platform , error ) {
62+ parts := strings .Split (s , "/" )
63+ if len (parts ) != 2 {
64+ return nil , fmt .Errorf ("invalid platform %q" , s )
65+ }
66+ os , arch := parts [0 ], parts [1 ]
67+ platform := & gcrv1.Platform {
68+ Architecture : arch ,
69+ OS : os ,
70+ }
71+ return platform , nil
72+ }
73+
74+ func findImageInIndex (index gcrv1.ImageIndex , requirements * gcrv1.Platform , depth int ) (gcrv1.Image , error ) {
75+ if depth > maxSubIndexes {
76+ return nil , fmt .Errorf ("too many subindexes (%d)" , maxSubIndexes )
77+ }
78+
79+ manifest , err := index .IndexManifest ()
80+ if err != nil {
81+ return nil , fmt .Errorf ("failed to read index manifest: %w" , err )
82+ }
83+
84+ for _ , desc := range manifest .Manifests {
85+ if desc .MediaType .IsImage () && desc .Platform .Satisfies (* requirements ) {
86+ return index .Image (desc .Digest )
87+ }
88+ if desc .MediaType .IsIndex () {
89+ // Recursively check subindex.
90+ childIndex , err := index .ImageIndex (desc .Digest )
91+ if err != nil {
92+ return nil , err
93+ }
94+ img , err := findImageInIndex (childIndex , requirements , depth + 1 )
95+ if ! errors .Is (err , errNoImageFound ) {
96+ return img , err
97+ }
98+ }
99+ }
100+
101+ return nil , errNoImageFound
102+ }
103+
54104func NewCmdTest (out io.Writer ) * cobra.Command {
55105 var testCmd = & cobra.Command {
56106 Use : "test" ,
@@ -124,14 +174,22 @@ func run(out io.Writer) error {
124174
125175 desc := m .Manifests [0 ]
126176
177+ var img gcrv1.Image
127178 if desc .MediaType .IsIndex () {
128- logrus . Fatal ( "multi-arch images are not supported yet." )
129- }
130-
131- img , err := l . Image ( desc . Digest )
179+ platform , err := parsePlatform ( opts . Platform )
180+ if err != nil {
181+ logrus . Fatalf ( "%s" , err )
182+ }
132183
133- if err != nil {
134- logrus .Fatalf ("could not get image from %s: %v" , opts .ImageFromLayout , err )
184+ img , err = findImageInIndex (l , platform , 0 )
185+ if err != nil {
186+ logrus .Fatalf ("could not get image from %s (platform %v): %v" , opts .ImageFromLayout , opts .Platform , err )
187+ }
188+ } else {
189+ img , err = l .Image (desc .Digest )
190+ if err != nil {
191+ logrus .Fatalf ("could not get image from %s: %v" , opts .ImageFromLayout , err )
192+ }
135193 }
136194
137195 var tag name.Tag
0 commit comments