mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-08-03 17:30:00 +00:00
Add "only_cpu_and_memory" GET parameter to /stats/summary http handler in kubelet. If parameter is true then only cpu and memory will be present in response. The parameter will be used by Metric Server to avoid sending/decoding unneeded data.
This commit is contained in:
parent
9dba077d02
commit
138a3c7172
@ -1011,6 +1011,10 @@ func (f *fakeSummaryProvider) Get(updateStats bool) (*statsapi.Summary, error) {
|
|||||||
return f.result, nil
|
return f.result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *fakeSummaryProvider) GetCPUAndMemoryStats() (*statsapi.Summary, error) {
|
||||||
|
return f.result, nil
|
||||||
|
}
|
||||||
|
|
||||||
// newPodStats returns a pod stat where each container is using the specified working set
|
// newPodStats returns a pod stat where each container is using the specified working set
|
||||||
// each pod must have a Name, UID, Namespace
|
// each pod must have a Name, UID, Namespace
|
||||||
func newPodStats(pod *v1.Pod, containerWorkingSetBytes int64) statsapi.PodStats {
|
func newPodStats(pod *v1.Pod, containerWorkingSetBytes int64) statsapi.PodStats {
|
||||||
|
@ -192,10 +192,23 @@ func (h *handler) handleStats(request *restful.Request, response *restful.Respon
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Handles stats summary requests to /stats/summary
|
// Handles stats summary requests to /stats/summary
|
||||||
|
// If "only_cpu_and_memory" GET param is true then only cpu and memory is returned in response.
|
||||||
func (h *handler) handleSummary(request *restful.Request, response *restful.Response) {
|
func (h *handler) handleSummary(request *restful.Request, response *restful.Response) {
|
||||||
// external calls to the summary API use cached stats
|
onlyCPUAndMemory := false
|
||||||
forceStatsUpdate := false
|
request.Request.ParseForm()
|
||||||
summary, err := h.summaryProvider.Get(forceStatsUpdate)
|
if onlyCluAndMemoryParam, found := request.Request.Form["only_cpu_and_memory"]; found &&
|
||||||
|
len(onlyCluAndMemoryParam) == 1 && onlyCluAndMemoryParam[0] == "true" {
|
||||||
|
onlyCPUAndMemory = true
|
||||||
|
}
|
||||||
|
var summary *statsapi.Summary
|
||||||
|
var err error
|
||||||
|
if onlyCPUAndMemory {
|
||||||
|
summary, err = h.summaryProvider.GetCPUAndMemoryStats()
|
||||||
|
} else {
|
||||||
|
// external calls to the summary API use cached stats
|
||||||
|
forceStatsUpdate := false
|
||||||
|
summary, err = h.summaryProvider.Get(forceStatsUpdate)
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
handleError(response, "/stats/summary", err)
|
handleError(response, "/stats/summary", err)
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,6 +26,8 @@ type SummaryProvider interface {
|
|||||||
// Get provides a new Summary with the stats from Kubelet,
|
// Get provides a new Summary with the stats from Kubelet,
|
||||||
// and will update some stats if updateStats is true
|
// and will update some stats if updateStats is true
|
||||||
Get(updateStats bool) (*statsapi.Summary, error)
|
Get(updateStats bool) (*statsapi.Summary, error)
|
||||||
|
// GetCPUAndMemoryStats provides a new Summary with the CPU and memory stats from Kubelet,
|
||||||
|
GetCPUAndMemoryStats() (*statsapi.Summary, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// summaryProviderImpl implements the SummaryProvider interface.
|
// summaryProviderImpl implements the SummaryProvider interface.
|
||||||
@ -87,3 +89,32 @@ func (sp *summaryProviderImpl) Get(updateStats bool) (*statsapi.Summary, error)
|
|||||||
}
|
}
|
||||||
return &summary, nil
|
return &summary, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (sp *summaryProviderImpl) GetCPUAndMemoryStats() (*statsapi.Summary, error) {
|
||||||
|
summary, err := sp.Get(false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
summary.Node.Network = nil
|
||||||
|
summary.Node.Fs = nil
|
||||||
|
summary.Node.Runtime = nil
|
||||||
|
summary.Node.Rlimit = nil
|
||||||
|
for i := 0; i < len(summary.Node.SystemContainers); i++ {
|
||||||
|
summary.Node.SystemContainers[i].Accelerators = nil
|
||||||
|
summary.Node.SystemContainers[i].Rootfs = nil
|
||||||
|
summary.Node.SystemContainers[i].Logs = nil
|
||||||
|
summary.Node.SystemContainers[i].UserDefinedMetrics = nil
|
||||||
|
}
|
||||||
|
for i := 0; i < len(summary.Pods); i++ {
|
||||||
|
summary.Pods[i].Network = nil
|
||||||
|
summary.Pods[i].VolumeStats = nil
|
||||||
|
summary.Pods[i].EphemeralStorage = nil
|
||||||
|
for j := 0; j < len(summary.Pods[i].Containers); j++ {
|
||||||
|
summary.Pods[i].Containers[j].Accelerators = nil
|
||||||
|
summary.Pods[i].Containers[j].Rootfs = nil
|
||||||
|
summary.Pods[i].Containers[j].Logs = nil
|
||||||
|
summary.Pods[i].Containers[j].UserDefinedMetrics = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return summary, nil
|
||||||
|
}
|
||||||
|
@ -32,39 +32,39 @@ import (
|
|||||||
statstest "k8s.io/kubernetes/pkg/kubelet/server/stats/testing"
|
statstest "k8s.io/kubernetes/pkg/kubelet/server/stats/testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestSummaryProvider(t *testing.T) {
|
var (
|
||||||
var (
|
podStats = []statsapi.PodStats{
|
||||||
podStats = []statsapi.PodStats{
|
{
|
||||||
{
|
PodRef: statsapi.PodReference{Name: "test-pod", Namespace: "test-namespace", UID: "UID_test-pod"},
|
||||||
PodRef: statsapi.PodReference{Name: "test-pod", Namespace: "test-namespace", UID: "UID_test-pod"},
|
StartTime: metav1.NewTime(time.Now()),
|
||||||
StartTime: metav1.NewTime(time.Now()),
|
Containers: []statsapi.ContainerStats{*getContainerStats()},
|
||||||
Containers: []statsapi.ContainerStats{*getContainerStats()},
|
Network: getNetworkStats(),
|
||||||
Network: getNetworkStats(),
|
VolumeStats: []statsapi.VolumeStats{*getVolumeStats()},
|
||||||
VolumeStats: []statsapi.VolumeStats{*getVolumeStats()},
|
},
|
||||||
},
|
}
|
||||||
}
|
imageFsStats = getFsStats()
|
||||||
imageFsStats = getFsStats()
|
rootFsStats = getFsStats()
|
||||||
rootFsStats = getFsStats()
|
node = &v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "test-node"}}
|
||||||
node = &v1.Node{ObjectMeta: metav1.ObjectMeta{Name: "test-node"}}
|
nodeConfig = cm.NodeConfig{
|
||||||
nodeConfig = cm.NodeConfig{
|
RuntimeCgroupsName: "/runtime",
|
||||||
RuntimeCgroupsName: "/runtime",
|
SystemCgroupsName: "/misc",
|
||||||
SystemCgroupsName: "/misc",
|
KubeletCgroupsName: "/kubelet",
|
||||||
KubeletCgroupsName: "/kubelet",
|
}
|
||||||
}
|
cgroupRoot = "/kubepods"
|
||||||
cgroupRoot = "/kubepods"
|
cgroupStatsMap = map[string]struct {
|
||||||
cgroupStatsMap = map[string]struct {
|
cs *statsapi.ContainerStats
|
||||||
cs *statsapi.ContainerStats
|
ns *statsapi.NetworkStats
|
||||||
ns *statsapi.NetworkStats
|
}{
|
||||||
}{
|
"/": {cs: getContainerStats(), ns: getNetworkStats()},
|
||||||
"/": {cs: getContainerStats(), ns: getNetworkStats()},
|
"/runtime": {cs: getContainerStats(), ns: getNetworkStats()},
|
||||||
"/runtime": {cs: getContainerStats(), ns: getNetworkStats()},
|
"/misc": {cs: getContainerStats(), ns: getNetworkStats()},
|
||||||
"/misc": {cs: getContainerStats(), ns: getNetworkStats()},
|
"/kubelet": {cs: getContainerStats(), ns: getNetworkStats()},
|
||||||
"/kubelet": {cs: getContainerStats(), ns: getNetworkStats()},
|
"/pods": {cs: getContainerStats(), ns: getNetworkStats()},
|
||||||
"/pods": {cs: getContainerStats(), ns: getNetworkStats()},
|
}
|
||||||
}
|
rlimitStats = getRlimitStats()
|
||||||
rlimitStats = getRlimitStats()
|
)
|
||||||
)
|
|
||||||
|
|
||||||
|
func TestSummaryProviderGetStats(t *testing.T) {
|
||||||
assert := assert.New(t)
|
assert := assert.New(t)
|
||||||
|
|
||||||
mockStatsProvider := new(statstest.StatsProvider)
|
mockStatsProvider := new(statstest.StatsProvider)
|
||||||
@ -130,6 +130,64 @@ func TestSummaryProvider(t *testing.T) {
|
|||||||
assert.Equal(summary.Pods, podStats)
|
assert.Equal(summary.Pods, podStats)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSummaryProviderGetCPUAndMemoryStats(t *testing.T) {
|
||||||
|
assert := assert.New(t)
|
||||||
|
|
||||||
|
mockStatsProvider := new(statstest.StatsProvider)
|
||||||
|
mockStatsProvider.
|
||||||
|
On("GetNode").Return(node, nil).
|
||||||
|
On("GetNodeConfig").Return(nodeConfig).
|
||||||
|
On("GetPodCgroupRoot").Return(cgroupRoot).
|
||||||
|
On("ListPodStats").Return(podStats, nil).
|
||||||
|
On("ImageFsStats").Return(imageFsStats, nil).
|
||||||
|
On("RootFsStats").Return(rootFsStats, nil).
|
||||||
|
On("RlimitStats").Return(rlimitStats, nil).
|
||||||
|
On("GetCgroupStats", "/", false).Return(cgroupStatsMap["/"].cs, cgroupStatsMap["/"].ns, nil).
|
||||||
|
On("GetCgroupStats", "/runtime", false).Return(cgroupStatsMap["/runtime"].cs, cgroupStatsMap["/runtime"].ns, nil).
|
||||||
|
On("GetCgroupStats", "/misc", false).Return(cgroupStatsMap["/misc"].cs, cgroupStatsMap["/misc"].ns, nil).
|
||||||
|
On("GetCgroupStats", "/kubelet", false).Return(cgroupStatsMap["/kubelet"].cs, cgroupStatsMap["/kubelet"].ns, nil).
|
||||||
|
On("GetCgroupStats", "/kubepods", false).Return(cgroupStatsMap["/pods"].cs, cgroupStatsMap["/pods"].ns, nil)
|
||||||
|
|
||||||
|
provider := NewSummaryProvider(mockStatsProvider)
|
||||||
|
summary, err := provider.GetCPUAndMemoryStats()
|
||||||
|
assert.NoError(err)
|
||||||
|
|
||||||
|
assert.Equal(summary.Node.NodeName, "test-node")
|
||||||
|
assert.Equal(summary.Node.StartTime, cgroupStatsMap["/"].cs.StartTime)
|
||||||
|
assert.Equal(summary.Node.CPU, cgroupStatsMap["/"].cs.CPU)
|
||||||
|
assert.Equal(summary.Node.Memory, cgroupStatsMap["/"].cs.Memory)
|
||||||
|
assert.Nil(summary.Node.Network)
|
||||||
|
assert.Nil(summary.Node.Fs)
|
||||||
|
assert.Nil(summary.Node.Runtime)
|
||||||
|
|
||||||
|
assert.Equal(len(summary.Node.SystemContainers), 4)
|
||||||
|
assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
|
||||||
|
Name: "kubelet",
|
||||||
|
StartTime: cgroupStatsMap["/kubelet"].cs.StartTime,
|
||||||
|
CPU: cgroupStatsMap["/kubelet"].cs.CPU,
|
||||||
|
Memory: cgroupStatsMap["/kubelet"].cs.Memory,
|
||||||
|
})
|
||||||
|
assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
|
||||||
|
Name: "misc",
|
||||||
|
StartTime: cgroupStatsMap["/misc"].cs.StartTime,
|
||||||
|
CPU: cgroupStatsMap["/misc"].cs.CPU,
|
||||||
|
Memory: cgroupStatsMap["/misc"].cs.Memory,
|
||||||
|
})
|
||||||
|
assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
|
||||||
|
Name: "runtime",
|
||||||
|
StartTime: cgroupStatsMap["/runtime"].cs.StartTime,
|
||||||
|
CPU: cgroupStatsMap["/runtime"].cs.CPU,
|
||||||
|
Memory: cgroupStatsMap["/runtime"].cs.Memory,
|
||||||
|
})
|
||||||
|
assert.Contains(summary.Node.SystemContainers, statsapi.ContainerStats{
|
||||||
|
Name: "pods",
|
||||||
|
StartTime: cgroupStatsMap["/pods"].cs.StartTime,
|
||||||
|
CPU: cgroupStatsMap["/pods"].cs.CPU,
|
||||||
|
Memory: cgroupStatsMap["/pods"].cs.Memory,
|
||||||
|
})
|
||||||
|
assert.Equal(summary.Pods, podStats)
|
||||||
|
}
|
||||||
|
|
||||||
func getFsStats() *statsapi.FsStats {
|
func getFsStats() *statsapi.FsStats {
|
||||||
f := fuzz.New().NilChance(0)
|
f := fuzz.New().NilChance(0)
|
||||||
v := &statsapi.FsStats{}
|
v := &statsapi.FsStats{}
|
||||||
|
@ -634,8 +634,9 @@ type fakeResourceAnalyzer struct {
|
|||||||
podVolumeStats serverstats.PodVolumeStats
|
podVolumeStats serverstats.PodVolumeStats
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *fakeResourceAnalyzer) Start() {}
|
func (o *fakeResourceAnalyzer) Start() {}
|
||||||
func (o *fakeResourceAnalyzer) Get(bool) (*statsapi.Summary, error) { return nil, nil }
|
func (o *fakeResourceAnalyzer) Get(bool) (*statsapi.Summary, error) { return nil, nil }
|
||||||
|
func (o *fakeResourceAnalyzer) GetCPUAndMemoryStats() (*statsapi.Summary, error) { return nil, nil }
|
||||||
func (o *fakeResourceAnalyzer) GetPodVolumeStats(uid types.UID) (serverstats.PodVolumeStats, bool) {
|
func (o *fakeResourceAnalyzer) GetPodVolumeStats(uid types.UID) (serverstats.PodVolumeStats, bool) {
|
||||||
return o.podVolumeStats, true
|
return o.podVolumeStats, true
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user