From 576d1ff139c05b12877b7e5ad81c46faba57f8c4 Mon Sep 17 00:00:00 2001 From: adarsh0728 Date: Fri, 15 Nov 2024 21:57:28 +0530 Subject: [PATCH 1/2] fix: add decimal precision to CPU and memory metrics in pod info Signed-off-by: adarsh0728 --- server/apis/v1/handler.go | 29 ++++++++++--- server/apis/v1/handler_test.go | 43 ++++++++++++++----- .../partials/ContainerInfo/index.tsx | 2 +- 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/server/apis/v1/handler.go b/server/apis/v1/handler.go index 20b77f915..6046b1e83 100644 --- a/server/apis/v1/handler.go +++ b/server/apis/v1/handler.go @@ -1573,6 +1573,25 @@ func (h *handler) getMonoVertexDaemonClient(ns, mvtName string) (mvtdaemonclient } } +func formatCPU(quantityStr string) string { + var value float64 + var format string + _, err := fmt.Sscanf(quantityStr, "%f%s", &value, &format) + if err != nil { + fmt.Println("Error parsing cpu quantity string:", err) + return "0m" + } else { + if strings.HasSuffix(format, "n") { + value /= 1e6 + } else if !strings.HasSuffix(format, "m") { // Handle cases where the format is not "m" + fmt.Println("Error parsing quantity string: invalid format") + return "0m" + } + cpuInMillicores := value + return fmt.Sprintf("%.2fm", cpuInMillicores) + } +} + func (h *handler) getPodDetails(pod corev1.Pod) (PodDetails, error) { podDetails := PodDetails{ Name: pod.Name, @@ -1598,24 +1617,24 @@ func (h *handler) getPodDetails(pod corev1.Pod) (PodDetails, error) { memQuantity := container.Usage.Memory() details, ok := containerDetails[containerName] if !ok { - details = ContainerDetails{Name: container.Name} // Initialize if not found + details = ContainerDetails{Name: container.Name} } if cpuQuantity != nil { - details.TotalCPU = strconv.FormatInt(cpuQuantity.MilliValue(), 10) + "m" + details.TotalCPU = formatCPU(cpuQuantity.String()) totalCPU.Add(*cpuQuantity) } if memQuantity != nil { - details.TotalMemory = strconv.FormatInt(memQuantity.Value()/(1024*1024), 10) + "Mi" + details.TotalMemory = fmt.Sprintf("%.2fMi", float64(memQuantity.Value())/(1024*1024)) totalMemory.Add(*memQuantity) } containerDetails[containerName] = details } if totalCPU != nil { - podDetails.TotalCPU = strconv.FormatInt(totalCPU.MilliValue(), 10) + "m" + podDetails.TotalCPU = formatCPU(totalCPU.String()) } if totalMemory != nil { - podDetails.TotalMemory = strconv.FormatInt(totalMemory.Value()/(1024*1024), 10) + "Mi" + podDetails.TotalMemory = fmt.Sprintf("%.2fMi", float64(totalMemory.Value())/(1024*1024)) } } return podDetails, nil diff --git a/server/apis/v1/handler_test.go b/server/apis/v1/handler_test.go index aeae24d8a..c1da66420 100644 --- a/server/apis/v1/handler_test.go +++ b/server/apis/v1/handler_test.go @@ -464,8 +464,8 @@ func TestHandler_GetMonoVertexPodsInfo(t *testing.T) { if len(podInfos) > 0 { assert.Equal(t, "test-pod-1", podInfos[0].Name) assert.Equal(t, string(corev1.PodRunning), podInfos[0].Status) - assert.Equal(t, "150m", podInfos[0].TotalCPU) - assert.Equal(t, "150Mi", podInfos[0].TotalMemory) + assert.Equal(t, "150.00m", podInfos[0].TotalCPU) + assert.Equal(t, "150.00Mi", podInfos[0].TotalMemory) } } }) @@ -662,8 +662,8 @@ func TestHandler_GetVertexPodsInfo(t *testing.T) { assert.Len(t, podInfos, 1) assert.Equal(t, "test-pod-1", podInfos[0].Name) assert.Equal(t, string(corev1.PodRunning), podInfos[0].Status) - assert.Equal(t, "150m", podInfos[0].TotalCPU) - assert.Equal(t, "150Mi", podInfos[0].TotalMemory) + assert.Equal(t, "150.00m", podInfos[0].TotalCPU) + assert.Equal(t, "150.00Mi", podInfos[0].TotalMemory) } }) } @@ -764,8 +764,8 @@ func TestHandler_GetPodDetails(t *testing.T) { Status: "Running", Message: "", Reason: "", - TotalCPU: "250m", - TotalMemory: "500Mi", + TotalCPU: "250.00m", + TotalMemory: "500.00Mi", ContainerDetailsMap: map[string]ContainerDetails{ "container-1": { Name: "container-1", @@ -777,8 +777,8 @@ func TestHandler_GetPodDetails(t *testing.T) { RequestedMemory: "200Mi", LimitCPU: "200m", LimitMemory: "400Mi", - TotalCPU: "100m", - TotalMemory: "200Mi", + TotalCPU: "100.00m", + TotalMemory: "200.00Mi", LastTerminationReason: "", LastTerminationMessage: "", WaitingReason: "", @@ -794,8 +794,8 @@ func TestHandler_GetPodDetails(t *testing.T) { RequestedMemory: "300Mi", LimitCPU: "300m", LimitMemory: "600Mi", - TotalCPU: "150m", - TotalMemory: "300Mi", + TotalCPU: "150.00m", + TotalMemory: "300.00Mi", LastTerminationReason: "", LastTerminationMessage: "", LastStartedAt: "", @@ -1028,3 +1028,26 @@ func TestHandler_GetContainerStatus(t *testing.T) { }) } } + +func TestFormatCPU(t *testing.T) { + testCases := []struct { + input string + expected string + }{ + {"2953072n", "2.95m"}, + {"500m", "500.00m"}, + {"10000n", "0.01m"}, + {"0n", "0.00m"}, + {"100000000g", "0m"}, + {"invalid input", "0m"}, // Error case + } + + for _, tc := range testCases { + t.Run(fmt.Sprintf("Input: %s", tc.input), func(t *testing.T) { + result := formatCPU(tc.input) + if result != tc.expected { + t.Errorf("Expected: %s, Got: %s", tc.expected, result) + } + }) + } +} diff --git a/ui/src/components/pages/Pipeline/partials/Graph/partials/NodeInfo/partials/Pods/partials/PodDetails/partials/ContainerInfo/index.tsx b/ui/src/components/pages/Pipeline/partials/Graph/partials/NodeInfo/partials/Pods/partials/PodDetails/partials/ContainerInfo/index.tsx index 5a225b0dc..556256b05 100644 --- a/ui/src/components/pages/Pipeline/partials/Graph/partials/NodeInfo/partials/Pods/partials/PodDetails/partials/ContainerInfo/index.tsx +++ b/ui/src/components/pages/Pipeline/partials/Graph/partials/NodeInfo/partials/Pods/partials/PodDetails/partials/ContainerInfo/index.tsx @@ -4,7 +4,7 @@ import { getPodContainerUsePercentages } from "../../../../../../../../../../../ import { PodInfoProps } from "../../../../../../../../../../../../../types/declarations/pods"; import "./style.css"; - +// to do: remove podDetails and calculate cpu/mem percent from containerInfoProps export function ContainerInfo({ pod, podDetails, From 8b8ea70141570e249a274a00a9da81cbaecb2862 Mon Sep 17 00:00:00 2001 From: adarsh0728 Date: Mon, 18 Nov 2024 11:26:13 +0530 Subject: [PATCH 2/2] added TODO comments for UI and function name change Signed-off-by: adarsh0728 --- server/apis/v1/handler.go | 44 ++++++++++--------- server/apis/v1/handler_test.go | 4 +- .../partials/NodeInfo/partials/Pods/index.tsx | 1 + .../partials/ContainerInfo/index.tsx | 2 +- ui/src/utils/fetcherHooks/podsViewFetch.ts | 2 + 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/server/apis/v1/handler.go b/server/apis/v1/handler.go index 6046b1e83..fcac4753f 100644 --- a/server/apis/v1/handler.go +++ b/server/apis/v1/handler.go @@ -1573,25 +1573,6 @@ func (h *handler) getMonoVertexDaemonClient(ns, mvtName string) (mvtdaemonclient } } -func formatCPU(quantityStr string) string { - var value float64 - var format string - _, err := fmt.Sscanf(quantityStr, "%f%s", &value, &format) - if err != nil { - fmt.Println("Error parsing cpu quantity string:", err) - return "0m" - } else { - if strings.HasSuffix(format, "n") { - value /= 1e6 - } else if !strings.HasSuffix(format, "m") { // Handle cases where the format is not "m" - fmt.Println("Error parsing quantity string: invalid format") - return "0m" - } - cpuInMillicores := value - return fmt.Sprintf("%.2fm", cpuInMillicores) - } -} - func (h *handler) getPodDetails(pod corev1.Pod) (PodDetails, error) { podDetails := PodDetails{ Name: pod.Name, @@ -1620,7 +1601,7 @@ func (h *handler) getPodDetails(pod corev1.Pod) (PodDetails, error) { details = ContainerDetails{Name: container.Name} } if cpuQuantity != nil { - details.TotalCPU = formatCPU(cpuQuantity.String()) + details.TotalCPU = cpuToMillicores(cpuQuantity.String()) totalCPU.Add(*cpuQuantity) } if memQuantity != nil { @@ -1630,7 +1611,7 @@ func (h *handler) getPodDetails(pod corev1.Pod) (PodDetails, error) { containerDetails[containerName] = details } if totalCPU != nil { - podDetails.TotalCPU = formatCPU(totalCPU.String()) + podDetails.TotalCPU = cpuToMillicores(totalCPU.String()) } if totalMemory != nil { @@ -1703,3 +1684,24 @@ func (h *handler) getContainerStatus(state corev1.ContainerState) string { return "Unknown" } } + +func cpuToMillicores(quantityStr string) string { + var value float64 + var format string + + // Parse the quantity string + if _, err := fmt.Sscanf(quantityStr, "%f%s", &value, &format); err != nil { + fmt.Println("Error parsing cpu quantity string:", err) + return "0m" + } + + // Adjust value based on the format suffix + switch { + case strings.HasSuffix(format, "n"): + value /= 1e6 + case !strings.HasSuffix(format, "m"): + fmt.Println("Error parsing quantity string: invalid format") + return "0m" + } + return fmt.Sprintf("%.2fm", value) +} diff --git a/server/apis/v1/handler_test.go b/server/apis/v1/handler_test.go index c1da66420..d6e7ff784 100644 --- a/server/apis/v1/handler_test.go +++ b/server/apis/v1/handler_test.go @@ -1029,7 +1029,7 @@ func TestHandler_GetContainerStatus(t *testing.T) { } } -func TestFormatCPU(t *testing.T) { +func TestHandler_cpuToMillicores(t *testing.T) { testCases := []struct { input string expected string @@ -1044,7 +1044,7 @@ func TestFormatCPU(t *testing.T) { for _, tc := range testCases { t.Run(fmt.Sprintf("Input: %s", tc.input), func(t *testing.T) { - result := formatCPU(tc.input) + result := cpuToMillicores(tc.input) if result != tc.expected { t.Errorf("Expected: %s, Got: %s", tc.expected, result) } diff --git a/ui/src/components/pages/Pipeline/partials/Graph/partials/NodeInfo/partials/Pods/index.tsx b/ui/src/components/pages/Pipeline/partials/Graph/partials/NodeInfo/partials/Pods/index.tsx index 91baaeed8..4041dd9df 100644 --- a/ui/src/components/pages/Pipeline/partials/Graph/partials/NodeInfo/partials/Pods/index.tsx +++ b/ui/src/components/pages/Pipeline/partials/Graph/partials/NodeInfo/partials/Pods/index.tsx @@ -30,6 +30,7 @@ import { PodsProps, } from "../../../../../../../../../types/declarations/pods"; +// TODO: calculate podsDetails from pods-info API export function Pods(props: PodsProps) { const { host } = useContext(AppContext); const { namespaceId, pipelineId, vertexId, type } = props; diff --git a/ui/src/components/pages/Pipeline/partials/Graph/partials/NodeInfo/partials/Pods/partials/PodDetails/partials/ContainerInfo/index.tsx b/ui/src/components/pages/Pipeline/partials/Graph/partials/NodeInfo/partials/Pods/partials/PodDetails/partials/ContainerInfo/index.tsx index 556256b05..22134c5e7 100644 --- a/ui/src/components/pages/Pipeline/partials/Graph/partials/NodeInfo/partials/Pods/partials/PodDetails/partials/ContainerInfo/index.tsx +++ b/ui/src/components/pages/Pipeline/partials/Graph/partials/NodeInfo/partials/Pods/partials/PodDetails/partials/ContainerInfo/index.tsx @@ -4,7 +4,7 @@ import { getPodContainerUsePercentages } from "../../../../../../../../../../../ import { PodInfoProps } from "../../../../../../../../../../../../../types/declarations/pods"; import "./style.css"; -// to do: remove podDetails and calculate cpu/mem percent from containerInfoProps +// TODO: calculate cpu/mem percent from containerInfoProps/calculateCPUPercent/calculateMemoryPercent export function ContainerInfo({ pod, podDetails, diff --git a/ui/src/utils/fetcherHooks/podsViewFetch.ts b/ui/src/utils/fetcherHooks/podsViewFetch.ts index e893381cf..3c7bf46e5 100644 --- a/ui/src/utils/fetcherHooks/podsViewFetch.ts +++ b/ui/src/utils/fetcherHooks/podsViewFetch.ts @@ -14,6 +14,8 @@ import { PodDetail, } from "../../types/declarations/pods"; + +// TODO: calculate podsDetails from pods-info API export const usePodsViewFetch = ( namespaceId: string | undefined, pipelineId: string | undefined,