Skip to content

Commit 0db4700

Browse files
authored
feat: --platform flag (GoogleContainerTools#380)
* feat: --platform flag - for images under test, pass the new --platform flag to pull the corresponding image if it is multi-platform capable - test execution via CreateContainerOptions passes in platform. If unset, will default to linux/amd64 * add e2e tests for --platform usage gofmt tidy specify correct folder for platform tests * set default value from host runtime * update flags section in docs * only need to support linux for running containers MacOS cannot run containers natively. M1/M2 defaults to linux/arm64 so the "os" field as part of --platform only needs to use linux/ as a default with GOARCH read in for the particular CPU architecture. Same deal with Windows, Docker on windows is virtualized Linux (AFAIU)
1 parent 8212f6e commit 0db4700

File tree

8 files changed

+79
-23
lines changed

8 files changed

+79
-23
lines changed

README.md

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -378,19 +378,22 @@ container_structure_test(
378378
### Flags:
379379
`container-structure-test test -h`
380380
```
381-
-c, --config stringArray test config files
382-
-d, --driver string driver to use when running tests (default "docker")
383-
-f, --force force run of host driver (without user prompt)
384-
-h, --help help for test
385-
-i, --image string path to test image
386-
--metadata string path to image metadata file
387-
--no-color no color in the output
388-
-o, --output string output format for the test report (available format: text, json, junit) (default "text")
389-
--pull force a pull of the image before running tests
390-
-q, --quiet flag to suppress output
391-
--runtime string runtime to use with docker driver
392-
--save preserve created containers after test run
393-
--test-report string generate test report and write it to specified file (supported format: json, junit; default: json)
381+
-c, --config stringArray test config files
382+
--default-image-tag string default image tag to used when loading images to the daemon. required when --image-from-oci-layout refers to a oci layout lacking the reference annotation.
383+
-d, --driver string driver to use when running tests (default "docker")
384+
-f, --force force run of host driver (without user prompt)
385+
-h, --help help for test
386+
-i, --image string path to test image
387+
--image-from-oci-layout string path to the oci layout to test against
388+
--metadata string path to image metadata file
389+
--no-color no color in the output
390+
-o, --output string output format for the test report (available format: text, json, junit) (default "text")
391+
--platform string Set platform if host is multi-platform capable (default "linux/amd64")
392+
--pull force a pull of the image before running tests
393+
-q, --quiet flag to suppress output
394+
--runtime string runtime to use with docker driver
395+
--save preserve created containers after test run
396+
--test-report string generate test report and write it to specified file (supported format: json, junit; default: json)
394397
```
395398
See this [example repo](https://github.com/nkubala/structure-test-examples) for a full working example.
396399

cmd/container-structure-test/app/cmd/test.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import (
1818
"fmt"
1919
"io"
2020
"os"
21-
21+
"runtime"
2222
"github.com/GoogleContainerTools/container-structure-test/cmd/container-structure-test/app/cmd/test"
2323
v1 "github.com/opencontainers/image-spec/specs-go/v1"
2424

@@ -99,6 +99,7 @@ func run(out io.Writer) error {
9999
Save: opts.Save,
100100
Metadata: opts.Metadata,
101101
Runtime: opts.Runtime,
102+
Platform: opts.Platform,
102103
}
103104

104105
var err error
@@ -170,6 +171,7 @@ func run(out io.Writer) error {
170171
logrus.Fatalf("error connecting to daemon: %v", err)
171172
}
172173
if err = client.PullImage(docker.PullImageOptions{
174+
Platform: opts.Platform,
173175
Repository: ref.Context().RepositoryStr(),
174176
Tag: ref.Identifier(),
175177
Registry: ref.Context().RegistryStr(),
@@ -223,7 +225,7 @@ func AddTestFlags(cmd *cobra.Command) {
223225
cmd.Flags().StringVarP(&opts.Driver, "driver", "d", "docker", "driver to use when running tests")
224226
cmd.Flags().StringVar(&opts.Metadata, "metadata", "", "path to image metadata file")
225227
cmd.Flags().StringVar(&opts.Runtime, "runtime", "", "runtime to use with docker driver")
226-
228+
cmd.Flags().StringVar(&opts.Platform, "platform", fmt.Sprintf("linux/%s", runtime.GOARCH), "Set platform if host is multi-platform capable")
227229
cmd.Flags().BoolVar(&opts.Pull, "pull", false, "force a pull of the image before running tests")
228230
cmd.MarkFlagsMutuallyExclusive("image-from-oci-layout", "pull")
229231
cmd.Flags().BoolVar(&opts.Save, "save", false, "preserve created containers after test run")

go.mod

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ go 1.19
44

55
require (
66
github.com/GoogleContainerTools/container-diff v0.17.1-0.20230727210151-35d9770aeea3
7-
github.com/fsouza/go-dockerclient v1.9.7
7+
github.com/fsouza/go-dockerclient v1.10.0
88
github.com/google/go-cmp v0.5.9
99
github.com/google/go-containerregistry v0.15.2
1010
github.com/joho/godotenv v1.5.1
@@ -16,6 +16,8 @@ require (
1616
gopkg.in/yaml.v2 v2.4.0
1717
)
1818

19+
exclude github.com/docker/docker v24.0.6+incompatible // indirect
20+
1921
require (
2022
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
2123
github.com/Microsoft/go-winio v0.6.1 // indirect
@@ -32,7 +34,7 @@ require (
3234
github.com/klauspost/compress v1.16.5 // indirect
3335
github.com/kr/text v0.2.0 // indirect
3436
github.com/mitchellh/go-homedir v1.1.0 // indirect
35-
github.com/moby/patternmatcher v0.5.0 // indirect
37+
github.com/moby/patternmatcher v0.6.0 // indirect
3638
github.com/moby/sys/sequential v0.5.0 // indirect
3739
github.com/moby/term v0.0.0-20221205130635-1aeaba878587 // indirect
3840
github.com/morikuni/aec v1.0.0 // indirect

go.sum

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
7777
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
7878
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
7979
github.com/fsouza/go-dockerclient v1.3.6/go.mod h1:ptN6nXBwrXuiHAz2TYGOFCBB1aKGr371sGjMFdJEr1A=
80-
github.com/fsouza/go-dockerclient v1.9.7 h1:FlIrT71E62zwKgRvCvWGdxRD+a/pIy+miY/n3MXgfuw=
81-
github.com/fsouza/go-dockerclient v1.9.7/go.mod h1:vx9C32kE2D15yDSOMCDaAEIARZpDQDFBHeqL3MgQy/U=
80+
github.com/fsouza/go-dockerclient v1.10.0 h1:ppSBsbR60I1DFbV4Ag7LlHlHakHFRNLk9XakATW1yVQ=
81+
github.com/fsouza/go-dockerclient v1.10.0/go.mod h1:+iNzAW78AzClIBTZ6WFjkaMvOgz68GyCJ236b1opLTs=
8282
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
8383
github.com/go-ini/ini v1.25.4/go.mod h1:ByCAeIL28uOIIG0E3PJtZPDL8WnHpFKFOtgjp+3Ies8=
8484
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
@@ -148,8 +148,8 @@ github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG
148148
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
149149
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
150150
github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A=
151-
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
152-
github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
151+
github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk=
152+
github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
153153
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
154154
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
155155
github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo=

pkg/config/options.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type StructureTestOptions struct {
2222
DefaultImageTag string
2323
Driver string
2424
Runtime string
25+
Platform string
2526
Metadata string
2627
TestReport string
2728
ConfigFiles []string

pkg/drivers/docker_driver.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ type DockerDriver struct {
4242
env map[string]string
4343
save bool
4444
runtime string
45+
platform string
4546
runOpts unversioned.ContainerRunOptions
4647
}
4748

@@ -57,6 +58,7 @@ func NewDockerDriver(args DriverConfig) (Driver, error) {
5758
env: nil,
5859
save: args.Save,
5960
runtime: args.Runtime,
61+
platform: args.Platform,
6062
runOpts: args.RunOpts,
6163
}, nil
6264
}
@@ -98,6 +100,7 @@ func (d *DockerDriver) Destroy() {
98100
func (d *DockerDriver) SetEnv(envVars []unversioned.EnvVar) error {
99101
env := d.processEnvVars(envVars)
100102
container, err := d.cli.CreateContainer(docker.CreateContainerOptions{
103+
Platform: d.platform,
101104
Config: &docker.Config{
102105
Image: d.currentImage,
103106
Env: env,
@@ -205,6 +208,7 @@ func (d *DockerDriver) retrieveTar(path string) (*tar.Reader, error) {
205208
// this contains a placeholder command which does not get run, since
206209
// the client doesn't allow creating a container without a command.
207210
container, err := d.cli.CreateContainer(docker.CreateContainerOptions{
211+
Platform: d.platform,
208212
Config: &docker.Config{
209213
Image: d.currentImage,
210214
Cmd: []string{utils.NoopCommand},
@@ -316,6 +320,7 @@ func (d *DockerDriver) ReadDir(target string) ([]os.FileInfo, error) {
316320
// and sets that image as the new "current image"
317321
func (d *DockerDriver) runAndCommit(env []string, command []string) (string, error) {
318322
createOpts := docker.CreateContainerOptions{
323+
Platform: d.platform,
319324
Config: &docker.Config{
320325
Image: d.currentImage,
321326
Env: env,
@@ -365,6 +370,7 @@ func (d *DockerDriver) runAndCommit(env []string, command []string) (string, err
365370

366371
func (d *DockerDriver) exec(env []string, command []string) (string, string, int, error) {
367372
createOpts := docker.CreateContainerOptions{
373+
Platform: d.platform,
368374
Config: &docker.Config{
369375
Image: d.currentImage,
370376
Env: env,

pkg/drivers/driver.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ type DriverConfig struct {
3333
Save bool // used by Docker/Tar drivers
3434
Metadata string // used by Host driver
3535
Runtime string // used by Docker driver
36+
Platform string // used by Docker driver
3637
RunOpts unversioned.ContainerRunOptions // used by Docker driver
3738
}
3839

tests/structure_test_tests.sh

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,7 +230,7 @@ then
230230
echo "$res"
231231
echo "$code"
232232
failures=$((failures +1))
233-
else
233+
else
234234
echo "PASS: oci failing test case"
235235
fi
236236

@@ -242,10 +242,51 @@ then
242242
echo "$res"
243243
echo "$code"
244244
failures=$((failures +1))
245-
else
245+
else
246246
echo "PASS: oci success test case"
247247
fi
248248

249+
HEADER "Platform test cases"
250+
251+
docker run --rm --privileged tonistiigi/binfmt --install all > /dev/null
252+
res=$(./out/container-structure-test test --image "$test_image" --platform="linux/$go_architecture" --config "${test_config_dir}/ubuntu_20_04_test.yaml" 2>&1)
253+
code=$?
254+
if ! [[ ("$res" =~ "PASS" && "$code" == "0") ]];
255+
then
256+
echo "FAIL: current host platform test case"
257+
echo "$res"
258+
echo "$code"
259+
failures=$((failures +1))
260+
else
261+
echo "PASS: current host platform test case"
262+
fi
263+
264+
res=$(./out/container-structure-test test --image "$test_image" --platform="linux/riscv64" --config "${test_config_dir}/ubuntu_20_04_test.yaml" 2>&1)
265+
code=$?
266+
if ! [[ ("$res" =~ image\ with\ reference.+was\ found\ but\ does\ not\ match\ the\ specified\ platform:\ wanted\ linux\/\riscv64,\ actual:\ linux\/$go_architecture && "$code" == "1") ]];
267+
then
268+
echo "FAIL: platform failing test case"
269+
echo "$res"
270+
echo "$code"
271+
failures=$((failures +1))
272+
else
273+
echo "PASS: platform failing test case"
274+
fi
275+
276+
test_config_dir="${test_dir}/s390x"
277+
res=$(./out/container-structure-test test --image "$test_image" --platform="linux/s390x" --pull --config "${test_config_dir}/ubuntu_20_04_test.yaml" 2>&1)
278+
code=$?
279+
if ! [[ ("$res" =~ "PASS" && "$code" == "0") ]];
280+
then
281+
echo "FAIL: platform w/ --pull test case"
282+
echo "$res"
283+
echo "$code"
284+
failures=$((failures +1))
285+
else
286+
echo "PASS: platform w/ --pull test case"
287+
fi
288+
289+
249290
if [ $failures -gt 0 ]; then
250291
echo "Some tests did not pass. $failures"
251292
exit 1

0 commit comments

Comments
 (0)