mirror of
https://github.com/moby/moby.git
synced 2026-01-11 10:41:43 +00:00
Currently the image export and load APIs can be used to export or load all platforms for the image, or a single specified platform. This commit updates the API so that it accepts a list of platforms to export or load, thereby giving clients the ability to export only selected platforms of an image into a tar file, or load selected platforms from a tar file. Unit and integration tests were updated accordingly. As this requires a daemon API change, the API version was bumped. Signed-off-by: Cesar Talledo <cesar.talledo@docker.com>
202 lines
5.7 KiB
Go
202 lines
5.7 KiB
Go
package containerd
|
|
|
|
import (
|
|
"reflect"
|
|
"runtime"
|
|
"testing"
|
|
|
|
"github.com/containerd/platforms"
|
|
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
|
|
"gotest.tools/v3/assert"
|
|
is "gotest.tools/v3/assert/cmp"
|
|
"gotest.tools/v3/skip"
|
|
)
|
|
|
|
var (
|
|
pLinuxAmd64 = ocispec.Platform{
|
|
OS: "linux",
|
|
Architecture: "amd64",
|
|
}
|
|
|
|
pLinuxArmv5 = ocispec.Platform{
|
|
OS: "linux",
|
|
Architecture: "arm",
|
|
Variant: "v5",
|
|
}
|
|
|
|
pLinuxArmv6 = ocispec.Platform{
|
|
OS: "linux",
|
|
Architecture: "arm",
|
|
Variant: "v6",
|
|
}
|
|
|
|
pLinuxArm64 = ocispec.Platform{
|
|
OS: "linux",
|
|
Architecture: "arm64",
|
|
Variant: "v8",
|
|
}
|
|
|
|
pWindowsAmd64 = ocispec.Platform{
|
|
OS: "windows",
|
|
Architecture: "amd64",
|
|
OSVersion: "10.0.14393",
|
|
}
|
|
)
|
|
|
|
type requestedAndFirst struct {
|
|
// Whether platforms.Only or OnlyStrict should be used
|
|
// Nil means both should be the same
|
|
strict *bool
|
|
requested *ocispec.Platform
|
|
first *ocispec.Platform
|
|
}
|
|
|
|
type indexTestCase struct {
|
|
name string
|
|
index []ocispec.Platform
|
|
tc []requestedAndFirst
|
|
}
|
|
|
|
func TestMatcherOnLinuxArm64v8(t *testing.T) {
|
|
daemonPlatform := platforms.Only(ocispec.Platform{
|
|
OS: "linux",
|
|
Architecture: "arm64",
|
|
Variant: "v8",
|
|
})
|
|
|
|
yes := true
|
|
no := false
|
|
|
|
for _, indexTc := range []indexTestCase{
|
|
{
|
|
name: "linux_amd64_armv5_armv6_arm64-windows_amd64",
|
|
index: []ocispec.Platform{pLinuxAmd64, pLinuxArmv5, pLinuxArmv6, pLinuxArm64, pWindowsAmd64},
|
|
tc: []requestedAndFirst{
|
|
{requested: nil, first: &pLinuxArm64},
|
|
{requested: &ocispec.Platform{OS: "linux", Architecture: "amd64"}, first: &pLinuxAmd64},
|
|
{requested: &ocispec.Platform{OS: "windows", Architecture: "amd64"}, first: &pWindowsAmd64},
|
|
|
|
// Select highest possible arm variant
|
|
{strict: &yes, requested: &ocispec.Platform{OS: "linux", Architecture: "arm"}, first: nil},
|
|
{strict: &no, requested: &ocispec.Platform{OS: "linux", Architecture: "arm"}, first: &pLinuxArmv6},
|
|
|
|
{requested: &ocispec.Platform{OS: "linux", Architecture: "arm", Variant: "v5"}, first: &pLinuxArmv5},
|
|
|
|
// Variant not present
|
|
{strict: &yes, requested: &ocispec.Platform{OS: "linux", Architecture: "arm", Variant: "v8"}, first: nil},
|
|
{strict: &no, requested: &ocispec.Platform{OS: "linux", Architecture: "arm", Variant: "v8"}, first: &pLinuxArmv6},
|
|
|
|
{requested: &ocispec.Platform{OS: "linux", Architecture: "s390x"}, first: nil},
|
|
},
|
|
},
|
|
} {
|
|
testOnlyAndOnlyStrict(t, daemonPlatform, indexTc)
|
|
}
|
|
}
|
|
|
|
func TestMatcherOnWindowsAmd64(t *testing.T) {
|
|
skip.If(t, runtime.GOOS != "windows", "TODO: containerd matcher only matches OSVersion when on Windows")
|
|
daemonPlatform := platforms.Only(ocispec.Platform{
|
|
OS: "windows",
|
|
Architecture: "amd64",
|
|
OSVersion: "10.0.18362",
|
|
})
|
|
|
|
for _, indexTc := range []indexTestCase{
|
|
{
|
|
name: "various windows",
|
|
index: []ocispec.Platform{
|
|
{OS: "windows", Architecture: "amd64", OSVersion: "10.0.14393"},
|
|
{OS: "windows", Architecture: "amd64", OSVersion: "10.0.17763"},
|
|
{OS: "windows", Architecture: "amd64", OSVersion: "10.0.18362"},
|
|
{OS: "windows", Architecture: "amd64", OSVersion: "10.0.19041"},
|
|
},
|
|
tc: []requestedAndFirst{
|
|
{requested: nil, first: &ocispec.Platform{OS: "windows", Architecture: "amd64", OSVersion: "10.0.18362"}},
|
|
{requested: &ocispec.Platform{OS: "windows", Architecture: "amd64"}, first: &ocispec.Platform{OS: "windows", Architecture: "amd64", OSVersion: "10.0.14393"}},
|
|
},
|
|
},
|
|
} {
|
|
testOnlyAndOnlyStrict(t, daemonPlatform, indexTc)
|
|
}
|
|
}
|
|
|
|
func testOnlyAndOnlyStrict(t *testing.T, daemonPlatform platforms.MatchComparer, indexTc indexTestCase) {
|
|
imgSvc := ImageService{}
|
|
imgSvc.defaultPlatformOverride = daemonPlatform
|
|
|
|
t.Run(indexTc.name, func(t *testing.T) {
|
|
indexTc := indexTc
|
|
idx := indexTc.index
|
|
for _, tc := range indexTc.tc {
|
|
for _, strict := range []bool{false, true} {
|
|
s := "non-strict"
|
|
if strict {
|
|
s = "strict"
|
|
}
|
|
if tc.strict != nil && *tc.strict != strict {
|
|
continue
|
|
}
|
|
|
|
req := "default"
|
|
if tc.requested != nil {
|
|
req = platforms.FormatAll(*tc.requested)
|
|
}
|
|
wanted := "none"
|
|
if tc.first != nil {
|
|
wanted = platforms.FormatAll(*tc.first)
|
|
}
|
|
t.Run(s+"/"+req+"=>"+wanted, func(t *testing.T) {
|
|
pm := imgSvc.matchRequestedOrDefault(platforms.Only, tc.requested)
|
|
if strict {
|
|
pm = imgSvc.matchRequestedOrDefault(platforms.OnlyStrict, tc.requested)
|
|
}
|
|
|
|
var first *ocispec.Platform
|
|
for _, p := range idx {
|
|
if !pm.Match(p) {
|
|
continue
|
|
}
|
|
if first == nil || pm.Less(p, *first) {
|
|
first = &p
|
|
}
|
|
}
|
|
|
|
assert.Check(t, is.DeepEqual(first, tc.first))
|
|
})
|
|
}
|
|
}
|
|
})
|
|
}
|
|
func TestPlatformsWithPreferenceMatcher(t *testing.T) {
|
|
platformList := []ocispec.Platform{
|
|
pLinuxAmd64,
|
|
pLinuxArmv5,
|
|
pLinuxArmv6,
|
|
pLinuxArm64,
|
|
pWindowsAmd64,
|
|
}
|
|
|
|
// Use pLinuxArm64 as the preferred platform
|
|
preferred := platforms.Only(pLinuxArm64)
|
|
matcher := matchAnyWithPreference(preferred, platformList)
|
|
|
|
// Should match all platforms in the list
|
|
for _, p := range platformList {
|
|
assert.Assert(t, matcher.Match(p), "matcher should match platform: %v", platforms.Format(p))
|
|
}
|
|
|
|
// Should not match a platform not in the list
|
|
notInList := ocispec.Platform{OS: "linux", Architecture: "s390x"}
|
|
assert.Assert(t, !matcher.Match(notInList), "matcher should not match platform: %v", platforms.Format(notInList))
|
|
|
|
// Test Less: preferred should be less than others
|
|
for _, p := range platformList {
|
|
if reflect.DeepEqual(p, pLinuxArm64) {
|
|
continue
|
|
}
|
|
assert.Assert(t, matcher.Less(pLinuxArm64, p), "preferred platform should be less than %v", platforms.Format(p))
|
|
assert.Assert(t, !matcher.Less(p, pLinuxArm64), "%v should not be less than preferred platform", platforms.Format(p))
|
|
}
|
|
}
|