Adding support for pod level resources in kubectl

1. Add support for pod level resources in kubectl
2. Reuse the existing method to describe container resources and generalize it to describe both pod and container level resources
This commit is contained in:
ndixita 2024-10-24 21:13:54 +00:00
parent 85488b5f10
commit 502e0f55c4
2 changed files with 80 additions and 7 deletions

View File

@ -838,6 +838,11 @@ func describePod(pod *corev1.Pod, events *corev1.EventList) (string, error) {
w.Write(LEVEL_0, "NominatedNodeName:\t%s\n", pod.Status.NominatedNodeName) w.Write(LEVEL_0, "NominatedNodeName:\t%s\n", pod.Status.NominatedNodeName)
} }
if pod.Spec.Resources != nil {
w.Write(LEVEL_0, "Resources:\n")
describeResources(pod.Spec.Resources, w, LEVEL_1)
}
if len(pod.Spec.InitContainers) > 0 { if len(pod.Spec.InitContainers) > 0 {
describeContainers("Init Containers", pod.Spec.InitContainers, pod.Status.InitContainerStatuses, EnvValueRetriever(pod), w, "") describeContainers("Init Containers", pod.Spec.InitContainers, pod.Status.InitContainerStatuses, EnvValueRetriever(pod), w, "")
} }
@ -1800,7 +1805,7 @@ func describeContainers(label string, containers []corev1.Container, containerSt
if ok { if ok {
describeContainerState(status, w) describeContainerState(status, w)
} }
describeContainerResource(container, w) describeResources(&container.Resources, w, LEVEL_2)
describeContainerProbe(container, w) describeContainerProbe(container, w)
if len(container.EnvFrom) > 0 { if len(container.EnvFrom) > 0 {
describeContainerEnvFrom(container, resolverFn, w) describeContainerEnvFrom(container, resolverFn, w)
@ -1886,22 +1891,25 @@ func describeContainerCommand(container corev1.Container, w PrefixWriter) {
} }
} }
func describeContainerResource(container corev1.Container, w PrefixWriter) { func describeResources(resources *corev1.ResourceRequirements, w PrefixWriter, level int) {
resources := container.Resources if resources == nil {
return
}
if len(resources.Limits) > 0 { if len(resources.Limits) > 0 {
w.Write(LEVEL_2, "Limits:\n") w.Write(level, "Limits:\n")
} }
for _, name := range SortedResourceNames(resources.Limits) { for _, name := range SortedResourceNames(resources.Limits) {
quantity := resources.Limits[name] quantity := resources.Limits[name]
w.Write(LEVEL_3, "%s:\t%s\n", name, quantity.String()) w.Write(level+1, "%s:\t%s\n", name, quantity.String())
} }
if len(resources.Requests) > 0 { if len(resources.Requests) > 0 {
w.Write(LEVEL_2, "Requests:\n") w.Write(level, "Requests:\n")
} }
for _, name := range SortedResourceNames(resources.Requests) { for _, name := range SortedResourceNames(resources.Requests) {
quantity := resources.Requests[name] quantity := resources.Requests[name]
w.Write(LEVEL_3, "%s:\t%s\n", name, quantity.String()) w.Write(level+1, "%s:\t%s\n", name, quantity.String())
} }
} }

View File

@ -1179,6 +1179,71 @@ func VerifyDatesInOrder(
} }
} }
func TestDescribeResources(t *testing.T) {
testCases := []struct {
resources *corev1.ResourceRequirements
expectedElements map[string]int
}{
{
resources: &corev1.ResourceRequirements{},
expectedElements: map[string]int{},
},
{
resources: &corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1000"),
corev1.ResourceMemory: resource.MustParse("100Mi"),
},
Limits: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1000"),
corev1.ResourceMemory: resource.MustParse("100Mi"),
},
},
expectedElements: map[string]int{"cpu": 2, "memory": 2, "Requests": 1, "Limits": 1, "1k": 2, "100Mi": 2},
},
{
resources: &corev1.ResourceRequirements{
Limits: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1000"),
corev1.ResourceMemory: resource.MustParse("100Mi"),
},
},
expectedElements: map[string]int{"cpu": 1, "memory": 1, "Limits": 1, "1k": 1, "100Mi": 1},
},
{
resources: &corev1.ResourceRequirements{
Requests: corev1.ResourceList{
corev1.ResourceCPU: resource.MustParse("1000"),
corev1.ResourceMemory: resource.MustParse("100Mi"),
},
},
expectedElements: map[string]int{"cpu": 1, "memory": 1, "Requests": 1, "1k": 1, "100Mi": 1},
},
}
for i, testCase := range testCases {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
out := new(bytes.Buffer)
writer := NewPrefixWriter(out)
describeResources(testCase.resources, writer, LEVEL_1)
output := out.String()
gotElements := make(map[string]int)
for key, val := range testCase.expectedElements {
count := strings.Count(output, key)
if count == 0 {
t.Errorf("expected to find %q in output: %q", val, output)
continue
}
gotElements[key] = count
}
if !reflect.DeepEqual(gotElements, testCase.expectedElements) {
t.Errorf("Expected %v, got %v in output string: %q", testCase.expectedElements, gotElements, output)
}
})
}
}
func TestDescribeContainers(t *testing.T) { func TestDescribeContainers(t *testing.T) {
trueVal := true trueVal := true
testCases := []struct { testCases := []struct {