diff --git a/pkg/kubelet/winstats/BUILD b/pkg/kubelet/winstats/BUILD index a4bdfa09c1bd..049fae2385f1 100644 --- a/pkg/kubelet/winstats/BUILD +++ b/pkg/kubelet/winstats/BUILD @@ -25,6 +25,7 @@ go_library( "@io_bazel_rules_go//go/platform:windows_amd64": [ "perfcounter_nodestats.go", "perfcounters.go", + "version.go", ], "//conditions:default": [], }), @@ -36,6 +37,7 @@ go_library( "@io_bazel_rules_go//go/platform:windows_amd64": [ "//vendor/github.com/JeffAshton/win_pdh:go_default_library", "//vendor/github.com/golang/glog:go_default_library", + "//vendor/golang.org/x/sys/windows:go_default_library", "//vendor/k8s.io/apimachinery/pkg/util/wait:go_default_library", ], "//conditions:default": [], diff --git a/pkg/kubelet/winstats/perfcounter_nodestats.go b/pkg/kubelet/winstats/perfcounter_nodestats.go index 4aa7602bf445..b6855df4013c 100644 --- a/pkg/kubelet/winstats/perfcounter_nodestats.go +++ b/pkg/kubelet/winstats/perfcounter_nodestats.go @@ -21,9 +21,7 @@ package winstats import ( "errors" "os" - "os/exec" "runtime" - "strings" "sync" "syscall" "time" @@ -57,13 +55,16 @@ func (p *perfCounterNodeStatsClient) startMonitoring() error { return err } - version, err := exec.Command("cmd", "/C", "ver").Output() + kernelVersion, err := getKernelVersion() + if err != nil { + return err + } + + osImageVersion, err := getOSImageVersion() if err != nil { return err } - osImageVersion := strings.TrimSpace(string(version)) - kernelVersion := extractVersionNumber(osImageVersion) p.nodeInfo = nodeInfo{ kernelVersion: kernelVersion, osImageVersion: osImageVersion, diff --git a/pkg/kubelet/winstats/version.go b/pkg/kubelet/winstats/version.go new file mode 100644 index 000000000000..e6cc097f5b1f --- /dev/null +++ b/pkg/kubelet/winstats/version.go @@ -0,0 +1,96 @@ +// +build windows + +/* +Copyright 2017 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 winstats + +import ( + "fmt" + "unsafe" + + "golang.org/x/sys/windows" +) + +// getCurrentVersionVal gets value of speficied key from registry. +func getCurrentVersionVal(key string) (string, error) { + var h windows.Handle + if err := windows.RegOpenKeyEx(windows.HKEY_LOCAL_MACHINE, + windows.StringToUTF16Ptr(`SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\`), + 0, + windows.KEY_READ, + &h); err != nil { + return "", err + } + defer windows.RegCloseKey(h) + + var buf [128]uint16 + var typ uint32 + n := uint32(len(buf) * int(unsafe.Sizeof(buf[0]))) // api expects array of bytes, not uint16 + if err := windows.RegQueryValueEx(h, + windows.StringToUTF16Ptr(key), + nil, + &typ, + (*byte)(unsafe.Pointer(&buf[0])), + &n); err != nil { + return "", err + } + + return windows.UTF16ToString(buf[:]), nil +} + +// getVersionRevision gets revision from UBR registry. +func getVersionRevision() (uint16, error) { + revisionString, err := getCurrentVersionVal("UBR") + if err != nil { + return 0, err + } + + revision, err := windows.UTF16FromString(revisionString) + if err != nil { + return 0, err + } + + return revision[0], nil +} + +// getKernelVersion gets the version of windows kernel. +func getKernelVersion() (string, error) { + ver, err := windows.GetVersion() + if err != nil { + return "", err + } + + revision, err := getVersionRevision() + if err != nil { + return "", err + } + + major := ver & 0xFF + minor := (ver >> 8) & 0xFF + build := (ver >> 16) & 0xFFFF + return fmt.Sprintf("%d.%d.%05d.%d\n", major, minor, build, revision), nil +} + +// getOSImageVersion gets the osImage name and version. +func getOSImageVersion() (string, error) { + productName, err := getCurrentVersionVal("ProductName") + if err != nil { + return "", nil + } + + return productName, nil +} diff --git a/pkg/kubelet/winstats/winstats.go b/pkg/kubelet/winstats/winstats.go index 123870b8968d..b02bab4f6bd8 100644 --- a/pkg/kubelet/winstats/winstats.go +++ b/pkg/kubelet/winstats/winstats.go @@ -18,7 +18,6 @@ limitations under the License. package winstats import ( - "regexp" "time" cadvisorapi "github.com/google/cadvisor/info/v1" @@ -135,11 +134,3 @@ func (c *statsClient) createRootContainerInfo() (*cadvisorapiv2.ContainerInfo, e return &rootInfo, nil } - -// extractVersionNumber gets the version number from the full version string on Windows -// e.g. extracts "10.0.14393" from "Microsoft Windows [Version 10.0.14393]" -func extractVersionNumber(fullVersion string) string { - re := regexp.MustCompile("[^0-9.]") - version := re.ReplaceAllString(fullVersion, "") - return version -} diff --git a/pkg/kubelet/winstats/winstats_test.go b/pkg/kubelet/winstats/winstats_test.go index c17107507087..42df2bb2d808 100644 --- a/pkg/kubelet/winstats/winstats_test.go +++ b/pkg/kubelet/winstats/winstats_test.go @@ -116,13 +116,6 @@ func TestWinVersionInfo(t *testing.T) { KernelVersion: "v42"}) } -func TestExtractVersionNumber(t *testing.T) { - fullVersion := "Microsoft Windows [Version 10.0.14393]" - versionNumber := extractVersionNumber(fullVersion) - expected := "10.0.14393" - assert.Equal(t, expected, versionNumber) -} - func getClient(t *testing.T) Client { f := fakeWinNodeStatsClient{} c, err := newClient(f)