Merge pull request #5747 from thaJeztah/vendor_containerd_platforms

vendor: github.com/containerd/platforms v1.0.0-rc.1
This commit is contained in:
Sebastiaan van Stijn 2025-01-14 15:13:42 +01:00 committed by GitHub
commit 25bdd5ced6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 186 additions and 154 deletions

View File

@ -8,7 +8,7 @@ go 1.22.0
require (
dario.cat/mergo v1.0.1
github.com/containerd/platforms v0.2.1
github.com/containerd/platforms v1.0.0-rc.1
github.com/creack/pty v1.1.24
github.com/distribution/reference v0.6.0
github.com/docker/cli-docs-tool v0.8.0

View File

@ -34,8 +34,8 @@ github.com/cloudflare/cfssl v1.6.4 h1:NMOvfrEjFfC63K3SGXgAnFdsgkmiq4kATme5BfcqrO
github.com/cloudflare/cfssl v1.6.4/go.mod h1:8b3CQMxfWPAeom3zBnGJ6sd+G1NkL5TXqmDXacb+1J0=
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A=
github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw=
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/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s=

View File

@ -1,6 +1,6 @@
linters:
enable:
- exportloopref # Checks for pointers to enclosing loop variables
- copyloopvar
- gofmt
- goimports
- gosec
@ -12,14 +12,16 @@ linters:
- tenv # Detects using os.Setenv instead of t.Setenv since Go 1.17
- unconvert
- unused
- vet
- govet
- dupword # Checks for duplicate words in the source code
disable:
- errcheck
run:
timeout: 5m
skip-dirs:
issues:
exclude-dirs:
- api
- cluster
- design

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 {
@ -72,6 +100,33 @@ func platformVector(platform specs.Platform) []specs.Platform {
if variant == "" {
variant = "v8"
}
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(major)
}
vector = append(vector, specs.Platform{
Architecture: "arm64",
OS: platform.OS,
OSVersion: platform.OSVersion,
OSFeatures: platform.OSFeatures,
Variant: arm64Variant,
})
}
}
// 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") {
variant = "v8"
}
vector = append(vector, platformVector(specs.Platform{
Architecture: "arm",
OS: platform.OS,
@ -87,6 +142,8 @@ func platformVector(platform specs.Platform) []specs.Platform {
// Only returns a match comparer for a single platform
// using default resolution logic for the platform.
//
// For arm64/v9.x, will also match arm64/v9.{0..x-1} and arm64/v8.{0..x+5}
// For arm64/v8.x, will also match arm64/v8.{0..x-1}
// For arm/v8, will also match arm/v7, arm/v6 and arm/v5
// For arm/v7, will also match arm/v6 and arm/v5
// For arm/v6, will also match arm/v5

View File

@ -87,8 +87,10 @@ func normalizeArch(arch, variant string) (string, string) {
case "aarch64", "arm64":
arch = "arm64"
switch variant {
case "8", "v8":
case "8", "v8", "v8.0":
variant = ""
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.Atoi(parts[0])
minorVersion, _ := strconv.Atoi(parts[1])
buildNumber, _ := strconv.Atoi(parts[2])
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

@ -121,7 +121,7 @@ import (
)
var (
specifierRe = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
specifierRe = regexp.MustCompile(`^[A-Za-z0-9_.-]+$`)
osAndVersionRe = regexp.MustCompile(`^([A-Za-z0-9_-]+)(?:\(([A-Za-z0-9_.-]*)\))?$`)
)
@ -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

@ -26,7 +26,7 @@ github.com/cespare/xxhash/v2
# github.com/containerd/log v0.1.0
## explicit; go 1.20
github.com/containerd/log
# github.com/containerd/platforms v0.2.1
# github.com/containerd/platforms v1.0.0-rc.1
## explicit; go 1.20
github.com/containerd/platforms
# github.com/creack/pty v1.1.24