Update platforms to latest rc

Signed-off-by: Derek McGowan <derek@mcg.dev>
This commit is contained in:
Derek McGowan 2025-01-13 08:18:55 -08:00 committed by k8s-infra-cherrypick-robot
parent c334ae68b8
commit eb125e1dd3
10 changed files with 163 additions and 208 deletions

2
go.mod
View File

@ -24,7 +24,7 @@ require (
github.com/containerd/log v0.1.0
github.com/containerd/nri v0.8.0
github.com/containerd/otelttrpc v0.1.0
github.com/containerd/platforms v1.0.0-rc.0
github.com/containerd/platforms v1.0.0-rc.1
github.com/containerd/plugin v1.0.0
github.com/containerd/ttrpc v1.2.7
github.com/containerd/typeurl/v2 v2.2.3

4
go.sum
View File

@ -61,8 +61,8 @@ github.com/containerd/nri v0.8.0 h1:n1S753B9lX8RFrHYeSgwVvS1yaUcHjxbB+f+xzEncRI=
github.com/containerd/nri v0.8.0/go.mod h1:uSkgBrCdEtAiEz4vnrq8gmAC4EnVAM5Klt0OuK5rZYQ=
github.com/containerd/otelttrpc v0.1.0 h1:UOX68eVTE8H/T45JveIg+I22Ev2aFj4qPITCmXsskjw=
github.com/containerd/otelttrpc v0.1.0/go.mod h1:XhoA2VvaGPW1clB2ULwrBZfXVuEWuyOd2NUD1IM0yTg=
github.com/containerd/platforms v1.0.0-rc.0 h1:GuHWSKgVVO3POn6nRBB4sH63uPOLa87yuuhsGLWaXAA=
github.com/containerd/platforms v1.0.0-rc.0/go.mod h1:T1XAzzOdYs3it7l073MNXyxRwQofJfqwi/8cRjufIk4=
github.com/containerd/platforms v1.0.0-rc.1 h1:83KIq4yy1erSRgOVHNk1HYdPvzdJ5CnsWaRoJX4C41E=
github.com/containerd/platforms v1.0.0-rc.1/go.mod h1:J71L7B+aiM5SdIEqmd9wp6THLVRzJGXfNuWCZCllLA4=
github.com/containerd/plugin v1.0.0 h1:c8Kf1TNl6+e2TtMHZt+39yAPDbouRH9WAToRjex483Y=
github.com/containerd/plugin v1.0.0/go.mod h1:hQfJe5nmWfImiqT1q8Si3jLv3ynMUIBB47bQ+KexvO8=
github.com/containerd/ttrpc v1.2.7 h1:qIrroQvuOL9HQ1X6KHe2ohc7p+HP/0VE6XPU7elJRqQ=

View File

@ -31,6 +31,34 @@ type MatchComparer interface {
Less(specs.Platform, specs.Platform) bool
}
type platformVersions struct {
major []int
minor []int
}
var arm64variantToVersion = map[string]platformVersions{
"v8": {[]int{8}, []int{0}},
"v8.0": {[]int{8}, []int{0}},
"v8.1": {[]int{8}, []int{1}},
"v8.2": {[]int{8}, []int{2}},
"v8.3": {[]int{8}, []int{3}},
"v8.4": {[]int{8}, []int{4}},
"v8.5": {[]int{8}, []int{5}},
"v8.6": {[]int{8}, []int{6}},
"v8.7": {[]int{8}, []int{7}},
"v8.8": {[]int{8}, []int{8}},
"v8.9": {[]int{8}, []int{9}},
"v9": {[]int{9, 8}, []int{0, 5}},
"v9.0": {[]int{9, 8}, []int{0, 5}},
"v9.1": {[]int{9, 8}, []int{1, 6}},
"v9.2": {[]int{9, 8}, []int{2, 7}},
"v9.3": {[]int{9, 8}, []int{3, 8}},
"v9.4": {[]int{9, 8}, []int{4, 9}},
"v9.5": {[]int{9, 8}, []int{5, 9}},
"v9.6": {[]int{9, 8}, []int{6, 9}},
"v9.7": {[]int{9, 8}, []int{7, 9}},
}
// platformVector returns an (ordered) vector of appropriate specs.Platform
// objects to try matching for the given platform object (see platforms.Only).
func platformVector(platform specs.Platform) []specs.Platform {
@ -73,52 +101,19 @@ func platformVector(platform specs.Platform) []specs.Platform {
variant = "v8"
}
majorVariant, minorVariant, hasMinor := strings.Cut(variant, ".")
if armMajor, err := strconv.Atoi(strings.TrimPrefix(majorVariant, "v")); err == nil && armMajor >= 8 {
armMinor := 0
if len(variant) == 4 {
if minor, err := strconv.Atoi(minorVariant); err == nil && hasMinor {
armMinor = minor
}
}
if armMajor == 9 {
for minor := armMinor - 1; minor >= 0; minor-- {
arm64Variant := "v" + strconv.Itoa(armMajor) + "." + strconv.Itoa(minor)
if minor == 0 {
arm64Variant = "v" + strconv.Itoa(armMajor)
}
vector = append(vector, specs.Platform{
Architecture: platform.Architecture,
OS: platform.OS,
OSVersion: platform.OSVersion,
OSFeatures: platform.OSFeatures,
Variant: arm64Variant,
})
}
// v9.0 diverged from v8.5, meaning that v9.x is compatible with v8.{x+5} until v9.4/v8.9
armMinor = armMinor + 5
if armMinor > 9 {
armMinor = 9
}
armMajor = 8
vector = append(vector, specs.Platform{
Architecture: platform.Architecture,
OS: platform.OS,
OSVersion: platform.OSVersion,
OSFeatures: platform.OSFeatures,
Variant: "v8." + strconv.Itoa(armMinor),
})
}
for minor := armMinor - 1; minor >= 0; minor-- {
arm64Variant := "v" + strconv.Itoa(armMajor) + "." + strconv.Itoa(minor)
vector = []specs.Platform{} // Reset vector, the first variant will be added in loop.
arm64Versions, ok := arm64variantToVersion[variant]
if !ok {
break
}
for i, major := range arm64Versions.major {
for minor := arm64Versions.minor[i]; minor >= 0; minor-- {
arm64Variant := "v" + strconv.Itoa(major) + "." + strconv.Itoa(minor)
if minor == 0 {
arm64Variant = "v" + strconv.Itoa(armMajor)
arm64Variant = "v" + strconv.Itoa(major)
}
vector = append(vector, specs.Platform{
Architecture: platform.Architecture,
Architecture: "arm64",
OS: platform.OS,
OSVersion: platform.OSVersion,
OSFeatures: platform.OSFeatures,
@ -129,7 +124,7 @@ func platformVector(platform specs.Platform) []specs.Platform {
// All arm64/v8.x and arm64/v9.x are compatible with arm/v8 (32-bits) and below.
// There's no arm64 v9 variant, so it's normalized to v8.
if strings.HasPrefix(variant, "v8.") || strings.HasPrefix(variant, "v9.") {
if strings.HasPrefix(variant, "v8") || strings.HasPrefix(variant, "v9") {
variant = "v8"
}
vector = append(vector, platformVector(specs.Platform{

View File

@ -86,22 +86,11 @@ func normalizeArch(arch, variant string) (string, string) {
}
case "aarch64", "arm64":
arch = "arm64"
majorVariant, minorVariant, hasMinor := strings.Cut(variant, ".")
majorVariant = strings.TrimPrefix(majorVariant, "v")
if minorVariant == "0" {
minorVariant = ""
hasMinor = false
}
if (majorVariant == "" || majorVariant == "8") && !hasMinor {
// normalize v8 to empty string
switch variant {
case "8", "v8", "v8.0":
variant = ""
} else {
// otherwise to v8.x or v9 or v9.x
variant = "v" + majorVariant
if hasMinor {
variant = variant + "." + minorVariant
}
case "9", "9.0", "v9.0":
variant = "v9"
}
case "armhf":
arch = "arm"

View File

@ -19,8 +19,6 @@ package platforms
import (
"fmt"
"runtime"
"strconv"
"strings"
specs "github.com/opencontainers/image-spec/specs-go/v1"
"golang.org/x/sys/windows"
@ -38,80 +36,6 @@ func DefaultSpec() specs.Platform {
}
}
type windowsmatcher struct {
specs.Platform
osVersionPrefix string
defaultMatcher Matcher
}
// Match matches platform with the same windows major, minor
// and build version.
func (m windowsmatcher) Match(p specs.Platform) bool {
match := m.defaultMatcher.Match(p)
if match && m.OS == "windows" {
// HPC containers do not have OS version filled
if m.OSVersion == "" || p.OSVersion == "" {
return true
}
hostOsVersion := getOSVersion(m.osVersionPrefix)
ctrOsVersion := getOSVersion(p.OSVersion)
return checkHostAndContainerCompat(hostOsVersion, ctrOsVersion)
}
return match
}
func getOSVersion(osVersionPrefix string) osVersion {
parts := strings.Split(osVersionPrefix, ".")
if len(parts) < 3 {
return osVersion{}
}
majorVersion, _ := strconv.ParseUint(parts[0], 10, 8)
minorVersion, _ := strconv.ParseUint(parts[1], 10, 8)
buildNumber, _ := strconv.ParseUint(parts[2], 10, 16)
return osVersion{
MajorVersion: uint8(majorVersion),
MinorVersion: uint8(minorVersion),
Build: uint16(buildNumber),
}
}
// Less sorts matched platforms in front of other platforms.
// For matched platforms, it puts platforms with larger revision
// number in front.
func (m windowsmatcher) Less(p1, p2 specs.Platform) bool {
m1, m2 := m.Match(p1), m.Match(p2)
if m1 && m2 {
r1, r2 := revision(p1.OSVersion), revision(p2.OSVersion)
return r1 > r2
}
return m1 && !m2
}
func revision(v string) int {
parts := strings.Split(v, ".")
if len(parts) < 4 {
return 0
}
r, err := strconv.Atoi(parts[3])
if err != nil {
return 0
}
return r
}
func prefix(v string) string {
parts := strings.Split(v, ".")
if len(parts) < 4 {
return v
}
return strings.Join(parts[0:3], ".")
}
// Default returns the current platform's default platform specification.
func Default() MatchComparer {
return Only(DefaultSpec())

View File

@ -16,9 +16,16 @@
package platforms
// osVersion is a wrapper for Windows version information
import (
"strconv"
"strings"
specs "github.com/opencontainers/image-spec/specs-go/v1"
)
// windowsOSVersion is a wrapper for Windows version information
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
type osVersion struct {
type windowsOSVersion struct {
Version uint32
MajorVersion uint8
MinorVersion uint8
@ -55,7 +62,7 @@ var compatLTSCReleases = []uint16{
// Every release after WS 2022 will support the previous ltsc
// container image. Stable ABI is in preview mode for windows 11 client.
// Refer: https://learn.microsoft.com/en-us/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-2022%2Cwindows-10#windows-server-host-os-compatibility
func checkHostAndContainerCompat(host, ctr osVersion) bool {
func checkWindowsHostAndContainerCompat(host, ctr windowsOSVersion) bool {
// check major minor versions of host and guest
if host.MajorVersion != ctr.MajorVersion ||
host.MinorVersion != ctr.MinorVersion {
@ -76,3 +83,74 @@ func checkHostAndContainerCompat(host, ctr osVersion) bool {
}
return ctr.Build >= supportedLtscRelease && ctr.Build <= host.Build
}
func getWindowsOSVersion(osVersionPrefix string) windowsOSVersion {
if strings.Count(osVersionPrefix, ".") < 2 {
return windowsOSVersion{}
}
major, extra, _ := strings.Cut(osVersionPrefix, ".")
minor, extra, _ := strings.Cut(extra, ".")
build, _, _ := strings.Cut(extra, ".")
majorVersion, err := strconv.ParseUint(major, 10, 8)
if err != nil {
return windowsOSVersion{}
}
minorVersion, err := strconv.ParseUint(minor, 10, 8)
if err != nil {
return windowsOSVersion{}
}
buildNumber, err := strconv.ParseUint(build, 10, 16)
if err != nil {
return windowsOSVersion{}
}
return windowsOSVersion{
MajorVersion: uint8(majorVersion),
MinorVersion: uint8(minorVersion),
Build: uint16(buildNumber),
}
}
func winRevision(v string) int {
parts := strings.Split(v, ".")
if len(parts) < 4 {
return 0
}
r, err := strconv.Atoi(parts[3])
if err != nil {
return 0
}
return r
}
type windowsVersionMatcher struct {
windowsOSVersion
}
func (m windowsVersionMatcher) Match(v string) bool {
if m.isEmpty() || v == "" {
return true
}
osv := getWindowsOSVersion(v)
return checkWindowsHostAndContainerCompat(m.windowsOSVersion, osv)
}
func (m windowsVersionMatcher) isEmpty() bool {
return m.MajorVersion == 0 && m.MinorVersion == 0 && m.Build == 0
}
type windowsMatchComparer struct {
Matcher
}
func (c *windowsMatchComparer) Less(p1, p2 specs.Platform) bool {
m1, m2 := c.Match(p1), c.Match(p2)
if m1 && m2 {
r1, r2 := winRevision(p1.OSVersion), winRevision(p2.OSVersion)
return r1 > r2
}
return m1 && !m2
}

View File

@ -144,18 +144,51 @@ type Matcher interface {
//
// Applications should opt to use `Match` over directly parsing specifiers.
func NewMatcher(platform specs.Platform) Matcher {
return newDefaultMatcher(platform)
m := &matcher{
Platform: Normalize(platform),
}
if platform.OS == "windows" {
m.osvM = &windowsVersionMatcher{
windowsOSVersion: getWindowsOSVersion(platform.OSVersion),
}
// In prior versions, on windows, the returned matcher implements a
// MatchComprarer interface.
// This preserves that behavior for backwards compatibility.
//
// TODO: This isn't actually used in this package, except for a test case,
// which may have been an unintended side of some refactor.
// It was likely intended to be used in `Ordered` but it is not since
// `Less` that is implemented here ends up getting masked due to wrapping.
if runtime.GOOS == "windows" {
return &windowsMatchComparer{m}
}
}
return m
}
type osVerMatcher interface {
Match(string) bool
}
type matcher struct {
specs.Platform
osvM osVerMatcher
}
func (m *matcher) Match(platform specs.Platform) bool {
normalized := Normalize(platform)
return m.OS == normalized.OS &&
m.Architecture == normalized.Architecture &&
m.Variant == normalized.Variant
m.Variant == normalized.Variant &&
m.matchOSVersion(platform)
}
func (m *matcher) matchOSVersion(platform specs.Platform) bool {
if m.osvM != nil {
return m.osvM.Match(platform.OSVersion)
}
return true
}
func (m *matcher) String() string {

View File

@ -1,30 +0,0 @@
//go:build !windows
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package platforms
import (
specs "github.com/opencontainers/image-spec/specs-go/v1"
)
// NewMatcher returns the default Matcher for containerd
func newDefaultMatcher(platform specs.Platform) Matcher {
return &matcher{
Platform: Normalize(platform),
}
}

View File

@ -1,34 +0,0 @@
/*
Copyright The containerd Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package platforms
import (
specs "github.com/opencontainers/image-spec/specs-go/v1"
)
// NewMatcher returns a Windows matcher that will match on osVersionPrefix if
// the platform is Windows otherwise use the default matcher
func newDefaultMatcher(platform specs.Platform) Matcher {
prefix := prefix(platform.OSVersion)
return windowsmatcher{
Platform: platform,
osVersionPrefix: prefix,
defaultMatcher: &matcher{
Platform: Normalize(platform),
},
}
}

2
vendor/modules.txt vendored
View File

@ -183,7 +183,7 @@ github.com/containerd/nri/types/v1
## explicit; go 1.21
github.com/containerd/otelttrpc
github.com/containerd/otelttrpc/internal
# github.com/containerd/platforms v1.0.0-rc.0
# github.com/containerd/platforms v1.0.0-rc.1
## explicit; go 1.20
github.com/containerd/platforms
# github.com/containerd/plugin v1.0.0