Merge pull request #52144 from andyxning/fix_network_value_for_stats_summary

Automatic merge from submit-queue. If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

fix network value for stats summary for multiple network interfaces

This PR is part of [Heapster #1788](https://github.com/kubernetes/heapster/pull/1788). 

The original reason is when there are more than one none `lo`, `docker0`, `veth` network interfaces instead of just one `eth0`, the network interface value is only partial and does not correct. For now, summary stats api only gets the eth0 network interface values.

The original issues about this can be find in [Heapster #1058](https://github.com/kubernetes/heapster/issues/1058) and [Cadvisor #1593](https://github.com/google/cadvisor/issues/1593).

```release-note
Fix stats summary network value when multiple network interfaces are available.
```

/cc @DirectXMan12 @piosz @xiangpengzhao @vishh @timstclair
pull/6/head
Kubernetes Submit Queue 2017-11-28 14:59:08 -08:00 committed by GitHub
commit 8226973ae8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 73 additions and 28 deletions

View File

@ -141,10 +141,10 @@ type PodReference struct {
UID string `json:"uid"`
}
// NetworkStats contains data about network resources.
type NetworkStats struct {
// The time at which these stats were updated.
Time metav1.Time `json:"time"`
// InterfaceStats contains resource value data about interface.
type InterfaceStats struct {
// The name of the interface
Name string `json:"name"`
// Cumulative count of bytes received.
// +optional
RxBytes *uint64 `json:"rxBytes,omitempty"`
@ -159,6 +159,17 @@ type NetworkStats struct {
TxErrors *uint64 `json:"txErrors,omitempty"`
}
// NetworkStats contains data about network resources.
type NetworkStats struct {
// The time at which these stats were updated.
Time metav1.Time `json:"time"`
// Stats for the default interface, if found
InterfaceStats `json:",inline"`
Interfaces []InterfaceStats `json:"interfaces,omitempty"`
}
// CPUStats contains data about CPU usage.
type CPUStats struct {
// The time at which these stats were updated.

View File

@ -138,19 +138,29 @@ func cadvisorInfoToNetworkStats(name string, info *cadvisorapiv2.ContainerInfo)
if !found {
return nil
}
for _, inter := range cstat.Network.Interfaces {
if inter.Name == network.DefaultInterfaceName {
return &statsapi.NetworkStats{
Time: metav1.NewTime(cstat.Timestamp),
RxBytes: &inter.RxBytes,
RxErrors: &inter.RxErrors,
TxBytes: &inter.TxBytes,
TxErrors: &inter.TxErrors,
}
}
iStats := statsapi.NetworkStats{
Time: metav1.NewTime(cstat.Timestamp),
}
glog.V(4).Infof("Missing default interface %q for %s", network.DefaultInterfaceName, name)
return nil
for i := range cstat.Network.Interfaces {
inter := cstat.Network.Interfaces[i]
iStat := statsapi.InterfaceStats{
Name: inter.Name,
RxBytes: &inter.RxBytes,
RxErrors: &inter.RxErrors,
TxBytes: &inter.TxBytes,
TxErrors: &inter.TxErrors,
}
if inter.Name == network.DefaultInterfaceName {
iStats.InterfaceStats = iStat
}
iStats.Interfaces = append(iStats.Interfaces, iStat)
}
return &iStats
}
// cadvisorInfoToUserDefinedMetrics returns the statsapi.UserDefinedMetric

View File

@ -531,10 +531,26 @@ func testTime(base time.Time, seed int) time.Time {
func checkNetworkStats(t *testing.T, label string, seed int, stats *statsapi.NetworkStats) {
assert.NotNil(t, stats)
assert.EqualValues(t, testTime(timestamp, seed).Unix(), stats.Time.Time.Unix(), label+".Net.Time")
assert.EqualValues(t, "eth0", stats.Name, "default interface name is not eth0")
assert.EqualValues(t, seed+offsetNetRxBytes, *stats.RxBytes, label+".Net.RxBytes")
assert.EqualValues(t, seed+offsetNetRxErrors, *stats.RxErrors, label+".Net.RxErrors")
assert.EqualValues(t, seed+offsetNetTxBytes, *stats.TxBytes, label+".Net.TxBytes")
assert.EqualValues(t, seed+offsetNetTxErrors, *stats.TxErrors, label+".Net.TxErrors")
assert.EqualValues(t, 2, len(stats.Interfaces), "network interfaces should contain 2 elements")
assert.EqualValues(t, "eth0", stats.Interfaces[0].Name, "default interface name is ont eth0")
assert.EqualValues(t, seed+offsetNetRxBytes, *stats.Interfaces[0].RxBytes, label+".Net.TxErrors")
assert.EqualValues(t, seed+offsetNetRxErrors, *stats.Interfaces[0].RxErrors, label+".Net.TxErrors")
assert.EqualValues(t, seed+offsetNetTxBytes, *stats.Interfaces[0].TxBytes, label+".Net.TxErrors")
assert.EqualValues(t, seed+offsetNetTxErrors, *stats.Interfaces[0].TxErrors, label+".Net.TxErrors")
assert.EqualValues(t, "cbr0", stats.Interfaces[1].Name, "cbr0 interface name is ont cbr0")
assert.EqualValues(t, 100, *stats.Interfaces[1].RxBytes, label+".Net.TxErrors")
assert.EqualValues(t, 100, *stats.Interfaces[1].RxErrors, label+".Net.TxErrors")
assert.EqualValues(t, 100, *stats.Interfaces[1].TxBytes, label+".Net.TxErrors")
assert.EqualValues(t, 100, *stats.Interfaces[1].TxErrors, label+".Net.TxErrors")
}
func checkCPUStats(t *testing.T, label string, seed int, stats *statsapi.CPUStats) {

View File

@ -169,11 +169,15 @@ var _ = framework.KubeDescribe("Summary API", func() {
}),
}),
"Network": ptrMatchAllFields(gstruct.Fields{
"Time": recent(maxStatsAge),
"RxBytes": bounded(10, 10*framework.Mb),
"RxErrors": bounded(0, 1000),
"TxBytes": bounded(10, 10*framework.Mb),
"TxErrors": bounded(0, 1000),
"Time": recent(maxStatsAge),
"InterfaceStats": gstruct.MatchAllFields(gstruct.Fields{
"Name": Equal("eth0"),
"RxBytes": bounded(10, 10*framework.Mb),
"RxErrors": bounded(0, 1000),
"TxBytes": bounded(10, 10*framework.Mb),
"TxErrors": bounded(0, 1000),
}),
"Interfaces": Not(BeNil()),
}),
"CPU": ptrMatchAllFields(gstruct.Fields{
"Time": recent(maxStatsAge),
@ -236,13 +240,17 @@ var _ = framework.KubeDescribe("Summary API", func() {
"MajorPageFaults": bounded(0, 100000),
}),
// TODO(#28407): Handle non-eth0 network interface names.
"Network": Or(BeNil(), ptrMatchAllFields(gstruct.Fields{
"Time": recent(maxStatsAge),
"RxBytes": bounded(1*framework.Mb, 100*framework.Gb),
"RxErrors": bounded(0, 100000),
"TxBytes": bounded(10*framework.Kb, 10*framework.Gb),
"TxErrors": bounded(0, 100000),
})),
"Network": ptrMatchAllFields(gstruct.Fields{
"Time": recent(maxStatsAge),
"InterfaceStats": gstruct.MatchAllFields(gstruct.Fields{
"Name": Or(BeEmpty(), Equal("eth0")),
"RxBytes": Or(BeNil(), bounded(1*framework.Mb, 100*framework.Gb)),
"RxErrors": Or(BeNil(), bounded(0, 100000)),
"TxBytes": Or(BeNil(), bounded(10*framework.Kb, 10*framework.Gb)),
"TxErrors": Or(BeNil(), bounded(0, 100000)),
}),
"Interfaces": Not(BeNil()),
}),
"Fs": ptrMatchAllFields(gstruct.Fields{
"Time": recent(maxStatsAge),
"AvailableBytes": fsCapacityBounds,