Merge pull request #74788 from feiskyer/windows-network-stats

Add network stats for Windows nodes and containers
pull/564/head
Kubernetes Prow Robot 2019-03-07 16:12:24 -08:00 committed by GitHub
commit fbc5150c7d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 547 additions and 15 deletions

View File

@ -5,6 +5,8 @@ go_library(
srcs = [
"cadvisor_stats_provider.go",
"cri_stats_provider.go",
"cri_stats_provider_others.go",
"cri_stats_provider_windows.go",
"helper.go",
"log_metrics_provider.go",
"stats_provider.go",
@ -32,7 +34,13 @@ go_library(
"//vendor/github.com/google/cadvisor/info/v1:go_default_library",
"//vendor/github.com/google/cadvisor/info/v2:go_default_library",
"//vendor/k8s.io/klog:go_default_library",
],
] + select({
"@io_bazel_rules_go//go/platform:windows": [
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//vendor/github.com/Microsoft/hcsshim:go_default_library",
],
"//conditions:default": [],
}),
)
filegroup(

View File

@ -26,11 +26,10 @@ import (
"time"
cadvisorfs "github.com/google/cadvisor/fs"
"k8s.io/klog"
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/klog"
internalapi "k8s.io/kubernetes/pkg/kubelet/apis/cri"
runtimeapi "k8s.io/kubernetes/pkg/kubelet/apis/cri/runtime/v1alpha2"
statsapi "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1"
@ -161,6 +160,13 @@ func (p *criStatsProvider) listPodStats(updateCPUNanoCoreUsage bool) ([]statsapi
}
caInfos := getCRICadvisorStats(allInfos)
// get network stats for containers.
// This is only used on Windows. For other platforms, (nil, nil) should be returned.
containerNetworkStats, err := p.listContainerNetworkStats()
if err != nil {
return nil, fmt.Errorf("failed to list container network stats: %v", err)
}
for _, stats := range resp {
containerID := stats.Attributes.Id
container, found := containerMap[containerID]
@ -184,7 +190,7 @@ func (p *criStatsProvider) listPodStats(updateCPUNanoCoreUsage bool) ([]statsapi
// Fill available stats for full set of required pod stats
cs := p.makeContainerStats(stats, container, &rootFsInfo, fsIDtoInfo, podSandbox.GetMetadata().GetUid(), updateCPUNanoCoreUsage)
p.addPodNetworkStats(ps, podSandboxID, caInfos, cs)
p.addPodNetworkStats(ps, podSandboxID, caInfos, cs, containerNetworkStats[podSandboxID])
p.addPodCPUMemoryStats(ps, types.UID(podSandbox.Metadata.Uid), allInfos, cs)
// If cadvisor stats is available for the container, use it to populate
@ -394,16 +400,26 @@ func (p *criStatsProvider) addPodNetworkStats(
podSandboxID string,
caInfos map[string]cadvisorapiv2.ContainerInfo,
cs *statsapi.ContainerStats,
netStats *statsapi.NetworkStats,
) {
caPodSandbox, found := caInfos[podSandboxID]
// try get network stats from cadvisor first.
if found {
ps.Network = cadvisorInfoToNetworkStats(ps.PodRef.Name, &caPodSandbox)
networkStats := cadvisorInfoToNetworkStats(ps.PodRef.Name, &caPodSandbox)
if networkStats != nil {
ps.Network = networkStats
return
}
}
// Not found from cadvisor, get from netStats.
if netStats != nil {
ps.Network = netStats
return
}
// TODO: sum Pod network stats from container stats.
klog.V(4).Infof("Unable to find cadvisor stats for sandbox %q", podSandboxID)
klog.V(4).Infof("Unable to find network stats for sandbox %q", podSandboxID)
}
func (p *criStatsProvider) addPodCPUMemoryStats(

View File

@ -0,0 +1,29 @@
// +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 stats
import (
statsapi "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1"
)
// listContainerNetworkStats returns the network stats of all the running containers.
// It should return (nil, nil) for platforms other than Windows.
func (p *criStatsProvider) listContainerNetworkStats() (map[string]*statsapi.NetworkStats, error) {
return nil, nil
}

View File

@ -0,0 +1,107 @@
// +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 stats
import (
"time"
"github.com/Microsoft/hcsshim"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog"
statsapi "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1"
)
// listContainerNetworkStats returns the network stats of all the running containers.
func (p *criStatsProvider) listContainerNetworkStats() (map[string]*statsapi.NetworkStats, error) {
containers, err := hcsshim.GetContainers(hcsshim.ComputeSystemQuery{
Types: []string{"Container"},
})
if err != nil {
return nil, err
}
stats := make(map[string]*statsapi.NetworkStats)
for _, c := range containers {
container, err := hcsshim.OpenContainer(c.ID)
if err != nil {
klog.V(4).Infof("Failed to open container %q with error '%v', continue to get stats for other containers", c.ID, err)
continue
}
cstats, err := container.Statistics()
if err != nil {
klog.V(4).Infof("Failed to get statistics for container %q with error '%v', continue to get stats for other containers", c.ID, err)
continue
}
if len(cstats.Network) > 0 {
stats[c.ID] = hcsStatsToNetworkStats(cstats.Timestamp, cstats.Network)
}
}
return stats, nil
}
// hcsStatsToNetworkStats converts hcsshim.Statistics.Network to statsapi.NetworkStats
func hcsStatsToNetworkStats(timestamp time.Time, hcsStats []hcsshim.NetworkStats) *statsapi.NetworkStats {
result := &statsapi.NetworkStats{
Time: metav1.NewTime(timestamp),
Interfaces: make([]statsapi.InterfaceStats, 0),
}
adapters := sets.NewString()
for _, stat := range hcsStats {
iStat, err := hcsStatsToInterfaceStats(stat)
if err != nil {
klog.Warningf("Failed to get HNS endpoint %q with error '%v', continue to get stats for other endpoints", stat.EndpointId, err)
continue
}
// Only count each adapter once.
if adapters.Has(iStat.Name) {
continue
}
result.Interfaces = append(result.Interfaces, *iStat)
adapters.Insert(iStat.Name)
}
// TODO(feiskyer): add support of multiple interfaces for getting default interface.
if len(result.Interfaces) > 0 {
result.InterfaceStats = result.Interfaces[0]
}
return result
}
// hcsStatsToInterfaceStats converts hcsshim.NetworkStats to statsapi.InterfaceStats.
func hcsStatsToInterfaceStats(stat hcsshim.NetworkStats) (*statsapi.InterfaceStats, error) {
endpoint, err := hcsshim.GetHNSEndpointByID(stat.EndpointId)
if err != nil {
return nil, err
}
return &statsapi.InterfaceStats{
Name: endpoint.Name,
RxBytes: &stat.BytesReceived,
TxBytes: &stat.BytesSent,
}, nil
}

View File

@ -20,11 +20,10 @@ import (
"fmt"
"time"
"k8s.io/klog"
cadvisorapiv1 "github.com/google/cadvisor/info/v1"
cadvisorapiv2 "github.com/google/cadvisor/info/v2"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/klog"
statsapi "k8s.io/kubernetes/pkg/kubelet/apis/stats/v1alpha1"
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
)
@ -158,6 +157,10 @@ func cadvisorInfoToNetworkStats(name string, info *cadvisorapiv2.ContainerInfo)
return nil
}
if cstat.Network == nil {
return nil
}
iStats := statsapi.NetworkStats{
Time: metav1.NewTime(cstat.Timestamp),
}

View File

@ -4,6 +4,7 @@ go_library(
name = "go_default_library",
srcs = [
"doc.go",
"network_stats.go",
"perfcounter_nodestats.go",
"perfcounters.go",
"version.go",
@ -13,6 +14,7 @@ go_library(
visibility = ["//visibility:public"],
deps = select({
"@io_bazel_rules_go//go/platform:windows": [
"//staging/src/k8s.io/apimachinery/pkg/util/sets:go_default_library",
"//staging/src/k8s.io/apimachinery/pkg/util/wait:go_default_library",
"//vendor/github.com/JeffAshton/win_pdh:go_default_library",
"//vendor/github.com/google/cadvisor/info/v1:go_default_library",

View File

@ -0,0 +1,312 @@
// +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 (
"sync"
cadvisorapi "github.com/google/cadvisor/info/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog"
)
const (
packetsReceivedPerSecondQuery = "\\Network Adapter(*)\\Packets Received/sec"
packetsSentPerSecondQuery = "\\Network Adapter(*)\\Packets Sent/sec"
bytesReceivedPerSecondQuery = "\\Network Adapter(*)\\Bytes Received/sec"
bytesSentPerSecondQuery = "\\Network Adapter(*)\\Bytes Sent/sec"
packetsReceivedDiscardedQuery = "\\Network Adapter(*)\\Packets Received Discarded"
packetsReceivedErrorsQuery = "\\Network Adapter(*)\\Packets Received Errors"
packetsOutboundDiscardedQuery = "\\Network Adapter(*)\\Packets Outbound Discarded"
packetsOutboundErrorsQuery = "\\Network Adapter(*)\\Packets Outbound Errors"
)
// networkCounter contains the counters for network adapters.
type networkCounter struct {
packetsReceivedPerSecondCounter *perfCounter
packetsSentPerSecondCounter *perfCounter
bytesReceivedPerSecondCounter *perfCounter
bytesSentPerSecondCounter *perfCounter
packetsReceivedDiscardedCounter *perfCounter
packetsReceivedErrorsCounter *perfCounter
packetsOutboundDiscardedCounter *perfCounter
packetsOutboundErrorsCounter *perfCounter
mu sync.RWMutex
adapterStats map[string]cadvisorapi.InterfaceStats
}
func newNetworkCounters() (*networkCounter, error) {
packetsReceivedPerSecondCounter, err := newPerfCounter(packetsReceivedPerSecondQuery)
if err != nil {
return nil, err
}
packetsSentPerSecondCounter, err := newPerfCounter(packetsSentPerSecondQuery)
if err != nil {
return nil, err
}
bytesReceivedPerSecondCounter, err := newPerfCounter(bytesReceivedPerSecondQuery)
if err != nil {
return nil, err
}
bytesSentPerSecondCounter, err := newPerfCounter(bytesSentPerSecondQuery)
if err != nil {
return nil, err
}
packetsReceivedDiscardedCounter, err := newPerfCounter(packetsReceivedDiscardedQuery)
if err != nil {
return nil, err
}
packetsReceivedErrorsCounter, err := newPerfCounter(packetsReceivedErrorsQuery)
if err != nil {
return nil, err
}
packetsOutboundDiscardedCounter, err := newPerfCounter(packetsOutboundDiscardedQuery)
if err != nil {
return nil, err
}
packetsOutboundErrorsCounter, err := newPerfCounter(packetsOutboundErrorsQuery)
if err != nil {
return nil, err
}
return &networkCounter{
packetsReceivedPerSecondCounter: packetsReceivedPerSecondCounter,
packetsSentPerSecondCounter: packetsSentPerSecondCounter,
bytesReceivedPerSecondCounter: bytesReceivedPerSecondCounter,
bytesSentPerSecondCounter: bytesSentPerSecondCounter,
packetsReceivedDiscardedCounter: packetsReceivedDiscardedCounter,
packetsReceivedErrorsCounter: packetsReceivedErrorsCounter,
packetsOutboundDiscardedCounter: packetsOutboundDiscardedCounter,
packetsOutboundErrorsCounter: packetsOutboundErrorsCounter,
adapterStats: map[string]cadvisorapi.InterfaceStats{},
}, nil
}
func (n *networkCounter) getData() ([]cadvisorapi.InterfaceStats, error) {
packetsReceivedPerSecondData, err := n.packetsReceivedPerSecondCounter.getDataList()
if err != nil {
klog.Errorf("Unable to get packetsReceivedPerSecond perf counter data; err: %v", err)
return nil, err
}
packetsSentPerSecondData, err := n.packetsSentPerSecondCounter.getDataList()
if err != nil {
klog.Errorf("Unable to get packetsSentPerSecond perf counter data; err: %v", err)
return nil, err
}
bytesReceivedPerSecondData, err := n.bytesReceivedPerSecondCounter.getDataList()
if err != nil {
klog.Errorf("Unable to get bytesReceivedPerSecond perf counter data; err: %v", err)
return nil, err
}
bytesSentPerSecondData, err := n.bytesSentPerSecondCounter.getDataList()
if err != nil {
klog.Errorf("Unable to get bytesSentPerSecond perf counter data; err: %v", err)
return nil, err
}
packetsReceivedDiscardedData, err := n.packetsReceivedDiscardedCounter.getDataList()
if err != nil {
klog.Errorf("Unable to get packetsReceivedDiscarded perf counter data; err: %v", err)
return nil, err
}
packetsReceivedErrorsData, err := n.packetsReceivedErrorsCounter.getDataList()
if err != nil {
klog.Errorf("Unable to get packetsReceivedErrors perf counter data; err: %v", err)
return nil, err
}
packetsOutboundDiscardedData, err := n.packetsOutboundDiscardedCounter.getDataList()
if err != nil {
klog.Errorf("Unable to get packetsOutboundDiscarded perf counter data; err: %v", err)
return nil, err
}
packetsOutboundErrorsData, err := n.packetsOutboundErrorsCounter.getDataList()
if err != nil {
klog.Errorf("Unable to get packetsOutboundErrors perf counter data; err: %v", err)
return nil, err
}
n.mu.Lock()
defer n.mu.Unlock()
n.mergeCollectedData(
packetsReceivedPerSecondData,
packetsSentPerSecondData,
bytesReceivedPerSecondData,
bytesSentPerSecondData,
packetsReceivedDiscardedData,
packetsReceivedErrorsData,
packetsOutboundDiscardedData,
packetsOutboundErrorsData,
)
return n.listInterfaceStats(), nil
}
// mergeCollectedData merges the collected data into cache. It should be invoked under lock protected.
func (n *networkCounter) mergeCollectedData(packetsReceivedPerSecondData,
packetsSentPerSecondData,
bytesReceivedPerSecondData,
bytesSentPerSecondData,
packetsReceivedDiscardedData,
packetsReceivedErrorsData,
packetsOutboundDiscardedData,
packetsOutboundErrorsData map[string]uint64) {
adapters := sets.NewString()
// merge the collected data and list of adapters.
adapters.Insert(n.mergePacketsReceivedPerSecondData(packetsReceivedPerSecondData)...)
adapters.Insert(n.mergePacketsSentPerSecondData(packetsSentPerSecondData)...)
adapters.Insert(n.mergeBytesReceivedPerSecondData(bytesReceivedPerSecondData)...)
adapters.Insert(n.mergeBytesSentPerSecondData(bytesSentPerSecondData)...)
adapters.Insert(n.mergePacketsReceivedDiscardedData(packetsReceivedDiscardedData)...)
adapters.Insert(n.mergePacketsReceivedErrorsData(packetsReceivedErrorsData)...)
adapters.Insert(n.mergePacketsOutboundDiscardedData(packetsOutboundDiscardedData)...)
adapters.Insert(n.mergePacketsOutboundErrorsData(packetsOutboundErrorsData)...)
// delete the cache for non-existing adapters.
for adapter := range n.adapterStats {
if !adapters.Has(adapter) {
delete(n.adapterStats, adapter)
}
}
}
func (n *networkCounter) mergePacketsReceivedPerSecondData(packetsReceivedPerSecondData map[string]uint64) []string {
var adapters []string
for adapterName, value := range packetsReceivedPerSecondData {
adapters = append(adapters, adapterName)
newStat := n.adapterStats[adapterName]
newStat.Name = adapterName
newStat.RxPackets = newStat.RxPackets + value
n.adapterStats[adapterName] = newStat
}
return adapters
}
func (n *networkCounter) mergePacketsSentPerSecondData(packetsSentPerSecondData map[string]uint64) []string {
var adapters []string
for adapterName, value := range packetsSentPerSecondData {
adapters = append(adapters, adapterName)
newStat := n.adapterStats[adapterName]
newStat.Name = adapterName
newStat.TxPackets = newStat.TxPackets + value
n.adapterStats[adapterName] = newStat
}
return adapters
}
func (n *networkCounter) mergeBytesReceivedPerSecondData(bytesReceivedPerSecondData map[string]uint64) []string {
var adapters []string
for adapterName, value := range bytesReceivedPerSecondData {
adapters = append(adapters, adapterName)
newStat := n.adapterStats[adapterName]
newStat.Name = adapterName
newStat.RxBytes = newStat.RxBytes + value
n.adapterStats[adapterName] = newStat
}
return adapters
}
func (n *networkCounter) mergeBytesSentPerSecondData(bytesSentPerSecondData map[string]uint64) []string {
var adapters []string
for adapterName, value := range bytesSentPerSecondData {
adapters = append(adapters, adapterName)
newStat := n.adapterStats[adapterName]
newStat.Name = adapterName
newStat.TxBytes = newStat.TxBytes + value
n.adapterStats[adapterName] = newStat
}
return adapters
}
func (n *networkCounter) mergePacketsReceivedDiscardedData(packetsReceivedDiscardedData map[string]uint64) []string {
var adapters []string
for adapterName, value := range packetsReceivedDiscardedData {
adapters = append(adapters, adapterName)
newStat := n.adapterStats[adapterName]
newStat.Name = adapterName
newStat.RxDropped = value
n.adapterStats[adapterName] = newStat
}
return adapters
}
func (n *networkCounter) mergePacketsReceivedErrorsData(packetsReceivedErrorsData map[string]uint64) []string {
var adapters []string
for adapterName, value := range packetsReceivedErrorsData {
adapters = append(adapters, adapterName)
newStat := n.adapterStats[adapterName]
newStat.Name = adapterName
newStat.RxErrors = value
n.adapterStats[adapterName] = newStat
}
return adapters
}
func (n *networkCounter) mergePacketsOutboundDiscardedData(packetsOutboundDiscardedData map[string]uint64) []string {
var adapters []string
for adapterName, value := range packetsOutboundDiscardedData {
adapters = append(adapters, adapterName)
newStat := n.adapterStats[adapterName]
newStat.Name = adapterName
newStat.TxDropped = value
n.adapterStats[adapterName] = newStat
}
return adapters
}
func (n *networkCounter) mergePacketsOutboundErrorsData(packetsOutboundErrorsData map[string]uint64) []string {
var adapters []string
for adapterName, value := range packetsOutboundErrorsData {
adapters = append(adapters, adapterName)
newStat := n.adapterStats[adapterName]
newStat.Name = adapterName
newStat.TxErrors = value
n.adapterStats[adapterName] = newStat
}
return adapters
}
func (n *networkCounter) listInterfaceStats() []cadvisorapi.InterfaceStats {
stats := make([]cadvisorapi.InterfaceStats, 0, len(n.adapterStats))
for _, stat := range n.adapterStats {
stats = append(stats, stat)
}
return stats
}

View File

@ -101,8 +101,13 @@ func (p *perfCounterNodeStatsClient) startMonitoring() error {
return err
}
networkAdapterCounter, err := newNetworkCounters()
if err != nil {
return err
}
go wait.Forever(func() {
p.collectMetricsData(cpuCounter, memWorkingSetCounter, memCommittedBytesCounter)
p.collectMetricsData(cpuCounter, memWorkingSetCounter, memCommittedBytesCounter, networkAdapterCounter)
}, perfCounterUpdatePeriod)
return nil
@ -138,7 +143,7 @@ func (p *perfCounterNodeStatsClient) getNodeInfo() nodeInfo {
return p.nodeInfo
}
func (p *perfCounterNodeStatsClient) collectMetricsData(cpuCounter, memWorkingSetCounter, memCommittedBytesCounter *perfCounter) {
func (p *perfCounterNodeStatsClient) collectMetricsData(cpuCounter, memWorkingSetCounter, memCommittedBytesCounter *perfCounter, networkAdapterCounter *networkCounter) {
cpuValue, err := cpuCounter.getData()
if err != nil {
klog.Errorf("Unable to get cpu perf counter data; err: %v", err)
@ -157,12 +162,19 @@ func (p *perfCounterNodeStatsClient) collectMetricsData(cpuCounter, memWorkingSe
return
}
networkAdapterStats, err := networkAdapterCounter.getData()
if err != nil {
klog.Errorf("Unable to get network adapter perf counter data; err: %v", err)
return
}
p.mu.Lock()
defer p.mu.Unlock()
p.nodeMetrics = nodeMetrics{
cpuUsageCoreNanoSeconds: p.convertCPUValue(cpuValue),
memoryPrivWorkingSetBytes: memWorkingSetValue,
memoryCommittedBytes: memCommittedBytesValue,
interfaceStats: networkAdapterStats,
timeStamp: time.Now(),
}
}

View File

@ -71,6 +71,7 @@ func newPerfCounter(counter string) (*perfCounter, error) {
}, nil
}
// getData is used for getting data without * in counter name.
func (p *perfCounter) getData() (uint64, error) {
ret := win_pdh.PdhCollectQueryData(p.queryHandle)
if ret != win_pdh.ERROR_SUCCESS {
@ -100,3 +101,36 @@ func (p *perfCounter) getData() (uint64, error) {
return data, nil
}
// getData is used for getting data with * in counter name.
func (p *perfCounter) getDataList() (map[string]uint64, error) {
ret := win_pdh.PdhCollectQueryData(p.queryHandle)
if ret != win_pdh.ERROR_SUCCESS {
return nil, fmt.Errorf("unable to collect data from counter. Error code is %x", ret)
}
var bufSize, bufCount uint32
var size = uint32(unsafe.Sizeof(win_pdh.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE{}))
var emptyBuf [1]win_pdh.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE // need at least 1 addressable null ptr.
data := map[string]uint64{}
ret = win_pdh.PdhGetFormattedCounterArrayDouble(p.counterHandle, &bufSize, &bufCount, &emptyBuf[0])
if ret != win_pdh.PDH_MORE_DATA {
return nil, fmt.Errorf("unable to collect data from counter. Error code is %x", ret)
}
filledBuf := make([]win_pdh.PDH_FMT_COUNTERVALUE_ITEM_DOUBLE, bufCount*size)
ret = win_pdh.PdhGetFormattedCounterArrayDouble(p.counterHandle, &bufSize, &bufCount, &filledBuf[0])
if ret != win_pdh.ERROR_SUCCESS {
return nil, fmt.Errorf("unable to collect data from counter. Error code is %x", ret)
}
for i := 0; i < int(bufCount); i++ {
c := filledBuf[i]
value := uint64(c.FmtValue.DoubleValue)
name := win_pdh.UTF16PtrToString(c.SzName)
data[name] = value
}
return data, nil
}

View File

@ -58,6 +58,7 @@ type nodeMetrics struct {
memoryPrivWorkingSetBytes uint64
memoryCommittedBytes uint64
timeStamp time.Time
interfaceStats []cadvisorapi.InterfaceStats
}
type nodeInfo struct {
@ -109,12 +110,11 @@ 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
var stats []*cadvisorapiv2.ContainerStats
stats = append(stats, &cadvisorapiv2.ContainerStats{
Timestamp: nodeMetrics.timeStamp,
Cpu: &cadvisorapi.CpuStats{
@ -126,6 +126,9 @@ func (c *StatsClient) createRootContainerInfo() (*cadvisorapiv2.ContainerInfo, e
WorkingSet: nodeMetrics.memoryPrivWorkingSetBytes,
Usage: nodeMetrics.memoryCommittedBytes,
},
Network: &cadvisorapiv2.NetworkStats{
Interfaces: nodeMetrics.interfaceStats,
},
})
nodeInfo := c.client.getNodeInfo()
@ -134,6 +137,7 @@ func (c *StatsClient) createRootContainerInfo() (*cadvisorapiv2.ContainerInfo, e
CreationTime: nodeInfo.startTime,
HasCpu: true,
HasMemory: true,
HasNetwork: true,
Memory: cadvisorapiv2.MemorySpec{
Limit: nodeInfo.memoryPhysicalCapacityBytes,
},

View File

@ -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) {