diff --git a/pkg/kubelet/winstats/perfcounter_nodestats.go b/pkg/kubelet/winstats/perfcounter_nodestats.go index e1b3d413f29..9eee9772f65 100644 --- a/pkg/kubelet/winstats/perfcounter_nodestats.go +++ b/pkg/kubelet/winstats/perfcounter_nodestats.go @@ -25,6 +25,7 @@ import ( "os" "os/exec" "runtime" + "strconv" "strings" "sync" "syscall" @@ -33,10 +34,16 @@ import ( cadvisorapi "github.com/google/cadvisor/info/v1" "golang.org/x/sys/windows" + "golang.org/x/sys/windows/registry" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/klog/v2" ) +const ( + bootIdRegistry = `SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters` + bootIdKey = `BootId` +) + // MemoryStatusEx is the same as Windows structure MEMORYSTATUSEX // https://msdn.microsoft.com/en-us/library/windows/desktop/aa366770(v=vs.85).aspx type MemoryStatusEx struct { @@ -144,11 +151,17 @@ func (p *perfCounterNodeStatsClient) getMachineInfo() (*cadvisorapi.MachineInfo, return nil, err } + bootId, err := getBootID() + if err != nil { + return nil, err + } + return &cadvisorapi.MachineInfo{ NumCores: processorCount(), MemoryCapacity: p.nodeInfo.memoryPhysicalCapacityBytes, MachineID: hostname, SystemUUID: systemUUID, + BootID: bootId, }, nil } @@ -275,3 +288,16 @@ func getPhysicallyInstalledSystemMemoryBytes() (uint64, error) { return statex.TotalPhys, nil } + +func getBootID() (string, error) { + regKey, err := registry.OpenKey(registry.LOCAL_MACHINE, bootIdRegistry, registry.READ) + if err != nil { + return "", err + } + defer regKey.Close() + regValue, _, err := regKey.GetIntegerValue(bootIdKey) + if err != nil { + return "", err + } + return strconv.FormatUint(regValue, 10), nil +} diff --git a/test/e2e/windows/kubelet_stats.go b/test/e2e/windows/kubelet_stats.go index 493d59f1ba8..23d003ec17e 100644 --- a/test/e2e/windows/kubelet_stats.go +++ b/test/e2e/windows/kubelet_stats.go @@ -39,6 +39,7 @@ var _ = SIGDescribe("[Feature:Windows] Kubelet-Stats [Serial]", func() { f := framework.NewDefaultFramework("kubelet-stats-test-windows-serial") ginkgo.Describe("Kubelet stats collection for Windows nodes", func() { + ginkgo.Context("when running 10 pods", func() { // 10 seconds is the default scrape timeout for metrics-server and kube-prometheus ginkgo.It("should return within 10 seconds", func() { @@ -113,6 +114,19 @@ var _ = SIGDescribe("[Feature:Windows] Kubelet-Stats", func() { f := framework.NewDefaultFramework("kubelet-stats-test-windows") ginkgo.Describe("Kubelet stats collection for Windows nodes", func() { + + ginkgo.Context("when windows is booted", func() { + ginkgo.It("should return bootid within 10 seconds", func() { + ginkgo.By("Selecting a Windows node") + targetNode, err := findWindowsNode(f) + framework.ExpectNoError(err, "Error finding Windows node") + framework.Logf("Using node: %v", targetNode.Name) + + ginkgo.By("Getting bootid") + framework.ExpectEqual(len(targetNode.Status.NodeInfo.BootID) != 0, true, "Should find bootId in kubelet stats") + }) + }) + ginkgo.Context("when running 3 pods", func() { // 10 seconds is the default scrape timeout for metrics-server and kube-prometheus ginkgo.It("should return within 10 seconds", func() {