diff --git a/hack/verify-gotest.sh b/hack/verify-gotest.sh index c0e1910..fb1fe8b 100755 --- a/hack/verify-gotest.sh +++ b/hack/verify-gotest.sh @@ -26,8 +26,13 @@ cd_root_path export GO111MODULE=on ERROR=0 DIRS=$(git ls-files | grep -v "vendor\/" | grep ".go" | xargs dirname | grep -v "\." | cut -d '/' -f 1 | uniq) +echo "running Linux unit tests..." while read -r dir; do - go test ./"$dir"/... || ERROR=1 + GOOS=linux go test ./"$dir"/... -count=1 || ERROR=1 +done <<< "$DIRS" +echo "running Windows unit tests..." +while read -r dir; do + GOOS=windows go test ./"$dir"/... -count=1 || ERROR=1 done <<< "$DIRS" if [[ "${ERROR}" = 1 ]]; then diff --git a/validators/os_validator.go b/validators/os_validator_unix.go similarity index 90% rename from validators/os_validator.go rename to validators/os_validator_unix.go index 2918976..7ce1106 100644 --- a/validators/os_validator.go +++ b/validators/os_validator_unix.go @@ -1,5 +1,8 @@ +//go:build !windows +// +build !windows + /* -Copyright 2016 The Kubernetes Authors. +Copyright 2024 The Kubernetes Authors. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -38,7 +41,7 @@ func (o *OSValidator) Name() string { func (o *OSValidator) Validate(spec SysSpec) ([]error, []error) { os, err := exec.Command("uname").CombinedOutput() if err != nil { - return nil, []error{fmt.Errorf("failed to get os name: %w", err)} + return nil, []error{fmt.Errorf("failed to get OS name: %w", err)} } if err = o.validateOS(strings.TrimSpace(string(os)), spec.OS); err != nil { return nil, []error{err} diff --git a/validators/os_validator_test.go b/validators/os_validator_unix_test.go similarity index 96% rename from validators/os_validator_test.go rename to validators/os_validator_unix_test.go index 6c32502..9179ce9 100644 --- a/validators/os_validator_test.go +++ b/validators/os_validator_unix_test.go @@ -1,3 +1,6 @@ +//go:build !windows +// +build !windows + /* Copyright 2016 The Kubernetes Authors. diff --git a/validators/os_validator_windows.go b/validators/os_validator_windows.go new file mode 100644 index 0000000..6c5b6aa --- /dev/null +++ b/validators/os_validator_windows.go @@ -0,0 +1,62 @@ +//go:build windows +// +build windows + +/* +Copyright 2024 The Kubernetes 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 system + +import ( + "fmt" + "os/exec" + "strings" +) + +var _ Validator = &OSValidator{} + +// OSValidator validates OS. +type OSValidator struct { + Reporter Reporter +} + +// Name is part of the system.Validator interface. +func (o *OSValidator) Name() string { + return "os" +} + +// Validate is part of the system.Validator interface. +func (o *OSValidator) Validate(spec SysSpec) ([]error, []error) { + args := []string{`(Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion').ProductName`} + os, err := exec.Command("powershell", args...).CombinedOutput() + if err != nil { + return nil, []error{fmt.Errorf("failed to get OS name: %w", err)} + } + if err = o.validateOS(strings.TrimSpace(string(os)), spec.OS); err != nil { + return nil, []error{err} + } + return nil, nil +} + +// validateOS would check if the reported string such as 'Windows Server 2019' contains +// the required OS prefix from the spec 'Windows Server'. +func (o *OSValidator) validateOS(os, specOS string) error { + if !strings.HasPrefix(os, specOS) { + o.Reporter.Report("OS", os, bad) + return fmt.Errorf("unsupported operating system: %s", os) + } + o.Reporter.Report("OS", os, good) + return nil +} diff --git a/validators/os_validator_windows_test.go b/validators/os_validator_windows_test.go new file mode 100644 index 0000000..76e54db --- /dev/null +++ b/validators/os_validator_windows_test.go @@ -0,0 +1,59 @@ +//go:build windows +// +build windows + +/* +Copyright 2016 The Kubernetes 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 system + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestValidateOS(t *testing.T) { + v := &OSValidator{ + Reporter: DefaultReporter, + } + specOS := "Windows Server" + for _, test := range []struct { + os string + err bool + }{ + { + os: "Windows Server", + err: false, + }, + { + os: "Windows 10 Enterprise", + err: true, + }, + { + os: "Windows", + err: true, + }, + } { + t.Run(test.os, func(t *testing.T) { + err := v.validateOS(test.os, specOS) + if !test.err { + assert.Nil(t, err, "Expect error not to occur with os %q", test.os) + } else { + assert.NotNil(t, err, "Expect error to occur with os %q", test.os) + } + }) + } +} diff --git a/validators/types_windows.go b/validators/types_windows.go index 2c5c367..3333494 100644 --- a/validators/types_windows.go +++ b/validators/types_windows.go @@ -24,9 +24,9 @@ import ( "strings" ) -// DefaultSysSpec is the default SysSpec for Windows +// DefaultSysSpec is the default SysSpec for Windows. var DefaultSysSpec = SysSpec{ - OS: "Microsoft Windows Server 2016", + OS: "Windows Server", KernelSpec: KernelSpec{ Versions: []string{`10\.0\.1439[3-9]`, `10\.0\.14[4-9][0-9]{2}`, `10\.0\.1[5-9][0-9]{3}`, `10\.0\.[2-9][0-9]{4}`, `10\.[1-9]+\.[0-9]+`}, //requires >= '10.0.14393' VersionsNote: "The kernel version should be >= '10.0.14393'", @@ -47,9 +47,11 @@ type KernelValidatorHelperImpl struct{} var _ KernelValidatorHelper = &KernelValidatorHelperImpl{} -// GetKernelReleaseVersion returns the windows release version (ex. 10.0.14393) as a string +// GetKernelReleaseVersion returns the Windows release version (e.g. 10.0.14393) as a string. +// It does not include the UBR (revision) func (o *KernelValidatorHelperImpl) GetKernelReleaseVersion() (string, error) { - args := []string{"(Get-CimInstance Win32_OperatingSystem).Version"} + args := []string{`$props = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion'; ` + + `"$($props.CurrentMajorVersionNumber).$($props.CurrentMinorVersionNumber).$($props.CurrentBuildNumber)"`} releaseVersion, err := exec.Command("powershell", args...).Output() if err != nil { return "", err