15
15
package cmd
16
16
17
17
import (
18
+ "errors"
18
19
"fmt"
19
20
"io"
20
21
"os"
21
22
"runtime"
23
+ "strings"
22
24
23
25
"github.com/GoogleContainerTools/container-structure-test/cmd/container-structure-test/app/cmd/test"
24
26
v1 "github.com/opencontainers/image-spec/specs-go/v1"
@@ -32,6 +34,7 @@ import (
32
34
33
35
docker "github.com/fsouza/go-dockerclient"
34
36
"github.com/google/go-containerregistry/pkg/name"
37
+ gcrv1 "github.com/google/go-containerregistry/pkg/v1"
35
38
"github.com/google/go-containerregistry/pkg/v1/daemon"
36
39
"github.com/google/go-containerregistry/pkg/v1/layout"
37
40
"github.com/sirupsen/logrus"
@@ -44,13 +47,60 @@ Be sure you know what you're doing before continuing!
44
47
45
48
Continue? (y/n)`
46
49
50
+ const maxSubIndexes = 5
51
+
47
52
var (
48
53
opts = & config.StructureTestOptions {}
49
54
50
55
args * drivers.DriverConfig
51
56
driverImpl func (drivers.DriverConfig ) (drivers.Driver , error )
57
+
58
+ errNoImageFound = errors .New ("no compatible image found" )
52
59
)
53
60
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
+
54
104
func NewCmdTest (out io.Writer ) * cobra.Command {
55
105
var testCmd = & cobra.Command {
56
106
Use : "test" ,
@@ -124,14 +174,22 @@ func run(out io.Writer) error {
124
174
125
175
desc := m .Manifests [0 ]
126
176
177
+ var img gcrv1.Image
127
178
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
+ }
132
183
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
+ }
135
193
}
136
194
137
195
var tag name.Tag
0 commit comments