diff --git a/pkg/kubelet/winstats/BUILD b/pkg/kubelet/winstats/BUILD index 25afdd4cfc0..503e8d7297c 100644 --- a/pkg/kubelet/winstats/BUILD +++ b/pkg/kubelet/winstats/BUILD @@ -4,6 +4,7 @@ go_library( name = "go_default_library", srcs = [ "doc.go", + "network_stats.go", "perfcounter_nodestats.go", "perfcounters.go", "version.go", diff --git a/pkg/kubelet/winstats/network_stats.go b/pkg/kubelet/winstats/network_stats.go new file mode 100644 index 00000000000..bfd80bc50d9 --- /dev/null +++ b/pkg/kubelet/winstats/network_stats.go @@ -0,0 +1,67 @@ +// +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 winstats + +import ( + "encoding/json" + "os/exec" + + cadvisorapi "github.com/google/cadvisor/info/v1" +) + +// netAdapterStat represents network statistics for an adapter. +type netAdapterStat struct { + Name string `json:"Name,omitempty"` + ReceivedBytes uint64 `json:"ReceivedBytes,omitempty"` + ReceivedErrors uint64 `json:"ReceivedPacketErrors,omitempty"` + SentBytes uint64 `json:"SentBytes,omitempty"` + SentErrors uint64 `json:"OutboundPacketErrors,omitempty"` +} + +// toCadvisorInterfaceStats converts netAdapterStat to cadvisorapi.InterfaceStats. +func (s *netAdapterStat) toCadvisorInterfaceStats() cadvisorapi.InterfaceStats { + return cadvisorapi.InterfaceStats{ + Name: s.Name, + RxBytes: s.ReceivedBytes, + RxErrors: s.ReceivedErrors, + TxBytes: s.SentBytes, + TxErrors: s.SentErrors, + } +} + +// getNetAdapterStats gets a list of network adapter statistics. +func getNetAdapterStats() ([]cadvisorapi.InterfaceStats, error) { + rawOutput, err := exec.Command("powershell", "/c", " Get-NetAdapterStatistics | ConvertTo-Json").CombinedOutput() + if err != nil { + return nil, err + } + + var stats []*netAdapterStat + err = json.Unmarshal(rawOutput, &stats) + if err != nil { + return nil, err + } + + result := make([]cadvisorapi.InterfaceStats, len(stats)) + for i := range stats { + result[i] = stats[i].toCadvisorInterfaceStats() + } + + return result, nil +} diff --git a/pkg/kubelet/winstats/winstats.go b/pkg/kubelet/winstats/winstats.go index 2c483f8967e..5a194429c5d 100644 --- a/pkg/kubelet/winstats/winstats.go +++ b/pkg/kubelet/winstats/winstats.go @@ -109,12 +109,16 @@ func (c *StatsClient) WinVersionInfo() (*cadvisorapi.VersionInfo, error) { func (c *StatsClient) createRootContainerInfo() (*cadvisorapiv2.ContainerInfo, error) { nodeMetrics, err := c.client.getNodeMetrics() - if err != nil { return nil, err } - var stats []*cadvisorapiv2.ContainerStats + netAdapterStats, err := getNetAdapterStats() + if err != nil { + return nil, err + } + + var stats []*cadvisorapiv2.ContainerStats stats = append(stats, &cadvisorapiv2.ContainerStats{ Timestamp: nodeMetrics.timeStamp, Cpu: &cadvisorapi.CpuStats{ @@ -126,6 +130,9 @@ func (c *StatsClient) createRootContainerInfo() (*cadvisorapiv2.ContainerInfo, e WorkingSet: nodeMetrics.memoryPrivWorkingSetBytes, Usage: nodeMetrics.memoryCommittedBytes, }, + Network: &cadvisorapiv2.NetworkStats{ + Interfaces: netAdapterStats, + }, }) nodeInfo := c.client.getNodeInfo() @@ -134,6 +141,7 @@ func (c *StatsClient) createRootContainerInfo() (*cadvisorapiv2.ContainerInfo, e CreationTime: nodeInfo.startTime, HasCpu: true, HasMemory: true, + HasNetwork: true, Memory: cadvisorapiv2.MemorySpec{ Limit: nodeInfo.memoryPhysicalCapacityBytes, }, diff --git a/pkg/kubelet/winstats/winstats_test.go b/pkg/kubelet/winstats/winstats_test.go index 830f76af039..51f7a290d19 100644 --- a/pkg/kubelet/winstats/winstats_test.go +++ b/pkg/kubelet/winstats/winstats_test.go @@ -86,8 +86,9 @@ func TestWinContainerInfos(t *testing.T) { infos := make(map[string]cadvisorapiv2.ContainerInfo) infos["/"] = cadvisorapiv2.ContainerInfo{ Spec: cadvisorapiv2.ContainerSpec{ - HasCpu: true, - HasMemory: true, + HasCpu: true, + HasMemory: true, + HasNetwork: true, Memory: cadvisorapiv2.MemorySpec{ Limit: 1.6e+10, }, @@ -95,7 +96,11 @@ func TestWinContainerInfos(t *testing.T) { Stats: stats, } - assert.Equal(t, actualRootInfos, infos) + assert.Equal(t, len(actualRootInfos), len(infos)) + assert.Equal(t, actualRootInfos["/"].Spec, infos["/"].Spec) + assert.Equal(t, len(actualRootInfos["/"].Stats), len(infos["/"].Stats)) + assert.Equal(t, actualRootInfos["/"].Stats[0].Cpu, infos["/"].Stats[0].Cpu) + assert.Equal(t, actualRootInfos["/"].Stats[0].Memory, infos["/"].Stats[0].Memory) } func TestWinMachineInfo(t *testing.T) {