diff --git a/pkg/kubelet/BUILD b/pkg/kubelet/BUILD index 714a98b6840..43ff5f1e25c 100644 --- a/pkg/kubelet/BUILD +++ b/pkg/kubelet/BUILD @@ -18,6 +18,8 @@ go_library( "kubelet_network_linux.go", "kubelet_network_others.go", "kubelet_node_status.go", + "kubelet_node_status_others.go", + "kubelet_node_status_windows.go", "kubelet_pods.go", "kubelet_resources.go", "kubelet_volumes.go", @@ -149,7 +151,12 @@ go_library( "//vendor/k8s.io/utils/integer:go_default_library", "//vendor/k8s.io/utils/net:go_default_library", "//vendor/k8s.io/utils/path:go_default_library", - ], + ] + select({ + "@io_bazel_rules_go//go/platform:windows": [ + "//pkg/kubelet/winstats:go_default_library", + ], + "//conditions:default": [], + }), ) go_test( diff --git a/pkg/kubelet/kubelet_node_status.go b/pkg/kubelet/kubelet_node_status.go index f56817ebcd9..5ed554c0fe8 100644 --- a/pkg/kubelet/kubelet_node_status.go +++ b/pkg/kubelet/kubelet_node_status.go @@ -156,6 +156,7 @@ func (kl *Kubelet) updateDefaultLabels(initialNode, existingNode *v1.Node) bool v1.LabelInstanceType, v1.LabelOSStable, v1.LabelArchStable, + v1.LabelWindowsBuild, kubeletapis.LabelOS, kubeletapis.LabelArch, } @@ -231,6 +232,14 @@ func (kl *Kubelet) initialNode(ctx context.Context) (*v1.Node, error) { Unschedulable: !kl.registerSchedulable, }, } + osLabels, err := getOSSpecificLabels() + if err != nil { + return nil, err + } + for label, value := range osLabels { + node.Labels[label] = value + } + nodeTaints := make([]v1.Taint, 0) if len(kl.registerWithTaints) > 0 { taints := make([]v1.Taint, len(kl.registerWithTaints)) diff --git a/pkg/kubelet/kubelet_node_status_others.go b/pkg/kubelet/kubelet_node_status_others.go new file mode 100644 index 00000000000..ab1e3647265 --- /dev/null +++ b/pkg/kubelet/kubelet_node_status_others.go @@ -0,0 +1,23 @@ +// +build !windows + +/* +Copyright 2019 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 kubelet + +func getOSSpecificLabels() (map[string]string, error) { + return nil, nil +} diff --git a/pkg/kubelet/kubelet_node_status_windows.go b/pkg/kubelet/kubelet_node_status_windows.go new file mode 100644 index 00000000000..53d523bcc88 --- /dev/null +++ b/pkg/kubelet/kubelet_node_status_windows.go @@ -0,0 +1,33 @@ +// +build windows + +/* +Copyright 2019 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 kubelet + +import ( + v1 "k8s.io/api/core/v1" + "k8s.io/kubernetes/pkg/kubelet/winstats" +) + +func getOSSpecificLabels() (map[string]string, error) { + osInfo, err := winstats.GetOSInfo() + if err != nil { + return nil, err + } + + return map[string]string{v1.LabelWindowsBuild: osInfo.GetBuild()}, nil +} diff --git a/pkg/kubelet/winstats/BUILD b/pkg/kubelet/winstats/BUILD index b3a1150d791..53f98edbf7b 100644 --- a/pkg/kubelet/winstats/BUILD +++ b/pkg/kubelet/winstats/BUILD @@ -20,6 +20,7 @@ go_library( "//vendor/github.com/google/cadvisor/info/v1:go_default_library", "//vendor/github.com/google/cadvisor/info/v2:go_default_library", "//vendor/golang.org/x/sys/windows:go_default_library", + "//vendor/golang.org/x/sys/windows/registry:go_default_library", "//vendor/k8s.io/klog:go_default_library", ], "//conditions:default": [], diff --git a/pkg/kubelet/winstats/perfcounter_nodestats.go b/pkg/kubelet/winstats/perfcounter_nodestats.go index 317c08bf028..4d8a2355197 100644 --- a/pkg/kubelet/winstats/perfcounter_nodestats.go +++ b/pkg/kubelet/winstats/perfcounter_nodestats.go @@ -78,19 +78,14 @@ func (p *perfCounterNodeStatsClient) startMonitoring() error { return err } - kernelVersion, err := getKernelVersion() - if err != nil { - return err - } - - osImageVersion, err := getOSImageVersion() + osInfo, err := GetOSInfo() if err != nil { return err } p.nodeInfo = nodeInfo{ - kernelVersion: kernelVersion, - osImageVersion: osImageVersion, + kernelVersion: osInfo.GetPatchVersion(), + osImageVersion: osInfo.ProductName, memoryPhysicalCapacityBytes: memory, startTime: time.Now(), } diff --git a/pkg/kubelet/winstats/version.go b/pkg/kubelet/winstats/version.go index 8020b297368..7f38cc1cea7 100644 --- a/pkg/kubelet/winstats/version.go +++ b/pkg/kubelet/winstats/version.go @@ -20,96 +20,63 @@ package winstats import ( "fmt" - "unsafe" - - "golang.org/x/sys/windows" + "golang.org/x/sys/windows/registry" ) -// getCurrentVersionVal gets value of specified 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 +//OSInfo is a convenience class for retrieving Windows OS information +type OSInfo struct { + BuildNumber, ProductName string + MajorVersion, MinorVersion, UBR uint64 } -// getVersionRevision gets revision from UBR registry. -func getVersionRevision() (uint16, error) { - revisionString, err := getCurrentVersionVal("UBR") +// GetOSInfo reads Windows version information from the registry +func GetOSInfo() (*OSInfo, error) { + k, err := registry.OpenKey(registry.LOCAL_MACHINE, `SOFTWARE\Microsoft\Windows NT\CurrentVersion`, registry.QUERY_VALUE) if err != nil { - return 0, err + return nil, err + } + defer k.Close() + + buildNumber, _, err := k.GetStringValue("CurrentBuildNumber") + if err != nil { + return nil, err } - revision, err := windows.UTF16FromString(revisionString) + majorVersionNumber, _, err := k.GetIntegerValue("CurrentMajorVersionNumber") if err != nil { - return 0, err + return nil, err } - return revision[0], nil + minorVersionNumber, _, err := k.GetIntegerValue("CurrentMinorVersionNumber") + if err != nil { + return nil, err + } + + revision, _, err := k.GetIntegerValue("UBR") + if err != nil { + return nil, err + } + + productName, _, err := k.GetStringValue("ProductName") + if err != nil { + return nil, nil + } + + return &OSInfo{ + BuildNumber: buildNumber, + ProductName: productName, + MajorVersion: majorVersionNumber, + MinorVersion: minorVersionNumber, + UBR: revision, + }, nil } -// getKernelVersion gets the version of windows kernel. -func getKernelVersion() (string, error) { - // Get CurrentBuildNumber. - buildNumber, err := getCurrentVersionVal("CurrentBuildNumber") - if err != nil { - return "", err - } - - // Get CurrentMajorVersionNumber. - majorVersionNumberString, err := getCurrentVersionVal("CurrentMajorVersionNumber") - if err != nil { - return "", err - } - majorVersionNumber, err := windows.UTF16FromString(majorVersionNumberString) - if err != nil { - return "", err - } - - // Get CurrentMinorVersionNumber. - minorVersionNumberString, err := getCurrentVersionVal("CurrentMinorVersionNumber") - if err != nil { - return "", err - } - minorVersionNumber, err := windows.UTF16FromString(minorVersionNumberString) - if err != nil { - return "", err - } - - // Get UBR. - revision, err := getVersionRevision() - if err != nil { - return "", err - } - - return fmt.Sprintf("%d.%d.%s.%d", majorVersionNumber[0], minorVersionNumber[0], buildNumber, revision), nil +//GetPatchVersion returns full OS version with patch +func (o *OSInfo) GetPatchVersion() string { + return fmt.Sprintf("%d.%d.%s.%d", o.MajorVersion, o.MinorVersion, o.BuildNumber, o.UBR) } -// getOSImageVersion gets the osImage name and version. -func getOSImageVersion() (string, error) { - productName, err := getCurrentVersionVal("ProductName") - if err != nil { - return "", nil - } - - return productName, nil +//GetBuild returns OS version upto build number +func (o *OSInfo) GetBuild() string { + return fmt.Sprintf("%d.%d.%s", o.MajorVersion, o.MinorVersion, o.BuildNumber) } diff --git a/staging/src/k8s.io/api/core/v1/well_known_labels.go b/staging/src/k8s.io/api/core/v1/well_known_labels.go index 9017cb17799..22aa55b9111 100644 --- a/staging/src/k8s.io/api/core/v1/well_known_labels.go +++ b/staging/src/k8s.io/api/core/v1/well_known_labels.go @@ -30,6 +30,10 @@ const ( LabelOSStable = "kubernetes.io/os" LabelArchStable = "kubernetes.io/arch" + // LabelWindowsBuild is used on Windows nodes to specify the Windows build number starting with v1.17.0. + // It's in the format MajorVersion.MinorVersion.BuildNumber (for ex: 10.0.17763) + LabelWindowsBuild = "node.kubernetes.io/windows-build" + // LabelNamespaceSuffixKubelet is an allowed label namespace suffix kubelets can self-set ([*.]kubelet.kubernetes.io/*) LabelNamespaceSuffixKubelet = "kubelet.kubernetes.io" // LabelNamespaceSuffixNode is an allowed label namespace suffix kubelets can self-set ([*.]node.kubernetes.io/*)