From b4ba8cf18858e05ee7aaae31fb38ee2a2295b9d0 Mon Sep 17 00:00:00 2001 From: gab-satchi Date: Thu, 24 Oct 2019 18:05:25 +0100 Subject: [PATCH 1/4] Adds Windows build information as a label on the node --- pkg/kubelet/kubelet_node_status.go | 4 + pkg/kubelet/kubelet_node_status_others.go | 27 ++++ pkg/kubelet/kubelet_node_status_windows.go | 33 +++++ pkg/kubelet/winstats/perfcounter_nodestats.go | 11 +- pkg/kubelet/winstats/version.go | 120 ++++++------------ .../k8s.io/api/core/v1/well_known_labels.go | 2 + 6 files changed, 111 insertions(+), 86 deletions(-) create mode 100644 pkg/kubelet/kubelet_node_status_others.go create mode 100644 pkg/kubelet/kubelet_node_status_windows.go diff --git a/pkg/kubelet/kubelet_node_status.go b/pkg/kubelet/kubelet_node_status.go index e0e27b32b7c..efba9666679 100644 --- a/pkg/kubelet/kubelet_node_status.go +++ b/pkg/kubelet/kubelet_node_status.go @@ -230,6 +230,10 @@ func (kl *Kubelet) initialNode(ctx context.Context) (*v1.Node, error) { Unschedulable: !kl.registerSchedulable, }, } + if err := addOSSpecificLabels(node); err != nil { + return nil, err + } + 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..30d3dd2f84f --- /dev/null +++ b/pkg/kubelet/kubelet_node_status_others.go @@ -0,0 +1,27 @@ +// +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" +) + +func addOSSpecificLabels(n *v1.Node) error { + return 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..9ee3ac81d07 --- /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 addOSSpecificLabels(n *v1.Node) error { + osInfo, err := winstats.GetOSInfo() + if err != nil { + return err + } + n.Labels[v1.LabelWindowsBuild] = osInfo.GetBuild() + return nil +} 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..66c8926f3e4 100644 --- a/pkg/kubelet/winstats/version.go +++ b/pkg/kubelet/winstats/version.go @@ -20,96 +20,60 @@ 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 +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 +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 +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 3287fb51fc2..55ddbb1cafb 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 @@ -26,6 +26,8 @@ const ( LabelOSStable = "kubernetes.io/os" LabelArchStable = "kubernetes.io/arch" + 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/*) From 79dafaa76023498dbe2cf1fc6c22243c14377e0a Mon Sep 17 00:00:00 2001 From: Gab Satch Date: Mon, 28 Oct 2019 17:02:15 -0400 Subject: [PATCH 2/4] bazel and gofmt fixes Signed-off-by: Ben Moss --- pkg/kubelet/BUILD | 9 ++++++++- pkg/kubelet/winstats/BUILD | 1 + pkg/kubelet/winstats/version.go | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/pkg/kubelet/BUILD b/pkg/kubelet/BUILD index 74580901464..a6fb4fe15a3 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", @@ -151,7 +153,12 @@ go_library( "//vendor/k8s.io/utils/exec:go_default_library", "//vendor/k8s.io/utils/integer: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/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/version.go b/pkg/kubelet/winstats/version.go index 66c8926f3e4..3a439d01aa6 100644 --- a/pkg/kubelet/winstats/version.go +++ b/pkg/kubelet/winstats/version.go @@ -24,7 +24,7 @@ import ( ) type OSInfo struct { - BuildNumber, ProductName string + BuildNumber, ProductName string MajorVersion, MinorVersion, UBR uint64 } From e852cd40f08e136d1ac384ad2dae021f88458046 Mon Sep 17 00:00:00 2001 From: Gab Satch Date: Tue, 29 Oct 2019 08:25:11 -0400 Subject: [PATCH 3/4] golint changes --- pkg/kubelet/winstats/version.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pkg/kubelet/winstats/version.go b/pkg/kubelet/winstats/version.go index 3a439d01aa6..7f38cc1cea7 100644 --- a/pkg/kubelet/winstats/version.go +++ b/pkg/kubelet/winstats/version.go @@ -23,6 +23,7 @@ import ( "golang.org/x/sys/windows/registry" ) +//OSInfo is a convenience class for retrieving Windows OS information type OSInfo struct { BuildNumber, ProductName string MajorVersion, MinorVersion, UBR uint64 @@ -70,10 +71,12 @@ func GetOSInfo() (*OSInfo, error) { }, 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) } +//GetBuild returns OS version upto build number func (o *OSInfo) GetBuild() string { return fmt.Sprintf("%d.%d.%s", o.MajorVersion, o.MinorVersion, o.BuildNumber) } From f8e90eb5b0e6b085ae00062de90c16a4bb6c643c Mon Sep 17 00:00:00 2001 From: Gab Satch Date: Tue, 12 Nov 2019 16:50:43 -0500 Subject: [PATCH 4/4] Replaces modifying node object with returning a map of labels - Adds label to update flow so can be picked up by an existing node --- pkg/kubelet/kubelet_node_status.go | 7 ++++++- pkg/kubelet/kubelet_node_status_others.go | 8 ++------ pkg/kubelet/kubelet_node_status_windows.go | 8 ++++---- staging/src/k8s.io/api/core/v1/well_known_labels.go | 2 ++ 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/pkg/kubelet/kubelet_node_status.go b/pkg/kubelet/kubelet_node_status.go index efba9666679..c1b8f1f72b0 100644 --- a/pkg/kubelet/kubelet_node_status.go +++ b/pkg/kubelet/kubelet_node_status.go @@ -155,6 +155,7 @@ func (kl *Kubelet) updateDefaultLabels(initialNode, existingNode *v1.Node) bool v1.LabelInstanceType, v1.LabelOSStable, v1.LabelArchStable, + v1.LabelWindowsBuild, kubeletapis.LabelOS, kubeletapis.LabelArch, } @@ -230,9 +231,13 @@ func (kl *Kubelet) initialNode(ctx context.Context) (*v1.Node, error) { Unschedulable: !kl.registerSchedulable, }, } - if err := addOSSpecificLabels(node); err != nil { + 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 { diff --git a/pkg/kubelet/kubelet_node_status_others.go b/pkg/kubelet/kubelet_node_status_others.go index 30d3dd2f84f..ab1e3647265 100644 --- a/pkg/kubelet/kubelet_node_status_others.go +++ b/pkg/kubelet/kubelet_node_status_others.go @@ -18,10 +18,6 @@ limitations under the License. package kubelet -import ( - v1 "k8s.io/api/core/v1" -) - -func addOSSpecificLabels(n *v1.Node) error { - return nil +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 index 9ee3ac81d07..53d523bcc88 100644 --- a/pkg/kubelet/kubelet_node_status_windows.go +++ b/pkg/kubelet/kubelet_node_status_windows.go @@ -23,11 +23,11 @@ import ( "k8s.io/kubernetes/pkg/kubelet/winstats" ) -func addOSSpecificLabels(n *v1.Node) error { +func getOSSpecificLabels() (map[string]string, error) { osInfo, err := winstats.GetOSInfo() if err != nil { - return err + return nil, err } - n.Labels[v1.LabelWindowsBuild] = osInfo.GetBuild() - return nil + + return map[string]string{v1.LabelWindowsBuild: osInfo.GetBuild()}, nil } 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 55ddbb1cafb..c6e09d9f565 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 @@ -26,6 +26,8 @@ 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/*)