Merge pull request #11259 from k8s-infra-cherrypick-robot/cherry-pick-11257-to-release/2.0

[release/2.0] Update platforms to latest rc
This commit is contained in:
Kazuyoshi Kato 2025-01-13 16:00:04 -08:00 committed by GitHub
commit 0d9aa65eba
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
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
vector = []specs.Platform{} // Reset vector, the first variant will be added in loop.
arm64Versions, ok := arm64variantToVersion[variant]
if !ok {
break
}
}
if armMajor == 9 {
for minor := armMinor - 1; minor >= 0; minor-- {
arm64Variant := "v" + strconv.Itoa(armMajor) + "." + strconv.Itoa(minor)
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,
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)
if minor == 0 {
arm64Variant = "v" + strconv.Itoa(armMajor)
}
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