diff --git a/src/components/Clusters/views/ClusterOverview/ClusterStats.js b/src/components/Clusters/views/ClusterOverview/ClusterStats.js index e2ae482659..273735891d 100644 --- a/src/components/Clusters/views/ClusterOverview/ClusterStats.js +++ b/src/components/Clusters/views/ClusterOverview/ClusterStats.js @@ -7,6 +7,7 @@ import { CountingCard } from 'shared/components/CountingCard/CountingCard'; import { useGetList } from 'shared/hooks/BackendAPI/useGet'; import { bytesToHumanReadable, + cpusToHumanReadable, getBytes, } from 'resources/Namespaces/ResourcesUsage'; import { @@ -129,9 +130,11 @@ export default function ClusterStats({ nodesData }) { color="var(--sapChart_OrderedColor_5)" value={roundTwoDecimals(cpu.usage)} max={roundTwoDecimals(cpu.capacity)} - additionalInfo={`${roundTwoDecimals( - cpu.usage, - )}m / ${roundTwoDecimals(cpu.capacity)}m`} + additionalInfo={`${cpusToHumanReadable(cpu.usage, { + unit: 'm', + })} / ${cpusToHumanReadable(cpu.capacity, { + unit: 'm', + })}`} /> diff --git a/src/components/Nodes/NodeResources/NodeResources.js b/src/components/Nodes/NodeResources/NodeResources.js index fa2807735b..d0426d9625 100644 --- a/src/components/Nodes/NodeResources/NodeResources.js +++ b/src/components/Nodes/NodeResources/NodeResources.js @@ -3,6 +3,7 @@ import { UI5RadialChart } from 'shared/components/UI5RadialChart/UI5RadialChart' import { Card, CardHeader } from '@ui5/webcomponents-react'; import { roundTwoDecimals } from 'shared/utils/helpers'; import './NodeResources.scss'; +import { cpusToHumanReadable } from '../../../resources/Namespaces/ResourcesUsage.js'; export function NodeResources({ metrics, resources }) { const { t } = useTranslation(); @@ -19,10 +20,10 @@ export function NodeResources({ metrics, resources }) { - Math.round(num * Math.pow(10, places)) / Math.pow(10, places); + Math.round((num + Number.EPSILON) * Math.pow(10, places)) / + Math.pow(10, places); const getPercentageFromUsage = (value, total) => { if (total === 0) { @@ -15,16 +16,16 @@ const getPercentageFromUsage = (value, total) => { return Math.round((100 * value) / total); }; -const formatCpu = cpuStr => Math.ceil(parseInt(cpuStr || '0') / 1000_000); -const formatMemory = memoryStr => +const formatKiToGiMemory = memoryStr => round(parseInt(memoryStr || '0') / 1024 / 1024, 1); const createUsageMetrics = (node, metricsForNode) => { - const cpuUsage = formatCpu(metricsForNode?.usage.cpu); - const memoryUsage = formatMemory(metricsForNode?.usage.memory); - const cpuCapacity = parseInt(node.status.allocatable?.cpu || '0'); - const memoryCapacity = formatMemory(node.status.allocatable?.memory); + const cpuUsage = getCpus(metricsForNode?.usage.cpu); + const memoryUsage = formatKiToGiMemory(metricsForNode?.usage.memory); + const cpuCapacity = getCpus(node.status.allocatable?.cpu || '0'); + const memoryCapacity = formatKiToGiMemory(node.status.allocatable?.memory); + console.log(cpuCapacity); const cpuPercentage = getPercentageFromUsage(cpuUsage, cpuCapacity); const memoryPercentage = getPercentageFromUsage(memoryUsage, memoryCapacity); @@ -176,11 +177,11 @@ export function calcNodeResources(pods) { return { limits: { - cpu: nodeResources.limits.cpu * 1000, + cpu: nodeResources.limits.cpu, memory: nodeResources.limits.memory / Math.pow(1024, 3), }, requests: { - cpu: nodeResources.requests.cpu * 1000, + cpu: nodeResources.requests.cpu, memory: nodeResources.requests.memory / Math.pow(1024, 3), }, }; diff --git a/src/components/Nodes/nodeQueries.test.js b/src/components/Nodes/nodeQueries.test.js index b5258567a4..e56f57f48b 100644 --- a/src/components/Nodes/nodeQueries.test.js +++ b/src/components/Nodes/nodeQueries.test.js @@ -1,4 +1,5 @@ import { calcNodeResources } from './nodeQueries.js'; + describe('Calculate resources for node', () => { const testCases = [ { @@ -11,11 +12,11 @@ describe('Calculate resources for node', () => { }, expectedValue: { limits: { - cpu: 10, + cpu: 0.01, memory: 100.0 / 1024, }, requests: { - cpu: 20, + cpu: 0.02, memory: 200.0 / 1024, }, }, @@ -36,11 +37,11 @@ describe('Calculate resources for node', () => { }, expectedValue: { limits: { - cpu: 22, + cpu: 0.022, memory: 220.0 / 1024, }, requests: { - cpu: 45, + cpu: 0.045, memory: 450.0 / 1024, }, }, @@ -55,11 +56,11 @@ describe('Calculate resources for node', () => { }, expectedValue: { limits: { - cpu: 7, + cpu: 0.007, memory: 70.0 / 1024, }, requests: { - cpu: 14, + cpu: 0.014, memory: 140.0 / 1024, }, }, diff --git a/src/resources/Namespaces/ResourcesUsage.js b/src/resources/Namespaces/ResourcesUsage.js index 3f09126f31..0ff9bd0900 100644 --- a/src/resources/Namespaces/ResourcesUsage.js +++ b/src/resources/Namespaces/ResourcesUsage.js @@ -3,7 +3,7 @@ import { useGetList } from 'shared/hooks/BackendAPI/useGet'; import { Spinner } from 'shared/components/Spinner/Spinner'; import { useTranslation } from 'react-i18next'; -import { getSIPrefix } from 'shared/helpers/siPrefixes'; +import { formatResourceUnit } from 'shared/helpers/resources.js'; import { Card, CardHeader } from '@ui5/webcomponents-react'; const MEMORY_SUFFIX_POWER = { @@ -21,6 +21,7 @@ const MEMORY_SUFFIX_POWER = { const CPU_SUFFIX_POWER = { m: 1e-3, + n: 1e-9, }; export function getBytes(memoryStr) { @@ -50,12 +51,12 @@ export function getCpus(cpuString) { export function bytesToHumanReadable(bytes) { if (!bytes) return bytes; - return getSIPrefix(bytes, true, { withoutSpace: true }).string; + return formatResourceUnit(bytes, true, { withoutSpace: true }); } -export function cpusToHumanReadable(cpus) { +export function cpusToHumanReadable(cpus, { fixed = 0, unit = '' } = {}) { if (!cpus) return cpus; - return cpus / MEMORY_SUFFIX_POWER['m'] + 'm'; + return formatResourceUnit(cpus, false, { withoutSpace: true, fixed, unit }); } const MemoryRequestsCircle = ({ resourceQuotas, isLoading }) => { diff --git a/src/shared/helpers/resources.js b/src/shared/helpers/resources.js new file mode 100644 index 0000000000..37583352bc --- /dev/null +++ b/src/shared/helpers/resources.js @@ -0,0 +1,56 @@ +const SI_PREFIXES = { + p: 1e-12, + n: 1e-9, + µ: 1e-6, + m: 1e-3, + '': 1, + k: 1e3, + M: 1e6, + G: 1e9, + T: 1e12, + P: 1e15, + E: 1e18, +}; + +const SI_PREFIXES_BINARY = { + Ki: 2 ** 10, + Mi: 2 ** 20, + Gi: 2 ** 30, + Ti: 2 ** 40, + Pi: 2 ** 50, +}; + +/* +More precise round method. +Want 1.005 to be rounded to 1.01 we need to add Number.EPSILON to fix the float inaccuracy + */ +const preciseRound = (num, places) => + Math.round((num + Number.EPSILON) * Math.pow(10, places)) / + Math.pow(10, places); + +export function formatResourceUnit( + amount, + binary = false, + { unit = '', withoutSpace = true, fixed = 2 } = {}, +) { + const prefixMap = binary ? SI_PREFIXES_BINARY : SI_PREFIXES; + const infix = withoutSpace ? '' : ' '; + + if (unit && prefixMap[unit]) { + const value = (amount / prefixMap[unit]).toFixed(fixed); + return `${value}${infix}${unit}`; + } + + const coreValue = preciseRound(amount, 2).toFixed(fixed); + + let output = `${coreValue}${infix}${unit}`; + Object.entries(prefixMap).forEach(([prefix, power]) => { + const tmpValue = amount / power; + if (tmpValue >= 1) { + const value = preciseRound(tmpValue, 2).toFixed(fixed); + output = `${value}${infix}${prefix}${unit}`; + } + }); + + return output.string; +} diff --git a/src/shared/helpers/siPrefixes.js b/src/shared/helpers/siPrefixes.js deleted file mode 100644 index a2693926b4..0000000000 --- a/src/shared/helpers/siPrefixes.js +++ /dev/null @@ -1,59 +0,0 @@ -const SI_PREFIXES = { - p: 1e-12, - n: 1e-9, - µ: 1e-6, - m: 1e-3, - '': 1, - k: 1e3, - M: 1e6, - G: 1e9, - T: 1e12, - P: 1e15, - E: 1e18, -}; - -const SI_PREFIXES_BINARY = { - Ki: 2 ** 10, - Mi: 2 ** 20, - Gi: 2 ** 30, - Ti: 2 ** 40, - Pi: 2 ** 50, -}; - -export function getSIPrefix( - amount, - binary = false, - { unit = '', withoutSpace = true, fixed = 2 } = {}, -) { - const prefixMap = binary ? SI_PREFIXES_BINARY : SI_PREFIXES; - const infix = withoutSpace ? '' : ' '; - - const coreValue = ( - Math.round((+amount + Number.EPSILON) * 100) / 100 - ).toFixed(fixed); - let output = { - raw: amount, - value: coreValue, - rounded: coreValue, - prefix: '', - string: `${coreValue}${infix}${unit}`, - }; - Object.entries(prefixMap).forEach(([prefix, power]) => { - const tmpValue = amount / power; - if (tmpValue >= 1) { - const value = ( - Math.round((tmpValue + Number.EPSILON) * 100) / 100 - ).toFixed(fixed); - output = { - raw: tmpValue, - value, - rounded: value * power, - prefix, - unit: `${prefix}${unit}`, - string: `${value}${infix}${prefix}${unit}`, - }; - } - }); - - return output; -}