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/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) 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) +}