Skip to content

Commit

Permalink
Add osversion from hcsshim
Browse files Browse the repository at this point in the history
[RtlGetVersion](https://learn.microsoft.com/en-us/windows/win32/devnotes/rtlgetversion)
returns the windows OS version regardless of manifest, so that is
preferred over
[GetVersion](https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversion).

Signed-off-by: Hamza El-Saawy <hamzaelsaawy@microsoft.com>
  • Loading branch information
helsaawy committed Mar 9, 2023
1 parent 2a14e68 commit c28a08a
Show file tree
Hide file tree
Showing 6 changed files with 239 additions and 3 deletions.
6 changes: 3 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ go 1.17

require (
github.com/sirupsen/logrus v1.9.0
golang.org/x/sys v0.5.0
golang.org/x/tools v0.6.0
golang.org/x/sys v0.6.0
golang.org/x/tools v0.7.0
)

require golang.org/x/mod v0.8.0 // indirect
require golang.org/x/mod v0.9.0 // indirect
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0 h1:LUYupSeNrTNCGzR/hVBk2NHZO4hXcVaW1k4Qx7rjPx8=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs=
golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
Expand All @@ -30,6 +32,8 @@ golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
Expand All @@ -42,6 +46,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0 h1:BOw41kyTf3PuCW1pVQf8+Cyg8pMlkYB1oo9iJ6D/lKM=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
Expand Down
84 changes: 84 additions & 0 deletions pkg/osversion/builds.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package osversion

// Windows Client and Server build numbers.
//
// See:
// https://learn.microsoft.com/en-us/windows/release-health/release-information
// https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info
// https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information
const (
// RS1 (version 1607, codename "Redstone 1") corresponds to Windows Server
// 2016 (ltsc2016) and Windows 10 (Anniversary Update).
RS1 BuildNumber = 14393
// V1607 (version 1607, codename "Redstone 1") is an alias for [RS1].
V1607 = RS1
// LTSC2016 (Windows Server 2016) is an alias for [RS1].
LTSC2016 = RS1

// RS2 (version 1703, codename "Redstone 2") was a client-only update, and
// corresponds to Windows 10 (Creators Update).
RS2 BuildNumber = 15063
// V1703 (version 1703, codename "Redstone 2") is an alias for [RS2].
V1703 = RS2

// RS3 (version 1709, codename "Redstone 3") corresponds to Windows Server
// 1709 (Semi-Annual Channel (SAC)), and Windows 10 (Fall Creators Update).
RS3 BuildNumber = 16299
// V1709 (version 1709, codename "Redstone 3") is an alias for [RS3].
V1709 = RS3

// RS4 (version 1803, codename "Redstone 4") corresponds to Windows Server
// 1803 (Semi-Annual Channel (SAC)), and Windows 10 (April 2018 Update).
RS4 BuildNumber = 17134
// V1803 (version 1803, codename "Redstone 4") is an alias for [RS4].
V1803 = RS4

// RS5 (version 1809, codename "Redstone 5") corresponds to Windows Server
// 2019 (ltsc2019), and Windows 10 (October 2018 Update).
RS5 BuildNumber = 17763
// V1809 (version 1809, codename "Redstone 5") is an alias for [RS5].
V1809 = RS5
// LTSC2019 (Windows Server 2019) is an alias for [RS5].
LTSC2019 = RS5

// V19H1 (version 1903, codename 19H1) corresponds to Windows Server 1903 (semi-annual
// channel).
V19H1 BuildNumber = 18362
// V1903 (version 1903) is an alias for [V19H1].
V1903 = V19H1

// V19H2 (version 1909, codename 19H2) corresponds to Windows Server 1909 (semi-annual
// channel).
V19H2 BuildNumber = 18363
// V1909 (version 1909) is an alias for [V19H2].
V1909 = V19H2

// V20H1 (version 2004, codename 20H1) corresponds to Windows Server 2004 (semi-annual
// channel).
V20H1 BuildNumber = 19041
// V2004 (version 2004) is an alias for [V20H1].
V2004 = V20H1

// V20H2 corresponds to Windows Server 20H2 (semi-annual channel).
V20H2 BuildNumber = 19042

// V21H1 corresponds to Windows Server 21H1 (semi-annual channel).
V21H1 BuildNumber = 19043

// V21H2Win10 corresponds to Windows 10 (November 2021 Update).
V21H2Win10 BuildNumber = 19044

// V21H2Server corresponds to Windows Server 2022 (ltsc2022).
V21H2Server BuildNumber = 20348
// LTSC2022 (Windows Server 2022) is an alias for [V21H2Server]
LTSC2022 = V21H2Server

// V21H2Win11 corresponds to Windows 11 (original release).
V21H2Win11 BuildNumber = 22000

// V22H2Win10 corresponds to Windows 10 (2022 Update).
V22H2Win10 BuildNumber = 19045

// V22H2Win11 corresponds to Windows 11 (2022 Update).
V22H2Win11 BuildNumber = 22621
)
61 changes: 61 additions & 0 deletions pkg/osversion/osversion.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package osversion

import (
"fmt"
)

// Documentation and [OSVERSIONINFO] struct lists fields as DWORDs (uint32), but they
// all packed into a uint32 in GetVersion, so safe to downcast to smallper types
//
//[OSVERSIONINFO]: https://learn.microsoft.com/en-us/windows/win32/api/winnt/ns-winnt-osversioninfoexw

type (
MajorVersion uint8
MinorVersion uint8
BuildNumber uint16
)

// Version is a wrapper for Windows version information
//
// https://learn.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getversion
type Version struct {
Major MajorVersion
Minor MinorVersion
Build BuildNumber
}

func FromPackedVersion(v uint32) Version {
return Version{
Major: MajorVersion(v & 0xFF),
Minor: MinorVersion(v >> 8 & 0xFF),
Build: BuildNumber(v >> 16),
}
}

var _ fmt.Stringer = Version{}

// String returns the OSVersion formatted as a string.
func (v Version) String() string {
return fmt.Sprintf("%d.%d.%d", v.Major, v.Minor, v.Build)
}

// Compare compares the current OSVersion to another.
// The result will be 0 if they are equal, -1 the current version is lesser, and +1 otherwise.
func (v Version) Compare(other Version) int {
cmp := func(a, b int) int {
if a > b {
return 1
} else if a < b {
return -1
}
return 0
}

if c := cmp(int(v.Major), int(other.Major)); c != 0 {
return c
}
if c := cmp(int(v.Minor), int(other.Minor)); c != 0 {
return c
}
return cmp(int(v.Build), int(other.Build))
}
54 changes: 54 additions & 0 deletions pkg/osversion/osversion_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package osversion

import (
"fmt"
"testing"
)

func TestCompare(t *testing.T) {
tt := []struct {
a, b Version
res int
}{
{
Version{10, 0, RS5},
Version{10, 0, LTSC2022},
-1,
},
{
Version{6, 1, 9801},
Version{10, 0, LTSC2022},
-1,
},
{
Version{10, 0, RS5},
Version{10, 0, RS5},
0,
},
{
Version{10, 0, LTSC2022},
Version{10, 0, RS5},
1,
},
{
Version{10, 0, LTSC2022},
Version{6, 1, 9801},
1,
},
}

for _, tc := range tt {
if res := tc.a.Compare(tc.b); res != tc.res {
t.Errorf("(%s).Compare(%s): expected: %d, got: %d", tc.a, tc.b, res, tc.res)
}
}
}

func TestOSVersionString(t *testing.T) {
v := FromPackedVersion(809042555)
expected := "123.2.12345"
actual := fmt.Sprintf("%s", v) //nolint: gosimple // testing that fmt works
if actual != expected {
t.Errorf("expected: %q, got: %q", expected, actual)
}
}
31 changes: 31 additions & 0 deletions pkg/osversion/osversion_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
//go:build windows

package osversion

import (
"sync"

"golang.org/x/sys/windows"
)

var (
v Version
once sync.Once
)

// Get returns the Windows operating system version.
func Get() Version {
once.Do(func() {
vi := windows.RtlGetVersion()

v.Major = MajorVersion(vi.MajorVersion)
v.Minor = MinorVersion(vi.MinorVersion)
v.Build = BuildNumber(vi.BuildNumber)
})
return v
}

// Build returns the Windows build number.
func Build() BuildNumber {
return Get().Build
}

0 comments on commit c28a08a

Please sign in to comment.