From cfb30a31a8507e4417d42d38c9a99b04fc8af8a9 Mon Sep 17 00:00:00 2001 From: Kirtana Ashok Date: Wed, 5 Jul 2023 10:11:57 -0700 Subject: [PATCH 1/2] Invoke Stable ABI compatibility function in windows platform matcher Signed-off-by: Kirtana Ashok --- platforms/defaults_windows.go | 26 +++++++- platforms/defaults_windows_test.go | 104 +++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+), 2 deletions(-) diff --git a/platforms/defaults_windows.go b/platforms/defaults_windows.go index fd5756516..d10fa9012 100644 --- a/platforms/defaults_windows.go +++ b/platforms/defaults_windows.go @@ -22,6 +22,7 @@ import ( "strconv" "strings" + "github.com/Microsoft/hcsshim/osversion" specs "github.com/opencontainers/image-spec/specs-go/v1" "golang.org/x/sys/windows" ) @@ -50,15 +51,36 @@ func (m windowsmatcher) Match(p specs.Platform) bool { match := m.defaultMatcher.Match(p) if match && m.OS == "windows" { - if strings.HasPrefix(p.OSVersion, m.osVersionPrefix) { + // HPC containers do not have OS version filled + if p.OSVersion == "" { return true } - return p.OSVersion == "" + + hostOsVersion := GetOsVersion(m.osVersionPrefix) + ctrOsVersion := GetOsVersion(p.OSVersion) + return osversion.CheckHostAndContainerCompat(hostOsVersion, ctrOsVersion) } return match } +func GetOsVersion(osVersionPrefix string) osversion.OSVersion { + parts := strings.Split(osVersionPrefix, ".") + if len(parts) < 3 { + return osversion.OSVersion{} + } + + majorVersion, _ := strconv.Atoi(parts[0]) + minorVersion, _ := strconv.Atoi(parts[1]) + buildNumber, _ := strconv.Atoi(parts[2]) + + return osversion.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. diff --git a/platforms/defaults_windows_test.go b/platforms/defaults_windows_test.go index 468438038..ab73ddda0 100644 --- a/platforms/defaults_windows_test.go +++ b/platforms/defaults_windows_test.go @@ -142,6 +142,110 @@ func TestMatchComparerMatch_WCOW(t *testing.T) { } } +// TestMatchComparerMatch_ABICheckWCOW checks windows platform matcher +// behavior for stable ABI and non-stable ABI compliant versions +func TestMatchComparerMatch_ABICheckWCOW(t *testing.T) { + platformWS2019 := imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17763", + } + platformWS2022 := imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.20348", + } + platformWindows11 := imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.22621", + } + matcherWS2019 := windowsmatcher{ + Platform: platformWS2019, + osVersionPrefix: platformWS2019.OSVersion, + defaultMatcher: &matcher{ + Platform: Normalize(platformWS2019), + }, + } + matcherWS2022 := windowsmatcher{ + Platform: platformWS2022, + osVersionPrefix: platformWS2022.OSVersion, + defaultMatcher: &matcher{ + Platform: Normalize(platformWS2022), + }, + } + matcherWindows11 := windowsmatcher{ + Platform: platformWindows11, + osVersionPrefix: platformWindows11.OSVersion, + defaultMatcher: &matcher{ + Platform: Normalize(platformWindows11), + }, + } + + for _, test := range []struct { + hostPlatformMatcher windowsmatcher + testPlatform imagespec.Platform + match bool + }{ + { + hostPlatformMatcher: matcherWS2019, + testPlatform: imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17763", + }, + match: true, + }, + { + hostPlatformMatcher: matcherWS2019, + testPlatform: imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.20348", + }, + match: false, + }, + { + hostPlatformMatcher: matcherWS2022, + testPlatform: imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17763", + }, + match: false, + }, + { + hostPlatformMatcher: matcherWS2022, + testPlatform: imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.20348", + }, + match: true, + }, + { + hostPlatformMatcher: matcherWindows11, + testPlatform: imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.17763", + }, + match: false, + }, + { + hostPlatformMatcher: matcherWindows11, + testPlatform: imagespec.Platform{ + Architecture: "amd64", + OS: "windows", + OSVersion: "10.0.20348", + }, + match: true, + }, + } { + assert.Equal(t, test.match, test.hostPlatformMatcher.Match(test.testPlatform), "should match: %t, %s to %s", test.match, test.hostPlatformMatcher.Platform, test.testPlatform) + } +} + func TestMatchComparerMatch_LCOW(t *testing.T) { major, minor, build := windows.RtlGetNtVersionNumbers() buildStr := fmt.Sprintf("%d.%d.%d", major, minor, build) From 823e0420eb3cd3eebbf15472cda0cfac85da14f6 Mon Sep 17 00:00:00 2001 From: Kirtana Ashok Date: Tue, 15 Aug 2023 12:55:56 -0700 Subject: [PATCH 2/2] Fix transfer service dependencies: - Fill OSVersion field of ocispec.Platform for windows OS in transfer service plugin init() - Do not return error from transfer service ReceiveStream if stream.Recv() returned context.Canceled error Signed-off-by: Kirtana Ashok --- pkg/transfer/streaming/stream.go | 2 +- platforms/platforms.go | 12 ++++++++++++ platforms/platforms_other.go | 4 ++++ platforms/platforms_windows.go | 8 ++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) diff --git a/pkg/transfer/streaming/stream.go b/pkg/transfer/streaming/stream.go index cf77cb8b5..061fd172d 100644 --- a/pkg/transfer/streaming/stream.go +++ b/pkg/transfer/streaming/stream.go @@ -164,7 +164,7 @@ func ReceiveStream(ctx context.Context, stream streaming.Stream) io.Reader { } anyType, err := stream.Recv() if err != nil { - if errors.Is(err, io.EOF) { + if errors.Is(err, io.EOF) || errors.Is(err, context.Canceled) { err = nil } else { err = fmt.Errorf("received failed: %w", err) diff --git a/platforms/platforms.go b/platforms/platforms.go index 0254ec0c5..5aee03a7e 100644 --- a/platforms/platforms.go +++ b/platforms/platforms.go @@ -213,6 +213,10 @@ func Parse(specifier string) (specs.Platform, error) { p.Variant = cpuVariant() } + if p.OS == "windows" { + p.OSVersion = GetWindowsOsVersion() + } + return p, nil } @@ -235,6 +239,10 @@ func Parse(specifier string) (specs.Platform, error) { p.Variant = "" } + if p.OS == "windows" { + p.OSVersion = GetWindowsOsVersion() + } + return p, nil case 3: // we have a fully specified variant, this is rare @@ -244,6 +252,10 @@ func Parse(specifier string) (specs.Platform, error) { p.Variant = "v8" } + if p.OS == "windows" { + p.OSVersion = GetWindowsOsVersion() + } + return p, nil } diff --git a/platforms/platforms_other.go b/platforms/platforms_other.go index 03f4dcd99..59beeb3d1 100644 --- a/platforms/platforms_other.go +++ b/platforms/platforms_other.go @@ -28,3 +28,7 @@ func newDefaultMatcher(platform specs.Platform) Matcher { Platform: Normalize(platform), } } + +func GetWindowsOsVersion() string { + return "" +} diff --git a/platforms/platforms_windows.go b/platforms/platforms_windows.go index 950e2a2dd..733d18dde 100644 --- a/platforms/platforms_windows.go +++ b/platforms/platforms_windows.go @@ -17,7 +17,10 @@ package platforms import ( + "fmt" + specs "github.com/opencontainers/image-spec/specs-go/v1" + "golang.org/x/sys/windows" ) // NewMatcher returns a Windows matcher that will match on osVersionPrefix if @@ -32,3 +35,8 @@ func newDefaultMatcher(platform specs.Platform) Matcher { }, } } + +func GetWindowsOsVersion() string { + major, minor, build := windows.RtlGetNtVersionNumbers() + return fmt.Sprintf("%d.%d.%d", major, minor, build) +}