Skip to content

Commit dbde606

Browse files
authored
[receiver/kubeletstats] Add resource getters (#26690)
**Description:** Add metadata map for pod and container requests and limits. Will be used to calculate new metrics in a future PR. **Link to tracking Issue:** <Issue number if applicable> #24905 **Testing:** <Describe what testing was performed and which tests were added.> added unit tests
1 parent 0e0e8f3 commit dbde606

File tree

2 files changed

+371
-1
lines changed

2 files changed

+371
-1
lines changed

receiver/kubeletstatsreceiver/internal/kubelet/metadata.go

+73-1
Original file line numberDiff line numberDiff line change
@@ -50,15 +50,87 @@ type Metadata struct {
5050
Labels map[MetadataLabel]bool
5151
PodsMetadata *v1.PodList
5252
DetailedPVCResourceSetter func(rb *metadata.ResourceBuilder, volCacheID, volumeClaim, namespace string) error
53+
podResources map[string]resources
54+
containerResources map[string]resources
55+
}
56+
57+
type resources struct {
58+
cpuRequest float64
59+
cpuLimit float64
60+
memoryRequest int64
61+
memoryLimit int64
62+
}
63+
64+
func getContainerResources(r *v1.ResourceRequirements) resources {
65+
if r == nil {
66+
return resources{}
67+
}
68+
69+
return resources{
70+
cpuRequest: r.Requests.Cpu().AsApproximateFloat64(),
71+
cpuLimit: r.Limits.Cpu().AsApproximateFloat64(),
72+
memoryRequest: r.Requests.Memory().Value(),
73+
memoryLimit: r.Limits.Memory().Value(),
74+
}
5375
}
5476

5577
func NewMetadata(labels []MetadataLabel, podsMetadata *v1.PodList,
5678
detailedPVCResourceSetter func(rb *metadata.ResourceBuilder, volCacheID, volumeClaim, namespace string) error) Metadata {
57-
return Metadata{
79+
m := Metadata{
5880
Labels: getLabelsMap(labels),
5981
PodsMetadata: podsMetadata,
6082
DetailedPVCResourceSetter: detailedPVCResourceSetter,
83+
podResources: make(map[string]resources, 0),
84+
containerResources: make(map[string]resources, 0),
85+
}
86+
87+
if podsMetadata != nil {
88+
for _, pod := range podsMetadata.Items {
89+
var podResource resources
90+
allContainersCPULimitsDefined := true
91+
allContainersCPURequestsDefined := true
92+
allContainersMemoryLimitsDefined := true
93+
allContainersMemoryRequestsDefined := true
94+
for _, container := range pod.Spec.Containers {
95+
containerResource := getContainerResources(&container.Resources)
96+
97+
if allContainersCPULimitsDefined && containerResource.cpuLimit == 0 {
98+
allContainersCPULimitsDefined = false
99+
podResource.cpuLimit = 0
100+
}
101+
if allContainersCPURequestsDefined && containerResource.cpuRequest == 0 {
102+
allContainersCPURequestsDefined = false
103+
podResource.cpuRequest = 0
104+
}
105+
if allContainersMemoryLimitsDefined && containerResource.memoryLimit == 0 {
106+
allContainersMemoryLimitsDefined = false
107+
podResource.memoryLimit = 0
108+
}
109+
if allContainersMemoryRequestsDefined && containerResource.memoryRequest == 0 {
110+
allContainersMemoryRequestsDefined = false
111+
podResource.memoryRequest = 0
112+
}
113+
114+
if allContainersCPULimitsDefined {
115+
podResource.cpuLimit += containerResource.cpuLimit
116+
}
117+
if allContainersCPURequestsDefined {
118+
podResource.cpuRequest += containerResource.cpuRequest
119+
}
120+
if allContainersMemoryLimitsDefined {
121+
podResource.memoryLimit += containerResource.memoryLimit
122+
}
123+
if allContainersMemoryRequestsDefined {
124+
podResource.memoryRequest += containerResource.memoryRequest
125+
}
126+
127+
m.containerResources[string(pod.UID)+container.Name] = containerResource
128+
}
129+
m.podResources[string(pod.UID)] = podResource
130+
}
61131
}
132+
133+
return m
62134
}
63135

64136
func getLabelsMap(metadataLabels []MetadataLabel) map[MetadataLabel]bool {

receiver/kubeletstatsreceiver/internal/kubelet/metadata_test.go

+298
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"github.com/stretchr/testify/assert"
1010
"github.com/stretchr/testify/require"
1111
v1 "k8s.io/api/core/v1"
12+
k8sresource "k8s.io/apimachinery/pkg/api/resource"
1213
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1314
stats "k8s.io/kubelet/pkg/apis/stats/v1alpha1"
1415

@@ -386,3 +387,300 @@ func TestSetExtraLabelsForVolumeTypes(t *testing.T) {
386387
})
387388
}
388389
}
390+
391+
// Test happy paths for volume type metadata.
392+
func TestCpuAndMemoryGetters(t *testing.T) {
393+
394+
tests := []struct {
395+
name string
396+
metadata Metadata
397+
podUID string
398+
containerName string
399+
wantPodCPULimit float64
400+
wantPodCPURequest float64
401+
wantContainerCPULimit float64
402+
wantContainerCPURequest float64
403+
wantPodMemoryLimit int64
404+
wantPodMemoryRequest int64
405+
wantContainerMemoryLimit int64
406+
wantContainerMemoryRequest int64
407+
}{
408+
{
409+
name: "no metadata",
410+
metadata: NewMetadata([]MetadataLabel{}, nil, nil),
411+
},
412+
{
413+
name: "pod happy path",
414+
metadata: NewMetadata([]MetadataLabel{}, &v1.PodList{
415+
Items: []v1.Pod{
416+
{
417+
ObjectMeta: metav1.ObjectMeta{
418+
UID: "uid-1234",
419+
},
420+
Spec: v1.PodSpec{
421+
Containers: []v1.Container{
422+
{
423+
Name: "container-1",
424+
Resources: v1.ResourceRequirements{
425+
Requests: v1.ResourceList{
426+
v1.ResourceCPU: k8sresource.MustParse("100m"),
427+
v1.ResourceMemory: k8sresource.MustParse("1G"),
428+
},
429+
Limits: v1.ResourceList{
430+
v1.ResourceCPU: k8sresource.MustParse("100m"),
431+
v1.ResourceMemory: k8sresource.MustParse("1G"),
432+
},
433+
},
434+
},
435+
{
436+
Name: "container-2",
437+
Resources: v1.ResourceRequirements{
438+
Requests: v1.ResourceList{
439+
v1.ResourceCPU: k8sresource.MustParse("2"),
440+
v1.ResourceMemory: k8sresource.MustParse("3G"),
441+
},
442+
Limits: v1.ResourceList{
443+
v1.ResourceCPU: k8sresource.MustParse("2"),
444+
v1.ResourceMemory: k8sresource.MustParse("3G"),
445+
},
446+
},
447+
},
448+
},
449+
},
450+
},
451+
},
452+
}, nil),
453+
podUID: "uid-1234",
454+
containerName: "container-2",
455+
wantPodCPULimit: 2.1,
456+
wantPodCPURequest: 2.1,
457+
wantContainerCPULimit: 2,
458+
wantContainerCPURequest: 2,
459+
wantPodMemoryLimit: 4000000000,
460+
wantPodMemoryRequest: 4000000000,
461+
wantContainerMemoryLimit: 3000000000,
462+
wantContainerMemoryRequest: 3000000000,
463+
},
464+
{
465+
name: "unknown pod",
466+
metadata: NewMetadata([]MetadataLabel{}, &v1.PodList{
467+
Items: []v1.Pod{
468+
{
469+
ObjectMeta: metav1.ObjectMeta{
470+
UID: "uid-1234",
471+
},
472+
Spec: v1.PodSpec{
473+
Containers: []v1.Container{
474+
{
475+
Name: "container-1",
476+
Resources: v1.ResourceRequirements{
477+
Requests: v1.ResourceList{
478+
v1.ResourceCPU: k8sresource.MustParse("1"),
479+
v1.ResourceMemory: k8sresource.MustParse("1G"),
480+
},
481+
Limits: v1.ResourceList{
482+
v1.ResourceCPU: k8sresource.MustParse("1"),
483+
v1.ResourceMemory: k8sresource.MustParse("1G"),
484+
},
485+
},
486+
},
487+
{
488+
Name: "container-2",
489+
Resources: v1.ResourceRequirements{
490+
Requests: v1.ResourceList{
491+
v1.ResourceCPU: k8sresource.MustParse("2"),
492+
v1.ResourceMemory: k8sresource.MustParse("3G"),
493+
},
494+
Limits: v1.ResourceList{
495+
v1.ResourceCPU: k8sresource.MustParse("2"),
496+
v1.ResourceMemory: k8sresource.MustParse("3G"),
497+
},
498+
},
499+
},
500+
},
501+
},
502+
},
503+
},
504+
}, nil),
505+
podUID: "uid-12345",
506+
},
507+
{
508+
name: "unknown container",
509+
metadata: NewMetadata([]MetadataLabel{}, &v1.PodList{
510+
Items: []v1.Pod{
511+
{
512+
ObjectMeta: metav1.ObjectMeta{
513+
UID: "uid-1234",
514+
},
515+
Spec: v1.PodSpec{
516+
Containers: []v1.Container{
517+
{
518+
Name: "container-1",
519+
Resources: v1.ResourceRequirements{
520+
Requests: v1.ResourceList{
521+
v1.ResourceCPU: k8sresource.MustParse("300m"),
522+
v1.ResourceMemory: k8sresource.MustParse("1G"),
523+
},
524+
Limits: v1.ResourceList{
525+
v1.ResourceCPU: k8sresource.MustParse("300m"),
526+
v1.ResourceMemory: k8sresource.MustParse("1G"),
527+
},
528+
},
529+
},
530+
{
531+
Name: "container-2",
532+
Resources: v1.ResourceRequirements{
533+
Requests: v1.ResourceList{
534+
v1.ResourceCPU: k8sresource.MustParse("400m"),
535+
v1.ResourceMemory: k8sresource.MustParse("3G"),
536+
},
537+
Limits: v1.ResourceList{
538+
v1.ResourceCPU: k8sresource.MustParse("400m"),
539+
v1.ResourceMemory: k8sresource.MustParse("3G"),
540+
},
541+
},
542+
},
543+
},
544+
},
545+
},
546+
},
547+
}, nil),
548+
podUID: "uid-1234",
549+
containerName: "container-3",
550+
wantPodCPULimit: 0.7,
551+
wantPodCPURequest: 0.7,
552+
wantPodMemoryLimit: 4000000000,
553+
wantPodMemoryRequest: 4000000000,
554+
},
555+
{
556+
name: "container limit not set",
557+
metadata: NewMetadata([]MetadataLabel{}, &v1.PodList{
558+
Items: []v1.Pod{
559+
{
560+
ObjectMeta: metav1.ObjectMeta{
561+
UID: "uid-1234",
562+
},
563+
Spec: v1.PodSpec{
564+
Containers: []v1.Container{
565+
{
566+
Name: "container-1",
567+
Resources: v1.ResourceRequirements{
568+
Requests: v1.ResourceList{
569+
v1.ResourceCPU: k8sresource.MustParse("1"),
570+
v1.ResourceMemory: k8sresource.MustParse("1G"),
571+
},
572+
},
573+
},
574+
{
575+
Name: "container-2",
576+
Resources: v1.ResourceRequirements{
577+
Requests: v1.ResourceList{
578+
v1.ResourceCPU: k8sresource.MustParse("1"),
579+
v1.ResourceMemory: k8sresource.MustParse("1G"),
580+
},
581+
},
582+
},
583+
},
584+
},
585+
},
586+
},
587+
}, nil),
588+
podUID: "uid-1234",
589+
containerName: "container-2",
590+
wantPodCPURequest: 2,
591+
wantContainerCPURequest: 1,
592+
wantPodMemoryRequest: 2000000000,
593+
wantContainerMemoryRequest: 1000000000,
594+
},
595+
{
596+
name: "container request not set",
597+
metadata: NewMetadata([]MetadataLabel{}, &v1.PodList{
598+
Items: []v1.Pod{
599+
{
600+
ObjectMeta: metav1.ObjectMeta{
601+
UID: "uid-1234",
602+
},
603+
Spec: v1.PodSpec{
604+
Containers: []v1.Container{
605+
{
606+
Name: "container-1",
607+
Resources: v1.ResourceRequirements{
608+
Limits: v1.ResourceList{
609+
v1.ResourceCPU: k8sresource.MustParse("1"),
610+
v1.ResourceMemory: k8sresource.MustParse("1G"),
611+
},
612+
},
613+
},
614+
{
615+
Name: "container-2",
616+
Resources: v1.ResourceRequirements{
617+
Limits: v1.ResourceList{
618+
v1.ResourceCPU: k8sresource.MustParse("1"),
619+
v1.ResourceMemory: k8sresource.MustParse("1G"),
620+
},
621+
},
622+
},
623+
},
624+
},
625+
},
626+
},
627+
}, nil),
628+
podUID: "uid-1234",
629+
containerName: "container-2",
630+
wantPodCPULimit: 2,
631+
wantContainerCPULimit: 1,
632+
wantPodMemoryLimit: 2000000000,
633+
wantContainerMemoryLimit: 1000000000,
634+
},
635+
{
636+
name: "container limit not set but other is",
637+
metadata: NewMetadata([]MetadataLabel{}, &v1.PodList{
638+
Items: []v1.Pod{
639+
{
640+
ObjectMeta: metav1.ObjectMeta{
641+
UID: "uid-1234",
642+
},
643+
Spec: v1.PodSpec{
644+
Containers: []v1.Container{
645+
{
646+
Name: "container-1",
647+
Resources: v1.ResourceRequirements{
648+
Requests: v1.ResourceList{
649+
v1.ResourceCPU: k8sresource.MustParse("1"),
650+
v1.ResourceMemory: k8sresource.MustParse("1G"),
651+
},
652+
Limits: v1.ResourceList{
653+
v1.ResourceCPU: k8sresource.MustParse("1"),
654+
v1.ResourceMemory: k8sresource.MustParse("1G"),
655+
},
656+
},
657+
},
658+
{
659+
Name: "container-2",
660+
},
661+
},
662+
},
663+
},
664+
},
665+
}, nil),
666+
podUID: "uid-1234",
667+
containerName: "container-1",
668+
wantContainerCPULimit: 1,
669+
wantContainerCPURequest: 1,
670+
wantContainerMemoryLimit: 1000000000,
671+
wantContainerMemoryRequest: 1000000000,
672+
},
673+
}
674+
for _, tt := range tests {
675+
t.Run(tt.name, func(t *testing.T) {
676+
require.Equal(t, tt.wantPodCPULimit, tt.metadata.podResources[tt.podUID].cpuLimit)
677+
require.Equal(t, tt.wantPodCPURequest, tt.metadata.podResources[tt.podUID].cpuRequest)
678+
require.Equal(t, tt.wantContainerCPULimit, tt.metadata.containerResources[tt.podUID+tt.containerName].cpuLimit)
679+
require.Equal(t, tt.wantContainerCPURequest, tt.metadata.containerResources[tt.podUID+tt.containerName].cpuRequest)
680+
require.Equal(t, tt.wantPodMemoryLimit, tt.metadata.podResources[tt.podUID].memoryLimit)
681+
require.Equal(t, tt.wantPodMemoryRequest, tt.metadata.podResources[tt.podUID].memoryRequest)
682+
require.Equal(t, tt.wantContainerMemoryLimit, tt.metadata.containerResources[tt.podUID+tt.containerName].memoryLimit)
683+
require.Equal(t, tt.wantContainerMemoryRequest, tt.metadata.containerResources[tt.podUID+tt.containerName].memoryRequest)
684+
})
685+
}
686+
}

0 commit comments

Comments
 (0)