mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-18 08:09:58 +00:00
Merge pull request #118865 from iholder101/kubelet/add-swap-to-summary-stats
Add swap to stats to Summary API and Prometheus endpoints (`/stats/summary` and `/metrics/resource`)
This commit is contained in:
commit
b4d793c450
@ -41,6 +41,13 @@ var (
|
|||||||
metrics.ALPHA,
|
metrics.ALPHA,
|
||||||
"")
|
"")
|
||||||
|
|
||||||
|
nodeSwapUsageDesc = metrics.NewDesc("node_swap_usage_bytes",
|
||||||
|
"Current swap usage of the node in bytes. Reported only on non-windows systems",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
metrics.ALPHA,
|
||||||
|
"")
|
||||||
|
|
||||||
containerCPUUsageDesc = metrics.NewDesc("container_cpu_usage_seconds_total",
|
containerCPUUsageDesc = metrics.NewDesc("container_cpu_usage_seconds_total",
|
||||||
"Cumulative cpu time consumed by the container in core-seconds",
|
"Cumulative cpu time consumed by the container in core-seconds",
|
||||||
[]string{"container", "pod", "namespace"},
|
[]string{"container", "pod", "namespace"},
|
||||||
@ -55,6 +62,13 @@ var (
|
|||||||
metrics.ALPHA,
|
metrics.ALPHA,
|
||||||
"")
|
"")
|
||||||
|
|
||||||
|
containerSwapUsageDesc = metrics.NewDesc("container_swap_usage_bytes",
|
||||||
|
"Current amount of the container swap usage in bytes. Reported only on non-windows systems",
|
||||||
|
[]string{"container", "pod", "namespace"},
|
||||||
|
nil,
|
||||||
|
metrics.ALPHA,
|
||||||
|
"")
|
||||||
|
|
||||||
podCPUUsageDesc = metrics.NewDesc("pod_cpu_usage_seconds_total",
|
podCPUUsageDesc = metrics.NewDesc("pod_cpu_usage_seconds_total",
|
||||||
"Cumulative cpu time consumed by the pod in core-seconds",
|
"Cumulative cpu time consumed by the pod in core-seconds",
|
||||||
[]string{"pod", "namespace"},
|
[]string{"pod", "namespace"},
|
||||||
@ -69,6 +83,13 @@ var (
|
|||||||
metrics.ALPHA,
|
metrics.ALPHA,
|
||||||
"")
|
"")
|
||||||
|
|
||||||
|
podSwapUsageDesc = metrics.NewDesc("pod_swap_usage_bytes",
|
||||||
|
"Current amount of the pod swap usage in bytes. Reported only on non-windows systems",
|
||||||
|
[]string{"pod", "namespace"},
|
||||||
|
nil,
|
||||||
|
metrics.ALPHA,
|
||||||
|
"")
|
||||||
|
|
||||||
resourceScrapeResultDesc = metrics.NewDesc("scrape_error",
|
resourceScrapeResultDesc = metrics.NewDesc("scrape_error",
|
||||||
"1 if there was an error while getting container metrics, 0 otherwise",
|
"1 if there was an error while getting container metrics, 0 otherwise",
|
||||||
nil,
|
nil,
|
||||||
@ -104,11 +125,14 @@ var _ metrics.StableCollector = &resourceMetricsCollector{}
|
|||||||
func (rc *resourceMetricsCollector) DescribeWithStability(ch chan<- *metrics.Desc) {
|
func (rc *resourceMetricsCollector) DescribeWithStability(ch chan<- *metrics.Desc) {
|
||||||
ch <- nodeCPUUsageDesc
|
ch <- nodeCPUUsageDesc
|
||||||
ch <- nodeMemoryUsageDesc
|
ch <- nodeMemoryUsageDesc
|
||||||
|
ch <- nodeSwapUsageDesc
|
||||||
ch <- containerStartTimeDesc
|
ch <- containerStartTimeDesc
|
||||||
ch <- containerCPUUsageDesc
|
ch <- containerCPUUsageDesc
|
||||||
ch <- containerMemoryUsageDesc
|
ch <- containerMemoryUsageDesc
|
||||||
|
ch <- containerSwapUsageDesc
|
||||||
ch <- podCPUUsageDesc
|
ch <- podCPUUsageDesc
|
||||||
ch <- podMemoryUsageDesc
|
ch <- podMemoryUsageDesc
|
||||||
|
ch <- podSwapUsageDesc
|
||||||
ch <- resourceScrapeResultDesc
|
ch <- resourceScrapeResultDesc
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,15 +155,18 @@ func (rc *resourceMetricsCollector) CollectWithStability(ch chan<- metrics.Metri
|
|||||||
|
|
||||||
rc.collectNodeCPUMetrics(ch, statsSummary.Node)
|
rc.collectNodeCPUMetrics(ch, statsSummary.Node)
|
||||||
rc.collectNodeMemoryMetrics(ch, statsSummary.Node)
|
rc.collectNodeMemoryMetrics(ch, statsSummary.Node)
|
||||||
|
rc.collectNodeSwapMetrics(ch, statsSummary.Node)
|
||||||
|
|
||||||
for _, pod := range statsSummary.Pods {
|
for _, pod := range statsSummary.Pods {
|
||||||
for _, container := range pod.Containers {
|
for _, container := range pod.Containers {
|
||||||
rc.collectContainerStartTime(ch, pod, container)
|
rc.collectContainerStartTime(ch, pod, container)
|
||||||
rc.collectContainerCPUMetrics(ch, pod, container)
|
rc.collectContainerCPUMetrics(ch, pod, container)
|
||||||
rc.collectContainerMemoryMetrics(ch, pod, container)
|
rc.collectContainerMemoryMetrics(ch, pod, container)
|
||||||
|
rc.collectContainerSwapMetrics(ch, pod, container)
|
||||||
}
|
}
|
||||||
rc.collectPodCPUMetrics(ch, pod)
|
rc.collectPodCPUMetrics(ch, pod)
|
||||||
rc.collectPodMemoryMetrics(ch, pod)
|
rc.collectPodMemoryMetrics(ch, pod)
|
||||||
|
rc.collectPodSwapMetrics(ch, pod)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,6 +188,15 @@ func (rc *resourceMetricsCollector) collectNodeMemoryMetrics(ch chan<- metrics.M
|
|||||||
metrics.NewLazyConstMetric(nodeMemoryUsageDesc, metrics.GaugeValue, float64(*s.Memory.WorkingSetBytes)))
|
metrics.NewLazyConstMetric(nodeMemoryUsageDesc, metrics.GaugeValue, float64(*s.Memory.WorkingSetBytes)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rc *resourceMetricsCollector) collectNodeSwapMetrics(ch chan<- metrics.Metric, s summary.NodeStats) {
|
||||||
|
if s.Swap == nil || s.Swap.SwapUsageBytes == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- metrics.NewLazyMetricWithTimestamp(s.Memory.Time.Time,
|
||||||
|
metrics.NewLazyConstMetric(nodeSwapUsageDesc, metrics.GaugeValue, float64(*s.Swap.SwapUsageBytes)))
|
||||||
|
}
|
||||||
|
|
||||||
func (rc *resourceMetricsCollector) collectContainerStartTime(ch chan<- metrics.Metric, pod summary.PodStats, s summary.ContainerStats) {
|
func (rc *resourceMetricsCollector) collectContainerStartTime(ch chan<- metrics.Metric, pod summary.PodStats, s summary.ContainerStats) {
|
||||||
if s.StartTime.Unix() <= 0 {
|
if s.StartTime.Unix() <= 0 {
|
||||||
return
|
return
|
||||||
@ -190,6 +226,16 @@ func (rc *resourceMetricsCollector) collectContainerMemoryMetrics(ch chan<- metr
|
|||||||
float64(*s.Memory.WorkingSetBytes), s.Name, pod.PodRef.Name, pod.PodRef.Namespace))
|
float64(*s.Memory.WorkingSetBytes), s.Name, pod.PodRef.Name, pod.PodRef.Namespace))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rc *resourceMetricsCollector) collectContainerSwapMetrics(ch chan<- metrics.Metric, pod summary.PodStats, s summary.ContainerStats) {
|
||||||
|
if s.Swap == nil || s.Swap.SwapUsageBytes == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- metrics.NewLazyMetricWithTimestamp(s.Swap.Time.Time,
|
||||||
|
metrics.NewLazyConstMetric(containerSwapUsageDesc, metrics.GaugeValue,
|
||||||
|
float64(*s.Swap.SwapUsageBytes), s.Name, pod.PodRef.Name, pod.PodRef.Namespace))
|
||||||
|
}
|
||||||
|
|
||||||
func (rc *resourceMetricsCollector) collectPodCPUMetrics(ch chan<- metrics.Metric, pod summary.PodStats) {
|
func (rc *resourceMetricsCollector) collectPodCPUMetrics(ch chan<- metrics.Metric, pod summary.PodStats) {
|
||||||
if pod.CPU == nil || pod.CPU.UsageCoreNanoSeconds == nil {
|
if pod.CPU == nil || pod.CPU.UsageCoreNanoSeconds == nil {
|
||||||
return
|
return
|
||||||
@ -209,3 +255,13 @@ func (rc *resourceMetricsCollector) collectPodMemoryMetrics(ch chan<- metrics.Me
|
|||||||
metrics.NewLazyConstMetric(podMemoryUsageDesc, metrics.GaugeValue,
|
metrics.NewLazyConstMetric(podMemoryUsageDesc, metrics.GaugeValue,
|
||||||
float64(*pod.Memory.WorkingSetBytes), pod.PodRef.Name, pod.PodRef.Namespace))
|
float64(*pod.Memory.WorkingSetBytes), pod.PodRef.Name, pod.PodRef.Namespace))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (rc *resourceMetricsCollector) collectPodSwapMetrics(ch chan<- metrics.Metric, pod summary.PodStats) {
|
||||||
|
if pod.Swap == nil || pod.Swap.SwapUsageBytes == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ch <- metrics.NewLazyMetricWithTimestamp(pod.Swap.Time.Time,
|
||||||
|
metrics.NewLazyConstMetric(podSwapUsageDesc, metrics.GaugeValue,
|
||||||
|
float64(*pod.Swap.SwapUsageBytes), pod.PodRef.Name, pod.PodRef.Namespace))
|
||||||
|
}
|
||||||
|
@ -38,11 +38,14 @@ func TestCollectResourceMetrics(t *testing.T) {
|
|||||||
"scrape_error",
|
"scrape_error",
|
||||||
"node_cpu_usage_seconds_total",
|
"node_cpu_usage_seconds_total",
|
||||||
"node_memory_working_set_bytes",
|
"node_memory_working_set_bytes",
|
||||||
|
"node_swap_usage_bytes",
|
||||||
"container_cpu_usage_seconds_total",
|
"container_cpu_usage_seconds_total",
|
||||||
"container_memory_working_set_bytes",
|
"container_memory_working_set_bytes",
|
||||||
|
"container_swap_usage_bytes",
|
||||||
"container_start_time_seconds",
|
"container_start_time_seconds",
|
||||||
"pod_cpu_usage_seconds_total",
|
"pod_cpu_usage_seconds_total",
|
||||||
"pod_memory_working_set_bytes",
|
"pod_memory_working_set_bytes",
|
||||||
|
"pod_swap_usage_bytes",
|
||||||
}
|
}
|
||||||
mockCtrl := gomock.NewController(t)
|
mockCtrl := gomock.NewController(t)
|
||||||
defer mockCtrl.Finish()
|
defer mockCtrl.Finish()
|
||||||
@ -75,6 +78,10 @@ func TestCollectResourceMetrics(t *testing.T) {
|
|||||||
Time: testTime,
|
Time: testTime,
|
||||||
WorkingSetBytes: uint64Ptr(1000),
|
WorkingSetBytes: uint64Ptr(1000),
|
||||||
},
|
},
|
||||||
|
Swap: &statsapi.SwapStats{
|
||||||
|
Time: testTime,
|
||||||
|
SwapUsageBytes: uint64Ptr(500),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
summaryErr: nil,
|
summaryErr: nil,
|
||||||
@ -85,6 +92,9 @@ func TestCollectResourceMetrics(t *testing.T) {
|
|||||||
# HELP node_memory_working_set_bytes [ALPHA] Current working set of the node in bytes
|
# HELP node_memory_working_set_bytes [ALPHA] Current working set of the node in bytes
|
||||||
# TYPE node_memory_working_set_bytes gauge
|
# TYPE node_memory_working_set_bytes gauge
|
||||||
node_memory_working_set_bytes 1000 1624396278302
|
node_memory_working_set_bytes 1000 1624396278302
|
||||||
|
# HELP node_swap_usage_bytes [ALPHA] Current swap usage of the node in bytes. Reported only on non-windows systems
|
||||||
|
# TYPE node_swap_usage_bytes gauge
|
||||||
|
node_swap_usage_bytes 500 1624396278302
|
||||||
# HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
|
# HELP scrape_error [ALPHA] 1 if there was an error while getting container metrics, 0 otherwise
|
||||||
# TYPE scrape_error gauge
|
# TYPE scrape_error gauge
|
||||||
scrape_error 0
|
scrape_error 0
|
||||||
@ -132,6 +142,10 @@ func TestCollectResourceMetrics(t *testing.T) {
|
|||||||
Time: testTime,
|
Time: testTime,
|
||||||
WorkingSetBytes: uint64Ptr(1000),
|
WorkingSetBytes: uint64Ptr(1000),
|
||||||
},
|
},
|
||||||
|
Swap: &statsapi.SwapStats{
|
||||||
|
Time: testTime,
|
||||||
|
SwapUsageBytes: uint64Ptr(1000),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "container_b",
|
Name: "container_b",
|
||||||
@ -189,6 +203,9 @@ func TestCollectResourceMetrics(t *testing.T) {
|
|||||||
container_start_time_seconds{container="container_a",namespace="namespace_a",pod="pod_a"} 1.6243962483020916e+09 1624396248302
|
container_start_time_seconds{container="container_a",namespace="namespace_a",pod="pod_a"} 1.6243962483020916e+09 1624396248302
|
||||||
container_start_time_seconds{container="container_a",namespace="namespace_b",pod="pod_b"} 1.6243956783020916e+09 1624395678302
|
container_start_time_seconds{container="container_a",namespace="namespace_b",pod="pod_b"} 1.6243956783020916e+09 1624395678302
|
||||||
container_start_time_seconds{container="container_b",namespace="namespace_a",pod="pod_a"} 1.6243961583020916e+09 1624396158302
|
container_start_time_seconds{container="container_b",namespace="namespace_a",pod="pod_a"} 1.6243961583020916e+09 1624396158302
|
||||||
|
# HELP container_swap_usage_bytes [ALPHA] Current amount of the container swap usage in bytes. Reported only on non-windows systems
|
||||||
|
# TYPE container_swap_usage_bytes gauge
|
||||||
|
container_swap_usage_bytes{container="container_a",namespace="namespace_a",pod="pod_a"} 1000 1624396278302
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -310,6 +327,10 @@ func TestCollectResourceMetrics(t *testing.T) {
|
|||||||
Time: testTime,
|
Time: testTime,
|
||||||
WorkingSetBytes: uint64Ptr(1000),
|
WorkingSetBytes: uint64Ptr(1000),
|
||||||
},
|
},
|
||||||
|
Swap: &statsapi.SwapStats{
|
||||||
|
Time: testTime,
|
||||||
|
SwapUsageBytes: uint64Ptr(5000),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -324,6 +345,9 @@ func TestCollectResourceMetrics(t *testing.T) {
|
|||||||
# HELP pod_memory_working_set_bytes [ALPHA] Current working set of the pod in bytes
|
# HELP pod_memory_working_set_bytes [ALPHA] Current working set of the pod in bytes
|
||||||
# TYPE pod_memory_working_set_bytes gauge
|
# TYPE pod_memory_working_set_bytes gauge
|
||||||
pod_memory_working_set_bytes{namespace="namespace_a",pod="pod_a"} 1000 1624396278302
|
pod_memory_working_set_bytes{namespace="namespace_a",pod="pod_a"} 1000 1624396278302
|
||||||
|
# HELP pod_swap_usage_bytes [ALPHA] Current amount of the pod swap usage in bytes. Reported only on non-windows systems
|
||||||
|
# TYPE pod_swap_usage_bytes gauge
|
||||||
|
pod_swap_usage_bytes{namespace="namespace_a",pod="pod_a"} 5000 1624396278302
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -105,6 +105,7 @@ func (sp *summaryProviderImpl) Get(ctx context.Context, updateStats bool) (*stat
|
|||||||
NodeName: node.Name,
|
NodeName: node.Name,
|
||||||
CPU: rootStats.CPU,
|
CPU: rootStats.CPU,
|
||||||
Memory: rootStats.Memory,
|
Memory: rootStats.Memory,
|
||||||
|
Swap: rootStats.Swap,
|
||||||
Network: networkStats,
|
Network: networkStats,
|
||||||
StartTime: sp.systemBootTime,
|
StartTime: sp.systemBootTime,
|
||||||
Fs: rootFsStats,
|
Fs: rootFsStats,
|
||||||
@ -141,6 +142,7 @@ func (sp *summaryProviderImpl) GetCPUAndMemoryStats(ctx context.Context) (*stats
|
|||||||
NodeName: node.Name,
|
NodeName: node.Name,
|
||||||
CPU: rootStats.CPU,
|
CPU: rootStats.CPU,
|
||||||
Memory: rootStats.Memory,
|
Memory: rootStats.Memory,
|
||||||
|
Swap: rootStats.Swap,
|
||||||
StartTime: rootStats.StartTime,
|
StartTime: rootStats.StartTime,
|
||||||
SystemContainers: sp.GetSystemContainersCPUAndMemoryStats(nodeConfig, podStats, false),
|
SystemContainers: sp.GetSystemContainersCPUAndMemoryStats(nodeConfig, podStats, false),
|
||||||
}
|
}
|
||||||
|
@ -100,6 +100,7 @@ func TestSummaryProviderGetStats(t *testing.T) {
|
|||||||
assert.Equal(summary.Node.StartTime, systemBootTime)
|
assert.Equal(summary.Node.StartTime, systemBootTime)
|
||||||
assert.Equal(summary.Node.CPU, cgroupStatsMap["/"].cs.CPU)
|
assert.Equal(summary.Node.CPU, cgroupStatsMap["/"].cs.CPU)
|
||||||
assert.Equal(summary.Node.Memory, cgroupStatsMap["/"].cs.Memory)
|
assert.Equal(summary.Node.Memory, cgroupStatsMap["/"].cs.Memory)
|
||||||
|
assert.Equal(summary.Node.Swap, cgroupStatsMap["/"].cs.Swap)
|
||||||
assert.Equal(summary.Node.Network, cgroupStatsMap["/"].ns)
|
assert.Equal(summary.Node.Network, cgroupStatsMap["/"].ns)
|
||||||
assert.Equal(summary.Node.Fs, rootFsStats)
|
assert.Equal(summary.Node.Fs, rootFsStats)
|
||||||
assert.Equal(summary.Node.Runtime, &statsapi.RuntimeStats{ImageFs: imageFsStats})
|
assert.Equal(summary.Node.Runtime, &statsapi.RuntimeStats{ImageFs: imageFsStats})
|
||||||
@ -112,6 +113,7 @@ func TestSummaryProviderGetStats(t *testing.T) {
|
|||||||
Memory: cgroupStatsMap["/kubelet"].cs.Memory,
|
Memory: cgroupStatsMap["/kubelet"].cs.Memory,
|
||||||
Accelerators: cgroupStatsMap["/kubelet"].cs.Accelerators,
|
Accelerators: cgroupStatsMap["/kubelet"].cs.Accelerators,
|
||||||
UserDefinedMetrics: cgroupStatsMap["/kubelet"].cs.UserDefinedMetrics,
|
UserDefinedMetrics: cgroupStatsMap["/kubelet"].cs.UserDefinedMetrics,
|
||||||
|
Swap: cgroupStatsMap["/kubelet"].cs.Swap,
|
||||||
})
|
})
|
||||||
assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
|
assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
|
||||||
Name: "misc",
|
Name: "misc",
|
||||||
@ -120,6 +122,7 @@ func TestSummaryProviderGetStats(t *testing.T) {
|
|||||||
Memory: cgroupStatsMap["/misc"].cs.Memory,
|
Memory: cgroupStatsMap["/misc"].cs.Memory,
|
||||||
Accelerators: cgroupStatsMap["/misc"].cs.Accelerators,
|
Accelerators: cgroupStatsMap["/misc"].cs.Accelerators,
|
||||||
UserDefinedMetrics: cgroupStatsMap["/misc"].cs.UserDefinedMetrics,
|
UserDefinedMetrics: cgroupStatsMap["/misc"].cs.UserDefinedMetrics,
|
||||||
|
Swap: cgroupStatsMap["/misc"].cs.Swap,
|
||||||
})
|
})
|
||||||
assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
|
assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
|
||||||
Name: "runtime",
|
Name: "runtime",
|
||||||
@ -128,6 +131,7 @@ func TestSummaryProviderGetStats(t *testing.T) {
|
|||||||
Memory: cgroupStatsMap["/runtime"].cs.Memory,
|
Memory: cgroupStatsMap["/runtime"].cs.Memory,
|
||||||
Accelerators: cgroupStatsMap["/runtime"].cs.Accelerators,
|
Accelerators: cgroupStatsMap["/runtime"].cs.Accelerators,
|
||||||
UserDefinedMetrics: cgroupStatsMap["/runtime"].cs.UserDefinedMetrics,
|
UserDefinedMetrics: cgroupStatsMap["/runtime"].cs.UserDefinedMetrics,
|
||||||
|
Swap: cgroupStatsMap["/runtime"].cs.Swap,
|
||||||
})
|
})
|
||||||
assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
|
assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
|
||||||
Name: "pods",
|
Name: "pods",
|
||||||
@ -136,6 +140,7 @@ func TestSummaryProviderGetStats(t *testing.T) {
|
|||||||
Memory: cgroupStatsMap["/pods"].cs.Memory,
|
Memory: cgroupStatsMap["/pods"].cs.Memory,
|
||||||
Accelerators: cgroupStatsMap["/pods"].cs.Accelerators,
|
Accelerators: cgroupStatsMap["/pods"].cs.Accelerators,
|
||||||
UserDefinedMetrics: cgroupStatsMap["/pods"].cs.UserDefinedMetrics,
|
UserDefinedMetrics: cgroupStatsMap["/pods"].cs.UserDefinedMetrics,
|
||||||
|
Swap: cgroupStatsMap["/pods"].cs.Swap,
|
||||||
})
|
})
|
||||||
assert.Equal(summary.Pods, podStats)
|
assert.Equal(summary.Pods, podStats)
|
||||||
}
|
}
|
||||||
|
@ -152,6 +152,7 @@ func (p *cadvisorStatsProvider) ListPodStats(_ context.Context) ([]statsapi.PodS
|
|||||||
cpu, memory := cadvisorInfoToCPUandMemoryStats(podInfo)
|
cpu, memory := cadvisorInfoToCPUandMemoryStats(podInfo)
|
||||||
podStats.CPU = cpu
|
podStats.CPU = cpu
|
||||||
podStats.Memory = memory
|
podStats.Memory = memory
|
||||||
|
podStats.Swap = cadvisorInfoToSwapStats(podInfo)
|
||||||
podStats.ProcessStats = cadvisorInfoToProcessStats(podInfo)
|
podStats.ProcessStats = cadvisorInfoToProcessStats(podInfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -227,6 +228,7 @@ func (p *cadvisorStatsProvider) ListPodCPUAndMemoryStats(_ context.Context) ([]s
|
|||||||
cpu, memory := cadvisorInfoToCPUandMemoryStats(podInfo)
|
cpu, memory := cadvisorInfoToCPUandMemoryStats(podInfo)
|
||||||
podStats.CPU = cpu
|
podStats.CPU = cpu
|
||||||
podStats.Memory = memory
|
podStats.Memory = memory
|
||||||
|
podStats.Swap = cadvisorInfoToSwapStats(podInfo)
|
||||||
}
|
}
|
||||||
result = append(result, *podStats)
|
result = append(result, *podStats)
|
||||||
}
|
}
|
||||||
|
@ -294,11 +294,13 @@ func TestCadvisorListPodStats(t *testing.T) {
|
|||||||
assert.EqualValues(t, testTime(creationTime, seedPod0Container0).Unix(), con.StartTime.Time.Unix())
|
assert.EqualValues(t, testTime(creationTime, seedPod0Container0).Unix(), con.StartTime.Time.Unix())
|
||||||
checkCPUStats(t, "Pod0Container0", seedPod0Container0, con.CPU)
|
checkCPUStats(t, "Pod0Container0", seedPod0Container0, con.CPU)
|
||||||
checkMemoryStats(t, "Pod0Conainer0", seedPod0Container0, infos["/pod0-c0"], con.Memory)
|
checkMemoryStats(t, "Pod0Conainer0", seedPod0Container0, infos["/pod0-c0"], con.Memory)
|
||||||
|
checkSwapStats(t, "Pod0Conainer0", seedPod0Container0, infos["/pod0-c0"], con.Swap)
|
||||||
|
|
||||||
con = indexCon[cName01]
|
con = indexCon[cName01]
|
||||||
assert.EqualValues(t, testTime(creationTime, seedPod0Container1).Unix(), con.StartTime.Time.Unix())
|
assert.EqualValues(t, testTime(creationTime, seedPod0Container1).Unix(), con.StartTime.Time.Unix())
|
||||||
checkCPUStats(t, "Pod0Container1", seedPod0Container1, con.CPU)
|
checkCPUStats(t, "Pod0Container1", seedPod0Container1, con.CPU)
|
||||||
checkMemoryStats(t, "Pod0Container1", seedPod0Container1, infos["/pod0-c1"], con.Memory)
|
checkMemoryStats(t, "Pod0Container1", seedPod0Container1, infos["/pod0-c1"], con.Memory)
|
||||||
|
checkSwapStats(t, "Pod0Container1", seedPod0Container1, infos["/pod0-c1"], con.Swap)
|
||||||
|
|
||||||
assert.EqualValues(t, p0Time.Unix(), ps.StartTime.Time.Unix())
|
assert.EqualValues(t, p0Time.Unix(), ps.StartTime.Time.Unix())
|
||||||
checkNetworkStats(t, "Pod0", seedPod0Infra, ps.Network)
|
checkNetworkStats(t, "Pod0", seedPod0Infra, ps.Network)
|
||||||
@ -309,6 +311,9 @@ func TestCadvisorListPodStats(t *testing.T) {
|
|||||||
if ps.Memory != nil {
|
if ps.Memory != nil {
|
||||||
checkMemoryStats(t, "Pod0", seedPod0Infra, infos["/pod0-i"], ps.Memory)
|
checkMemoryStats(t, "Pod0", seedPod0Infra, infos["/pod0-i"], ps.Memory)
|
||||||
}
|
}
|
||||||
|
if ps.Swap != nil {
|
||||||
|
checkSwapStats(t, "Pod0", seedPod0Infra, infos["/pod0-i"], ps.Swap)
|
||||||
|
}
|
||||||
|
|
||||||
// Validate Pod1 Results
|
// Validate Pod1 Results
|
||||||
ps, found = indexPods[prf1]
|
ps, found = indexPods[prf1]
|
||||||
@ -318,6 +323,7 @@ func TestCadvisorListPodStats(t *testing.T) {
|
|||||||
assert.Equal(t, cName10, con.Name)
|
assert.Equal(t, cName10, con.Name)
|
||||||
checkCPUStats(t, "Pod1Container0", seedPod1Container, con.CPU)
|
checkCPUStats(t, "Pod1Container0", seedPod1Container, con.CPU)
|
||||||
checkMemoryStats(t, "Pod1Container0", seedPod1Container, infos["/pod1-c0"], con.Memory)
|
checkMemoryStats(t, "Pod1Container0", seedPod1Container, infos["/pod1-c0"], con.Memory)
|
||||||
|
checkSwapStats(t, "Pod1Container0", seedPod1Container, infos["/pod1-c0"], con.Swap)
|
||||||
checkNetworkStats(t, "Pod1", seedPod1Infra, ps.Network)
|
checkNetworkStats(t, "Pod1", seedPod1Infra, ps.Network)
|
||||||
|
|
||||||
// Validate Pod2 Results
|
// Validate Pod2 Results
|
||||||
@ -328,6 +334,7 @@ func TestCadvisorListPodStats(t *testing.T) {
|
|||||||
assert.Equal(t, cName20, con.Name)
|
assert.Equal(t, cName20, con.Name)
|
||||||
checkCPUStats(t, "Pod2Container0", seedPod2Container, con.CPU)
|
checkCPUStats(t, "Pod2Container0", seedPod2Container, con.CPU)
|
||||||
checkMemoryStats(t, "Pod2Container0", seedPod2Container, infos["/pod2-c0"], con.Memory)
|
checkMemoryStats(t, "Pod2Container0", seedPod2Container, infos["/pod2-c0"], con.Memory)
|
||||||
|
checkSwapStats(t, "Pod2Container0", seedPod2Container, infos["/pod2-c0"], con.Swap)
|
||||||
checkNetworkStats(t, "Pod2", seedPod2Infra, ps.Network)
|
checkNetworkStats(t, "Pod2", seedPod2Infra, ps.Network)
|
||||||
|
|
||||||
// Validate Pod3 Results
|
// Validate Pod3 Results
|
||||||
@ -344,6 +351,7 @@ func TestCadvisorListPodStats(t *testing.T) {
|
|||||||
assert.Equal(t, cName31, con.Name)
|
assert.Equal(t, cName31, con.Name)
|
||||||
checkCPUStats(t, "Pod3Container1", seedPod3Container1, con.CPU)
|
checkCPUStats(t, "Pod3Container1", seedPod3Container1, con.CPU)
|
||||||
checkMemoryStats(t, "Pod3Container1", seedPod3Container1, infos["/pod3-c1"], con.Memory)
|
checkMemoryStats(t, "Pod3Container1", seedPod3Container1, infos["/pod3-c1"], con.Memory)
|
||||||
|
checkSwapStats(t, "Pod3Container1", seedPod3Container1, infos["/pod3-c1"], con.Swap)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCadvisorListPodCPUAndMemoryStats(t *testing.T) {
|
func TestCadvisorListPodCPUAndMemoryStats(t *testing.T) {
|
||||||
|
@ -206,6 +206,7 @@ func (p *criStatsProvider) listPodStatsPartiallyFromCRI(ctx context.Context, upd
|
|||||||
cs := p.makeContainerStats(stats, container, rootFsInfo, fsIDtoInfo, podSandbox.GetMetadata(), updateCPUNanoCoreUsage)
|
cs := p.makeContainerStats(stats, container, rootFsInfo, fsIDtoInfo, podSandbox.GetMetadata(), updateCPUNanoCoreUsage)
|
||||||
p.addPodNetworkStats(ps, podSandboxID, caInfos, cs, containerNetworkStats[podSandboxID])
|
p.addPodNetworkStats(ps, podSandboxID, caInfos, cs, containerNetworkStats[podSandboxID])
|
||||||
p.addPodCPUMemoryStats(ps, types.UID(podSandbox.Metadata.Uid), allInfos, cs)
|
p.addPodCPUMemoryStats(ps, types.UID(podSandbox.Metadata.Uid), allInfos, cs)
|
||||||
|
p.addSwapStats(ps, types.UID(podSandbox.Metadata.Uid), allInfos, cs)
|
||||||
p.addProcessStats(ps, types.UID(podSandbox.Metadata.Uid), allInfos, cs)
|
p.addProcessStats(ps, types.UID(podSandbox.Metadata.Uid), allInfos, cs)
|
||||||
|
|
||||||
// If cadvisor stats is available for the container, use it to populate
|
// If cadvisor stats is available for the container, use it to populate
|
||||||
@ -548,6 +549,31 @@ func (p *criStatsProvider) addPodCPUMemoryStats(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *criStatsProvider) addSwapStats(
|
||||||
|
ps *statsapi.PodStats,
|
||||||
|
podUID types.UID,
|
||||||
|
allInfos map[string]cadvisorapiv2.ContainerInfo,
|
||||||
|
cs *statsapi.ContainerStats,
|
||||||
|
) {
|
||||||
|
// try get cpu and memory stats from cadvisor first.
|
||||||
|
podCgroupInfo := getCadvisorPodInfoFromPodUID(podUID, allInfos)
|
||||||
|
if podCgroupInfo != nil {
|
||||||
|
ps.Swap = cadvisorInfoToSwapStats(podCgroupInfo)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum Pod cpu and memory stats from containers stats.
|
||||||
|
if cs.Swap != nil {
|
||||||
|
if ps.Swap == nil {
|
||||||
|
ps.Swap = &statsapi.SwapStats{Time: cs.Swap.Time}
|
||||||
|
}
|
||||||
|
swapAvailableBytes := getUint64Value(cs.Swap.SwapAvailableBytes) + getUint64Value(ps.Swap.SwapAvailableBytes)
|
||||||
|
swapUsageBytes := getUint64Value(cs.Swap.SwapUsageBytes) + getUint64Value(ps.Swap.SwapUsageBytes)
|
||||||
|
ps.Swap.SwapAvailableBytes = &swapAvailableBytes
|
||||||
|
ps.Swap.SwapUsageBytes = &swapUsageBytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (p *criStatsProvider) addProcessStats(
|
func (p *criStatsProvider) addProcessStats(
|
||||||
ps *statsapi.PodStats,
|
ps *statsapi.PodStats,
|
||||||
podUID types.UID,
|
podUID types.UID,
|
||||||
@ -577,6 +603,7 @@ func (p *criStatsProvider) makeContainerStats(
|
|||||||
CPU: &statsapi.CPUStats{},
|
CPU: &statsapi.CPUStats{},
|
||||||
Memory: &statsapi.MemoryStats{},
|
Memory: &statsapi.MemoryStats{},
|
||||||
Rootfs: &statsapi.FsStats{},
|
Rootfs: &statsapi.FsStats{},
|
||||||
|
Swap: &statsapi.SwapStats{},
|
||||||
// UserDefinedMetrics is not supported by CRI.
|
// UserDefinedMetrics is not supported by CRI.
|
||||||
}
|
}
|
||||||
if stats.Cpu != nil {
|
if stats.Cpu != nil {
|
||||||
@ -607,6 +634,19 @@ func (p *criStatsProvider) makeContainerStats(
|
|||||||
result.Memory.Time = metav1.NewTime(time.Unix(0, time.Now().UnixNano()))
|
result.Memory.Time = metav1.NewTime(time.Unix(0, time.Now().UnixNano()))
|
||||||
result.Memory.WorkingSetBytes = uint64Ptr(0)
|
result.Memory.WorkingSetBytes = uint64Ptr(0)
|
||||||
}
|
}
|
||||||
|
if stats.Swap != nil {
|
||||||
|
result.Swap.Time = metav1.NewTime(time.Unix(0, stats.Swap.Timestamp))
|
||||||
|
if stats.Swap.SwapUsageBytes != nil {
|
||||||
|
result.Swap.SwapUsageBytes = &stats.Swap.SwapUsageBytes.Value
|
||||||
|
}
|
||||||
|
if stats.Swap.SwapAvailableBytes != nil {
|
||||||
|
result.Swap.SwapAvailableBytes = &stats.Swap.SwapAvailableBytes.Value
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result.Swap.Time = metav1.NewTime(time.Unix(0, time.Now().UnixNano()))
|
||||||
|
result.Swap.SwapUsageBytes = uint64Ptr(0)
|
||||||
|
result.Swap.SwapAvailableBytes = uint64Ptr(0)
|
||||||
|
}
|
||||||
if stats.WritableLayer != nil {
|
if stats.WritableLayer != nil {
|
||||||
result.Rootfs.Time = metav1.NewTime(time.Unix(0, stats.WritableLayer.Timestamp))
|
result.Rootfs.Time = metav1.NewTime(time.Unix(0, stats.WritableLayer.Timestamp))
|
||||||
if stats.WritableLayer.UsedBytes != nil {
|
if stats.WritableLayer.UsedBytes != nil {
|
||||||
|
@ -282,6 +282,7 @@ func TestCRIListPodStats(t *testing.T) {
|
|||||||
checkCRILogsStats(assert, c1, &rootFsInfo, containerLogStats1)
|
checkCRILogsStats(assert, c1, &rootFsInfo, containerLogStats1)
|
||||||
checkCRINetworkStats(assert, p0.Network, infos[sandbox0.PodSandboxStatus.Id].Stats[0].Network)
|
checkCRINetworkStats(assert, p0.Network, infos[sandbox0.PodSandboxStatus.Id].Stats[0].Network)
|
||||||
checkCRIPodCPUAndMemoryStats(assert, p0, infos[sandbox0Cgroup].Stats[0])
|
checkCRIPodCPUAndMemoryStats(assert, p0, infos[sandbox0Cgroup].Stats[0])
|
||||||
|
checkCRIPodSwapStats(assert, p0, infos[sandbox0Cgroup].Stats[0])
|
||||||
|
|
||||||
p1 := podStatsMap[statsapi.PodReference{Name: "sandbox1-name", UID: "sandbox1-uid", Namespace: "sandbox1-ns"}]
|
p1 := podStatsMap[statsapi.PodReference{Name: "sandbox1-name", UID: "sandbox1-uid", Namespace: "sandbox1-ns"}]
|
||||||
assert.Equal(sandbox1.CreatedAt, p1.StartTime.UnixNano())
|
assert.Equal(sandbox1.CreatedAt, p1.StartTime.UnixNano())
|
||||||
@ -298,6 +299,7 @@ func TestCRIListPodStats(t *testing.T) {
|
|||||||
checkCRILogsStats(assert, c2, &rootFsInfo, containerLogStats2)
|
checkCRILogsStats(assert, c2, &rootFsInfo, containerLogStats2)
|
||||||
checkCRINetworkStats(assert, p1.Network, infos[sandbox1.PodSandboxStatus.Id].Stats[0].Network)
|
checkCRINetworkStats(assert, p1.Network, infos[sandbox1.PodSandboxStatus.Id].Stats[0].Network)
|
||||||
checkCRIPodCPUAndMemoryStats(assert, p1, infos[sandbox1Cgroup].Stats[0])
|
checkCRIPodCPUAndMemoryStats(assert, p1, infos[sandbox1Cgroup].Stats[0])
|
||||||
|
checkCRIPodSwapStats(assert, p1, infos[sandbox1Cgroup].Stats[0])
|
||||||
|
|
||||||
p2 := podStatsMap[statsapi.PodReference{Name: "sandbox2-name", UID: "sandbox2-uid", Namespace: "sandbox2-ns"}]
|
p2 := podStatsMap[statsapi.PodReference{Name: "sandbox2-name", UID: "sandbox2-uid", Namespace: "sandbox2-ns"}]
|
||||||
assert.Equal(sandbox2.CreatedAt, p2.StartTime.UnixNano())
|
assert.Equal(sandbox2.CreatedAt, p2.StartTime.UnixNano())
|
||||||
@ -316,6 +318,7 @@ func TestCRIListPodStats(t *testing.T) {
|
|||||||
checkCRILogsStats(assert, c3, &rootFsInfo, containerLogStats4)
|
checkCRILogsStats(assert, c3, &rootFsInfo, containerLogStats4)
|
||||||
checkCRINetworkStats(assert, p2.Network, infos[sandbox2.PodSandboxStatus.Id].Stats[0].Network)
|
checkCRINetworkStats(assert, p2.Network, infos[sandbox2.PodSandboxStatus.Id].Stats[0].Network)
|
||||||
checkCRIPodCPUAndMemoryStats(assert, p2, infos[sandbox2Cgroup].Stats[0])
|
checkCRIPodCPUAndMemoryStats(assert, p2, infos[sandbox2Cgroup].Stats[0])
|
||||||
|
checkCRIPodSwapStats(assert, p2, infos[sandbox2Cgroup].Stats[0])
|
||||||
|
|
||||||
p3 := podStatsMap[statsapi.PodReference{Name: "sandbox3-name", UID: "sandbox3-uid", Namespace: "sandbox3-ns"}]
|
p3 := podStatsMap[statsapi.PodReference{Name: "sandbox3-name", UID: "sandbox3-uid", Namespace: "sandbox3-ns"}]
|
||||||
assert.Equal(sandbox3.CreatedAt, p3.StartTime.UnixNano())
|
assert.Equal(sandbox3.CreatedAt, p3.StartTime.UnixNano())
|
||||||
@ -327,6 +330,7 @@ func TestCRIListPodStats(t *testing.T) {
|
|||||||
assert.NotNil(c8.CPU.Time)
|
assert.NotNil(c8.CPU.Time)
|
||||||
assert.NotNil(c8.Memory.Time)
|
assert.NotNil(c8.Memory.Time)
|
||||||
checkCRIPodCPUAndMemoryStats(assert, p3, infos[sandbox3Cgroup].Stats[0])
|
checkCRIPodCPUAndMemoryStats(assert, p3, infos[sandbox3Cgroup].Stats[0])
|
||||||
|
checkCRIPodSwapStats(assert, p3, infos[sandbox3Cgroup].Stats[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestListPodStatsStrictlyFromCRI(t *testing.T) {
|
func TestListPodStatsStrictlyFromCRI(t *testing.T) {
|
||||||
@ -1074,6 +1078,15 @@ func checkCRIPodCPUAndMemoryStats(assert *assert.Assertions, actual statsapi.Pod
|
|||||||
assert.Equal(cs.Memory.ContainerData.Pgmajfault, *actual.Memory.MajorPageFaults)
|
assert.Equal(cs.Memory.ContainerData.Pgmajfault, *actual.Memory.MajorPageFaults)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkCRIPodSwapStats(assert *assert.Assertions, actual statsapi.PodStats, cs *cadvisorapiv2.ContainerStats) {
|
||||||
|
if runtime.GOOS != "linux" {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Equal(cs.Timestamp.UnixNano(), actual.Swap.Time.UnixNano())
|
||||||
|
assert.Equal(cs.Memory.Swap, *actual.Swap.SwapUsageBytes)
|
||||||
|
}
|
||||||
|
|
||||||
func checkCRIPodCPUAndMemoryStatsStrictlyFromCRI(assert *assert.Assertions, actual statsapi.PodStats, excepted statsapi.PodStats) {
|
func checkCRIPodCPUAndMemoryStatsStrictlyFromCRI(assert *assert.Assertions, actual statsapi.PodStats, excepted statsapi.PodStats) {
|
||||||
if runtime.GOOS != "linux" {
|
if runtime.GOOS != "linux" {
|
||||||
return
|
return
|
||||||
|
@ -95,6 +95,7 @@ func cadvisorInfoToContainerStats(name string, info *cadvisorapiv2.ContainerInfo
|
|||||||
cpu, memory := cadvisorInfoToCPUandMemoryStats(info)
|
cpu, memory := cadvisorInfoToCPUandMemoryStats(info)
|
||||||
result.CPU = cpu
|
result.CPU = cpu
|
||||||
result.Memory = memory
|
result.Memory = memory
|
||||||
|
result.Swap = cadvisorInfoToSwapStats(info)
|
||||||
|
|
||||||
// NOTE: if they can be found, log stats will be overwritten
|
// NOTE: if they can be found, log stats will be overwritten
|
||||||
// by the caller, as it knows more information about the pod,
|
// by the caller, as it knows more information about the pod,
|
||||||
@ -257,6 +258,29 @@ func cadvisorInfoToUserDefinedMetrics(info *cadvisorapiv2.ContainerInfo) []stats
|
|||||||
return udm
|
return udm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func cadvisorInfoToSwapStats(info *cadvisorapiv2.ContainerInfo) *statsapi.SwapStats {
|
||||||
|
cstat, found := latestContainerStats(info)
|
||||||
|
if !found {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var swapStats *statsapi.SwapStats
|
||||||
|
|
||||||
|
if info.Spec.HasMemory && cstat.Memory != nil {
|
||||||
|
swapStats = &statsapi.SwapStats{
|
||||||
|
Time: metav1.NewTime(cstat.Timestamp),
|
||||||
|
SwapUsageBytes: &cstat.Memory.Swap,
|
||||||
|
}
|
||||||
|
|
||||||
|
if !isMemoryUnlimited(info.Spec.Memory.SwapLimit) {
|
||||||
|
swapAvailableBytes := info.Spec.Memory.SwapLimit - cstat.Memory.Swap
|
||||||
|
swapStats.SwapAvailableBytes = &swapAvailableBytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return swapStats
|
||||||
|
}
|
||||||
|
|
||||||
// latestContainerStats returns the latest container stats from cadvisor, or nil if none exist
|
// latestContainerStats returns the latest container stats from cadvisor, or nil if none exist
|
||||||
func latestContainerStats(info *cadvisorapiv2.ContainerInfo) (*cadvisorapiv2.ContainerStats, bool) {
|
func latestContainerStats(info *cadvisorapiv2.ContainerInfo) (*cadvisorapiv2.ContainerStats, bool) {
|
||||||
stats := info.Stats
|
stats := info.Stats
|
||||||
|
@ -63,6 +63,7 @@ const (
|
|||||||
offsetFsBaseUsageBytes
|
offsetFsBaseUsageBytes
|
||||||
offsetFsInodeUsage
|
offsetFsInodeUsage
|
||||||
offsetAcceleratorDutyCycle
|
offsetAcceleratorDutyCycle
|
||||||
|
offsetMemSwapUsageBytes
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@ -101,6 +102,7 @@ func TestGetCgroupStats(t *testing.T) {
|
|||||||
checkCPUStats(t, "", containerInfoSeed, cs.CPU)
|
checkCPUStats(t, "", containerInfoSeed, cs.CPU)
|
||||||
checkMemoryStats(t, "", containerInfoSeed, containerInfo, cs.Memory)
|
checkMemoryStats(t, "", containerInfoSeed, containerInfo, cs.Memory)
|
||||||
checkNetworkStats(t, "", containerInfoSeed, ns)
|
checkNetworkStats(t, "", containerInfoSeed, ns)
|
||||||
|
checkSwapStats(t, "", containerInfoSeed, containerInfo, cs.Swap)
|
||||||
|
|
||||||
assert.Equal(cgroupName, cs.Name)
|
assert.Equal(cgroupName, cs.Name)
|
||||||
assert.Equal(metav1.NewTime(containerInfo.Spec.CreationTime), cs.StartTime)
|
assert.Equal(metav1.NewTime(containerInfo.Spec.CreationTime), cs.StartTime)
|
||||||
@ -498,6 +500,7 @@ func getTestContainerInfo(seed int, podName string, podNamespace string, contain
|
|||||||
Labels: labels,
|
Labels: labels,
|
||||||
Memory: cadvisorapiv2.MemorySpec{
|
Memory: cadvisorapiv2.MemorySpec{
|
||||||
Limit: unlimitedMemory,
|
Limit: unlimitedMemory,
|
||||||
|
SwapLimit: unlimitedMemory,
|
||||||
},
|
},
|
||||||
CustomMetrics: generateCustomMetricSpec(),
|
CustomMetrics: generateCustomMetricSpec(),
|
||||||
}
|
}
|
||||||
@ -518,6 +521,7 @@ func getTestContainerInfo(seed int, podName string, podNamespace string, contain
|
|||||||
Pgfault: uint64(seed + offsetMemPageFaults),
|
Pgfault: uint64(seed + offsetMemPageFaults),
|
||||||
Pgmajfault: uint64(seed + offsetMemMajorPageFaults),
|
Pgmajfault: uint64(seed + offsetMemMajorPageFaults),
|
||||||
},
|
},
|
||||||
|
Swap: uint64(seed + offsetMemSwapUsageBytes),
|
||||||
},
|
},
|
||||||
Network: &cadvisorapiv2.NetworkStats{
|
Network: &cadvisorapiv2.NetworkStats{
|
||||||
Interfaces: []cadvisorapiv1.InterfaceStats{{
|
Interfaces: []cadvisorapiv1.InterfaceStats{{
|
||||||
@ -696,6 +700,20 @@ func checkMemoryStats(t *testing.T, label string, seed int, info cadvisorapiv2.C
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func checkSwapStats(t *testing.T, label string, seed int, info cadvisorapiv2.ContainerInfo, stats *statsapi.SwapStats) {
|
||||||
|
label += ".Swap"
|
||||||
|
|
||||||
|
assert.EqualValues(t, testTime(timestamp, seed).Unix(), stats.Time.Time.Unix(), label+".Time")
|
||||||
|
assert.EqualValues(t, seed+offsetMemSwapUsageBytes, *stats.SwapUsageBytes, label+".SwapUsageBytes")
|
||||||
|
|
||||||
|
if !info.Spec.HasMemory || isMemoryUnlimited(info.Spec.Memory.SwapLimit) {
|
||||||
|
assert.Nil(t, stats.SwapAvailableBytes, label+".SwapAvailableBytes")
|
||||||
|
} else {
|
||||||
|
expected := info.Spec.Memory.Limit - *stats.SwapUsageBytes
|
||||||
|
assert.EqualValues(t, expected, *stats.SwapAvailableBytes, label+".AvailableBytes")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func checkFsStats(t *testing.T, label string, seed int, stats *statsapi.FsStats) {
|
func checkFsStats(t *testing.T, label string, seed int, stats *statsapi.FsStats) {
|
||||||
assert.EqualValues(t, seed+offsetFsCapacity, *stats.CapacityBytes, label+".CapacityBytes")
|
assert.EqualValues(t, seed+offsetFsCapacity, *stats.CapacityBytes, label+".CapacityBytes")
|
||||||
assert.EqualValues(t, seed+offsetFsAvailable, *stats.AvailableBytes, label+".AvailableBytes")
|
assert.EqualValues(t, seed+offsetFsAvailable, *stats.AvailableBytes, label+".AvailableBytes")
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1639,6 +1639,8 @@ message ContainerStats {
|
|||||||
MemoryUsage memory = 3;
|
MemoryUsage memory = 3;
|
||||||
// Usage of the writable layer.
|
// Usage of the writable layer.
|
||||||
FilesystemUsage writable_layer = 4;
|
FilesystemUsage writable_layer = 4;
|
||||||
|
// Swap usage gathered from the container.
|
||||||
|
SwapUsage swap = 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// WindowsContainerStats provides the resource usage statistics for a container specific for Windows
|
// WindowsContainerStats provides the resource usage statistics for a container specific for Windows
|
||||||
@ -1693,6 +1695,15 @@ message MemoryUsage {
|
|||||||
UInt64Value major_page_faults = 7;
|
UInt64Value major_page_faults = 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message SwapUsage {
|
||||||
|
// Timestamp in nanoseconds at which the information were collected. Must be > 0.
|
||||||
|
int64 timestamp = 1;
|
||||||
|
// Available swap for use. This is defined as the swap limit - swapUsageBytes.
|
||||||
|
UInt64Value swap_available_bytes = 2;
|
||||||
|
// Total memory in use. This includes all memory regardless of when it was accessed.
|
||||||
|
UInt64Value swap_usage_bytes = 3;
|
||||||
|
}
|
||||||
|
|
||||||
// WindowsMemoryUsage provides the memory usage information specific to Windows
|
// WindowsMemoryUsage provides the memory usage information specific to Windows
|
||||||
message WindowsMemoryUsage {
|
message WindowsMemoryUsage {
|
||||||
// Timestamp in nanoseconds at which the information were collected. Must be > 0.
|
// Timestamp in nanoseconds at which the information were collected. Must be > 0.
|
||||||
|
@ -59,6 +59,9 @@ type NodeStats struct {
|
|||||||
// Stats about the rlimit of system.
|
// Stats about the rlimit of system.
|
||||||
// +optional
|
// +optional
|
||||||
Rlimit *RlimitStats `json:"rlimit,omitempty"`
|
Rlimit *RlimitStats `json:"rlimit,omitempty"`
|
||||||
|
// Stats pertaining to swap resources. This is reported to non-windows systems only.
|
||||||
|
// +optional
|
||||||
|
Swap *SwapStats `json:"swap,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// RlimitStats are stats rlimit of OS.
|
// RlimitStats are stats rlimit of OS.
|
||||||
@ -131,6 +134,9 @@ type PodStats struct {
|
|||||||
// ProcessStats pertaining to processes.
|
// ProcessStats pertaining to processes.
|
||||||
// +optional
|
// +optional
|
||||||
ProcessStats *ProcessStats `json:"process_stats,omitempty"`
|
ProcessStats *ProcessStats `json:"process_stats,omitempty"`
|
||||||
|
// Stats pertaining to swap resources. This is reported to non-windows systems only.
|
||||||
|
// +optional
|
||||||
|
Swap *SwapStats `json:"swap,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ContainerStats holds container-level unprocessed sample stats.
|
// ContainerStats holds container-level unprocessed sample stats.
|
||||||
@ -159,6 +165,9 @@ type ContainerStats struct {
|
|||||||
// +patchMergeKey=name
|
// +patchMergeKey=name
|
||||||
// +patchStrategy=merge
|
// +patchStrategy=merge
|
||||||
UserDefinedMetrics []UserDefinedMetric `json:"userDefinedMetrics,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
|
UserDefinedMetrics []UserDefinedMetric `json:"userDefinedMetrics,omitempty" patchStrategy:"merge" patchMergeKey:"name"`
|
||||||
|
// Stats pertaining to swap resources. This is reported to non-windows systems only.
|
||||||
|
// +optional
|
||||||
|
Swap *SwapStats `json:"swap,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// PodReference contains enough information to locate the referenced pod.
|
// PodReference contains enough information to locate the referenced pod.
|
||||||
@ -237,6 +246,19 @@ type MemoryStats struct {
|
|||||||
MajorPageFaults *uint64 `json:"majorPageFaults,omitempty"`
|
MajorPageFaults *uint64 `json:"majorPageFaults,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SwapStats contains data about memory usage
|
||||||
|
type SwapStats struct {
|
||||||
|
// The time at which these stats were updated.
|
||||||
|
Time metav1.Time `json:"time"`
|
||||||
|
// Available swap memory for use. This is defined as the <swap-limit> - <current-swap-usage>.
|
||||||
|
// If swap limit is undefined, this value is omitted.
|
||||||
|
// +optional
|
||||||
|
SwapAvailableBytes *uint64 `json:"swapAvailableBytes,omitempty"`
|
||||||
|
// Total swap memory in use.
|
||||||
|
// +optional
|
||||||
|
SwapUsageBytes *uint64 `json:"swapUsageBytes,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
// AcceleratorStats contains stats for accelerators attached to the container.
|
// AcceleratorStats contains stats for accelerators attached to the container.
|
||||||
type AcceleratorStats struct {
|
type AcceleratorStats struct {
|
||||||
// Make of the accelerator (nvidia, amd, google etc.)
|
// Make of the accelerator (nvidia, amd, google etc.)
|
||||||
|
@ -112,6 +112,7 @@ var _ = SIGDescribe("Summary API [NodeConformance]", func() {
|
|||||||
"PageFaults": bounded(1000, 1e9),
|
"PageFaults": bounded(1000, 1e9),
|
||||||
"MajorPageFaults": bounded(0, 100000),
|
"MajorPageFaults": bounded(0, 100000),
|
||||||
}),
|
}),
|
||||||
|
"Swap": swapExpectation(memoryLimit),
|
||||||
"Accelerators": gomega.BeEmpty(),
|
"Accelerators": gomega.BeEmpty(),
|
||||||
"Rootfs": gomega.BeNil(),
|
"Rootfs": gomega.BeNil(),
|
||||||
"Logs": gomega.BeNil(),
|
"Logs": gomega.BeNil(),
|
||||||
@ -183,6 +184,7 @@ var _ = SIGDescribe("Summary API [NodeConformance]", func() {
|
|||||||
"PageFaults": bounded(100, expectedPageFaultsUpperBound),
|
"PageFaults": bounded(100, expectedPageFaultsUpperBound),
|
||||||
"MajorPageFaults": bounded(0, expectedMajorPageFaultsUpperBound),
|
"MajorPageFaults": bounded(0, expectedMajorPageFaultsUpperBound),
|
||||||
}),
|
}),
|
||||||
|
"Swap": swapExpectation(memoryLimit),
|
||||||
"Accelerators": gomega.BeEmpty(),
|
"Accelerators": gomega.BeEmpty(),
|
||||||
"Rootfs": ptrMatchAllFields(gstruct.Fields{
|
"Rootfs": ptrMatchAllFields(gstruct.Fields{
|
||||||
"Time": recent(maxStatsAge),
|
"Time": recent(maxStatsAge),
|
||||||
@ -230,6 +232,7 @@ var _ = SIGDescribe("Summary API [NodeConformance]", func() {
|
|||||||
"PageFaults": bounded(0, expectedPageFaultsUpperBound),
|
"PageFaults": bounded(0, expectedPageFaultsUpperBound),
|
||||||
"MajorPageFaults": bounded(0, expectedMajorPageFaultsUpperBound),
|
"MajorPageFaults": bounded(0, expectedMajorPageFaultsUpperBound),
|
||||||
}),
|
}),
|
||||||
|
"Swap": swapExpectation(memoryLimit),
|
||||||
"VolumeStats": gstruct.MatchAllElements(summaryObjectID, gstruct.Elements{
|
"VolumeStats": gstruct.MatchAllElements(summaryObjectID, gstruct.Elements{
|
||||||
"test-empty-dir": gstruct.MatchAllFields(gstruct.Fields{
|
"test-empty-dir": gstruct.MatchAllFields(gstruct.Fields{
|
||||||
"Name": gomega.Equal("test-empty-dir"),
|
"Name": gomega.Equal("test-empty-dir"),
|
||||||
@ -280,6 +283,7 @@ var _ = SIGDescribe("Summary API [NodeConformance]", func() {
|
|||||||
"PageFaults": bounded(1000, 1e9),
|
"PageFaults": bounded(1000, 1e9),
|
||||||
"MajorPageFaults": bounded(0, 100000),
|
"MajorPageFaults": bounded(0, 100000),
|
||||||
}),
|
}),
|
||||||
|
"Swap": swapExpectation(memoryLimit),
|
||||||
// TODO(#28407): Handle non-eth0 network interface names.
|
// TODO(#28407): Handle non-eth0 network interface names.
|
||||||
"Network": ptrMatchAllFields(gstruct.Fields{
|
"Network": ptrMatchAllFields(gstruct.Fields{
|
||||||
"Time": recent(maxStatsAge),
|
"Time": recent(maxStatsAge),
|
||||||
@ -410,6 +414,27 @@ func bounded(lower, upper interface{}) types.GomegaMatcher {
|
|||||||
gomega.BeNumerically("<=", upper)))
|
gomega.BeNumerically("<=", upper)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func swapExpectation(upper interface{}) types.GomegaMatcher {
|
||||||
|
// Size after which we consider memory to be "unlimited". This is not
|
||||||
|
// MaxInt64 due to rounding by the kernel.
|
||||||
|
const maxMemorySize = uint64(1 << 62)
|
||||||
|
|
||||||
|
swapBytesMatcher := gomega.Or(
|
||||||
|
gomega.BeNil(),
|
||||||
|
bounded(0, upper),
|
||||||
|
gstruct.PointTo(gomega.BeNumerically(">=", maxMemorySize)),
|
||||||
|
)
|
||||||
|
|
||||||
|
return gomega.Or(
|
||||||
|
gomega.BeNil(),
|
||||||
|
ptrMatchAllFields(gstruct.Fields{
|
||||||
|
"Time": recent(maxStatsAge),
|
||||||
|
"SwapUsageBytes": swapBytesMatcher,
|
||||||
|
"SwapAvailableBytes": swapBytesMatcher,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func recent(d time.Duration) types.GomegaMatcher {
|
func recent(d time.Duration) types.GomegaMatcher {
|
||||||
return gomega.WithTransform(func(t metav1.Time) time.Time {
|
return gomega.WithTransform(func(t metav1.Time) time.Time {
|
||||||
return t.Time
|
return t.Time
|
||||||
|
Loading…
Reference in New Issue
Block a user