Skip to content

Commit c1d2c86

Browse files
author
John Howard
committed
Add schema2, schemaversion, test\assets, osversion
Signed-off-by: John Howard <[email protected]>
1 parent 63661d9 commit c1d2c86

8 files changed

Lines changed: 873 additions & 0 deletions

File tree

internal/osversion/osversion.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package osversion
2+
3+
import (
4+
"fmt"
5+
6+
"golang.org/x/sys/windows"
7+
)
8+
9+
// OSVersion is a wrapper for Windows version information
10+
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724439(v=vs.85).aspx
11+
type OSVersion struct {
12+
Version uint32
13+
MajorVersion uint8
14+
MinorVersion uint8
15+
Build uint16
16+
}
17+
18+
// https://msdn.microsoft.com/en-us/library/windows/desktop/ms724833(v=vs.85).aspx
19+
type osVersionInfoEx struct {
20+
OSVersionInfoSize uint32
21+
MajorVersion uint32
22+
MinorVersion uint32
23+
BuildNumber uint32
24+
PlatformID uint32
25+
CSDVersion [128]uint16
26+
ServicePackMajor uint16
27+
ServicePackMinor uint16
28+
SuiteMask uint16
29+
ProductType byte
30+
Reserve byte
31+
}
32+
33+
// GetOSVersion gets the operating system version on Windows.
34+
// The calling application must be manifested to get the correct version information.
35+
func GetOSVersion() OSVersion {
36+
var err error
37+
osv := OSVersion{}
38+
osv.Version, err = windows.GetVersion()
39+
if err != nil {
40+
// GetVersion never fails.
41+
panic(err)
42+
}
43+
osv.MajorVersion = uint8(osv.Version & 0xFF)
44+
osv.MinorVersion = uint8(osv.Version >> 8 & 0xFF)
45+
osv.Build = uint16(osv.Version >> 16)
46+
return osv
47+
}
48+
49+
func (osv OSVersion) ToString() string {
50+
return fmt.Sprintf("%d.%d.%d", osv.MajorVersion, osv.MinorVersion, osv.Build)
51+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package osversion
2+
3+
const (
4+
5+
// RS2 was a client-only release in case you're asking why it's not in the list.
6+
RS1 = 14393
7+
RS3 = 16299
8+
RS4 = 17134
9+
RS5 = 17659 // TODO Bump to final RS5 build
10+
)

internal/schema2/schema2.go

Lines changed: 408 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// +build windows
2+
3+
package schemaversion
4+
5+
import (
6+
"encoding/json"
7+
"fmt"
8+
9+
"github.com/Microsoft/hcsshim/internal/osversion"
10+
"github.com/sirupsen/logrus"
11+
)
12+
13+
type SchemaVersion struct {
14+
Major int32 `json:"Major"`
15+
Minor int32 `json:"Minor"`
16+
}
17+
18+
// SchemaV10 makes it easy for callers to get a v1.0 schema version object
19+
func SchemaV10() *SchemaVersion {
20+
return &SchemaVersion{Major: 1, Minor: 0}
21+
}
22+
23+
// SchemaV20 makes it easy for callers to get a v2.0 schema version object
24+
func SchemaV20() *SchemaVersion {
25+
return &SchemaVersion{Major: 2, Minor: 0}
26+
}
27+
28+
// isSupported determines if a given schema version is supported
29+
func (sv *SchemaVersion) isSupported() error {
30+
if sv.IsV10() {
31+
return nil
32+
}
33+
if sv.IsV20() {
34+
if osversion.GetOSVersion().Build < osversion.RS5 {
35+
return fmt.Errorf("unsupported on this Windows build")
36+
}
37+
return nil
38+
}
39+
return fmt.Errorf("unknown schema version %s", sv.String())
40+
}
41+
42+
// IsV10 determines if a given schema version object is 1.0. This was the only thing
43+
// supported in RS1..3. It lives on in RS5, but will be deprecated in a future release.
44+
func (sv *SchemaVersion) IsV10() bool {
45+
if sv.Major == 1 && sv.Minor == 0 {
46+
return true
47+
}
48+
return false
49+
}
50+
51+
// IsV20 determines if a given schema version object is 2.0. This was introduced in
52+
// RS4, but not fully implemented. Recommended for applications using HCS in RS5
53+
// onwards.
54+
func (sv *SchemaVersion) IsV20() bool {
55+
if sv.Major == 2 && sv.Minor == 0 {
56+
return true
57+
}
58+
return false
59+
}
60+
61+
// String returns a JSON encoding of a schema version object
62+
func (sv *SchemaVersion) String() string {
63+
b, err := json.Marshal(sv)
64+
if err != nil {
65+
return ""
66+
}
67+
return string(b[:])
68+
}
69+
70+
// DetermineSchemaVersion works out what schema version to use based on build and
71+
// requested option.
72+
func DetermineSchemaVersion(requestedSV *SchemaVersion) *SchemaVersion {
73+
sv := SchemaV10()
74+
if osversion.GetOSVersion().Build >= osversion.RS5 {
75+
sv = SchemaV10() // TODO: When do we flip this to V2 for RS5? Answer - when functionally complete. Templating. CredSpecs. Networking. LCOW...
76+
}
77+
if requestedSV != nil {
78+
if err := requestedSV.isSupported(); err == nil {
79+
sv = requestedSV
80+
} else {
81+
logrus.Warnf("Ignoring unsupported requested schema version %+v", requestedSV)
82+
}
83+
}
84+
return sv
85+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
// +build windows
2+
3+
package schemaversion
4+
5+
import (
6+
"testing"
7+
8+
"github.com/Microsoft/hcsshim/internal/osversion"
9+
_ "github.com/Microsoft/hcsshim/test/assets" // For manifest
10+
)
11+
12+
// Note that the .syso file is required to manifest the test app
13+
func TestDetermineSchemaVersion(t *testing.T) {
14+
osv := osversion.GetOSVersion()
15+
16+
if osv.Build >= osversion.RS5 {
17+
if sv := DetermineSchemaVersion(nil); !sv.IsV10() { // TODO: Toggle this at some point so default is 2.0
18+
t.Fatalf("expected v1")
19+
}
20+
if sv := DetermineSchemaVersion(SchemaV20()); !sv.IsV20() {
21+
t.Fatalf("expected requested v2")
22+
}
23+
if sv := DetermineSchemaVersion(SchemaV10()); !sv.IsV10() {
24+
t.Fatalf("expected requested v1")
25+
}
26+
if sv := DetermineSchemaVersion(&SchemaVersion{}); !sv.IsV10() { // Logs a warning that 0.0 is ignored // TODO: Toggle this too
27+
t.Fatalf("expected requested v1")
28+
}
29+
30+
if err := SchemaV20().isSupported(); err != nil {
31+
t.Fatalf("v2 expected to be supported")
32+
}
33+
if err := SchemaV10().isSupported(); err != nil {
34+
t.Fatalf("v1 expected to be supported")
35+
}
36+
37+
} else {
38+
if sv := DetermineSchemaVersion(nil); !sv.IsV10() {
39+
t.Fatalf("expected v1")
40+
}
41+
// Pre RS5 will downgrade to v1 even if request v2
42+
if sv := DetermineSchemaVersion(SchemaV20()); !sv.IsV10() { // Logs a warning that 2.0 is ignored.
43+
t.Fatalf("expected requested v1")
44+
}
45+
if sv := DetermineSchemaVersion(SchemaV10()); !sv.IsV10() {
46+
t.Fatalf("expected requested v1")
47+
}
48+
if sv := DetermineSchemaVersion(&SchemaVersion{}); !sv.IsV10() { // Log a warning that 0.0 is ignored
49+
t.Fatalf("expected requested v1")
50+
}
51+
52+
if err := SchemaV20().isSupported(); err == nil {
53+
t.Fatalf("didn't expect v2 to be supported")
54+
}
55+
if err := SchemaV10().isSupported(); err != nil {
56+
t.Fatalf("v1 expected to be supported")
57+
}
58+
}
59+
}

test/assets/assets.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
package assets
2+
3+
// This is so that tests can include the .syso to manifest them to pick up the right Windows build
4+
// TODO: Auto-generation of the .syso through rsrc or similar.

0 commit comments

Comments
 (0)