Skip to content

Commit abc00ee

Browse files
authored
feat: improve handling of resource units (#3980)
1 parent 5d911b8 commit abc00ee

File tree

8 files changed

+62
-77
lines changed

8 files changed

+62
-77
lines changed

src/components/Clusters/views/ClusterOverview/ClusterStats.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ import {
99
bytesToHumanReadable,
1010
cpusToHumanReadable,
1111
getBytes,
12-
} from 'resources/Namespaces/ResourcesUsage';
12+
} from 'shared/helpers/resources';
1313
import {
1414
getHealthyDaemonsets,
1515
getHealthyReplicasCount,

src/components/Nodes/NodeResources/NodeResources.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import './NodeResources.scss';
55
import {
66
bytesToHumanReadable,
77
cpusToHumanReadable,
8-
} from '../../../resources/Namespaces/ResourcesUsage.js';
8+
} from 'shared/helpers/resources';
99

1010
export function NodeResources({ metrics, resources }) {
1111
const { t } = useTranslation();

src/components/Nodes/nodeQueries.js

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
import { useEffect, useMemo, useState } from 'react';
22
import { useGet } from 'shared/hooks/BackendAPI/useGet';
3-
import {
4-
getBytes,
5-
getCpus,
6-
} from '../../resources/Namespaces/ResourcesUsage.js';
3+
import { getBytes, getCpus } from 'shared/helpers/resources';
74

85
const getPercentageFromUsage = (value, total) => {
96
if (total === 0) {
@@ -123,18 +120,12 @@ const emptyResources = {
123120
};
124121

125122
function addResources(a, b) {
126-
if (!a) {
127-
if (!b) {
128-
return structuredClone(emptyResources);
129-
}
130-
return b;
131-
}
132-
if (!b) {
133-
if (!a) {
134-
return structuredClone(emptyResources);
135-
}
136-
return a;
123+
if (!a && !b) {
124+
return structuredClone(emptyResources);
137125
}
126+
if (!a) return b ?? structuredClone(emptyResources);
127+
if (!b) return a;
128+
138129
return {
139130
limits: {
140131
cpu: getCpus(a?.limits?.cpu) + getCpus(b?.limits?.cpu),

src/resources/Namespaces/ResourcesUsage.js

Lines changed: 4 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,17 @@
11
import { UI5RadialChart } from 'shared/components/UI5RadialChart/UI5RadialChart';
22
import { useTranslation } from 'react-i18next';
33

4-
import { formatResourceUnit } from 'shared/helpers/resources.js';
4+
import {
5+
bytesToHumanReadable,
6+
cpusToHumanReadable,
7+
} from 'shared/helpers/resources';
58
import { Card, CardHeader } from '@ui5/webcomponents-react';
69
import {
710
calculateMetrics,
811
usePodsMetricsQuery,
912
} from 'resources/Pods/podQueries';
1013
import { Spinner } from 'shared/components/Spinner/Spinner';
1114

12-
const MEMORY_SUFFIX_POWER = {
13-
// must be sorted from the smallest to the largest; it is case sensitive; more info: https://medium.com/swlh/understanding-kubernetes-resource-cpu-and-memory-units-30284b3cc866
14-
m: 1e-3,
15-
k: 1e3,
16-
K: 1e3,
17-
Ki: 2 ** 10,
18-
M: 1e6,
19-
Mi: 2 ** 20,
20-
G: 1e9,
21-
Gi: 2 ** 30,
22-
Ti: 2 ** 40,
23-
};
24-
25-
const CPU_SUFFIX_POWER = {
26-
m: 1e-3,
27-
n: 1e-9,
28-
};
29-
30-
export function getBytes(memoryStr) {
31-
if (!memoryStr) return 0;
32-
33-
const unit = String(memoryStr).match(/[a-zA-Z]+/g)?.[0];
34-
const value = parseFloat(memoryStr);
35-
const bytes = value * (MEMORY_SUFFIX_POWER[unit] || 1);
36-
return bytes;
37-
}
38-
39-
export function getCpus(cpuString) {
40-
if (!cpuString || cpuString === '0') {
41-
return 0;
42-
}
43-
44-
const suffix = String(cpuString).slice(-1);
45-
46-
const suffixPower = CPU_SUFFIX_POWER[suffix];
47-
if (!suffixPower) {
48-
return parseFloat(cpuString);
49-
}
50-
51-
const number = String(cpuString).replace(suffix, '');
52-
return number * suffixPower;
53-
}
54-
55-
export function bytesToHumanReadable(bytes, { fixed = 0, unit = '' } = {}) {
56-
return formatResourceUnit(bytes, true, { withoutSpace: true, fixed, unit });
57-
}
58-
59-
export function cpusToHumanReadable(cpus, { fixed = 0, unit = '' } = {}) {
60-
return formatResourceUnit(cpus, false, { withoutSpace: true, fixed, unit });
61-
}
62-
6315
export const ResourcesUsage = ({ namespace }) => {
6416
const { t } = useTranslation();
6517
const { podsMetrics, error, loading } = usePodsMetricsQuery(namespace);

src/resources/Pods/podQueries.ts

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/resources/ResourceQuotas/support.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import {
33
cpusToHumanReadable,
44
getBytes,
55
getCpus,
6-
} from 'resources/Namespaces/ResourcesUsage';
6+
} from 'shared/helpers/resources';
77
import { ResourceQuota } from './ResourceQuotaDetails';
88
import { calculateMetrics } from 'resources/Pods/podQueries';
99
import { UsageMetrics } from 'resources/Pods/types';

src/shared/components/Link/Link.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ type LinkProps = {
1212
design?: 'Default' | 'Subtle' | 'Emphasized';
1313
resetLayout?: boolean;
1414
onClick?: any;
15-
style: React.CSSProperties;
15+
style?: React.CSSProperties;
1616
};
1717

1818
export const Link = ({
@@ -23,7 +23,7 @@ export const Link = ({
2323
design = 'Emphasized',
2424
resetLayout = true,
2525
onClick,
26-
style,
26+
style = {},
2727
}: LinkProps) => {
2828
const setLayout = useSetRecoilState(columnLayoutState);
2929
const navigate = useNavigate();

src/shared/helpers/resources.js

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ const SI_PREFIXES = {
55
m: 1e-3,
66
'': 1,
77
k: 1e3,
8+
K: 1e3,
89
M: 1e6,
910
G: 1e9,
1011
T: 1e12,
@@ -13,20 +14,28 @@ const SI_PREFIXES = {
1314
};
1415

1516
const SI_PREFIXES_BINARY = {
17+
'': 1,
1618
Ki: 2 ** 10,
1719
Mi: 2 ** 20,
1820
Gi: 2 ** 30,
1921
Ti: 2 ** 40,
2022
Pi: 2 ** 50,
23+
Ei: 2 ** 60,
24+
};
25+
26+
const MEMORY_PREFIXES = {
27+
...SI_PREFIXES,
28+
...SI_PREFIXES_BINARY,
2129
};
2230

2331
/*
2432
More precise round method.
25-
Want 1.005 to be rounded to 1.01 we need to add Number.EPSILON to fix the float inaccuracy
33+
Fixes floating point precision issues (e.g., 1.005 rounds to 1.01)
2634
*/
27-
const preciseRound = (num, places) =>
28-
Math.round((num + Number.EPSILON) * Math.pow(10, places)) /
29-
Math.pow(10, places);
35+
const preciseRound = (num, places) => {
36+
const multiplier = Math.pow(10, places);
37+
return Math.round((num + Number.EPSILON) * multiplier) / multiplier;
38+
};
3039

3140
export function formatResourceUnit(
3241
amount = 0,
@@ -67,3 +76,36 @@ export function formatResourceUnit(
6776

6877
return output;
6978
}
79+
80+
export function bytesToHumanReadable(bytes, { fixed = 0, unit = '' } = {}) {
81+
return formatResourceUnit(bytes, true, { withoutSpace: true, fixed, unit });
82+
}
83+
84+
export function cpusToHumanReadable(cpus, { fixed = 0, unit = '' } = {}) {
85+
return formatResourceUnit(cpus, false, { withoutSpace: true, fixed, unit });
86+
}
87+
88+
export function getCpus(cpuString) {
89+
if (!cpuString || cpuString === '0') {
90+
return 0;
91+
}
92+
93+
const suffix = String(cpuString).slice(-1);
94+
95+
const suffixPower = SI_PREFIXES[suffix];
96+
if (!suffixPower) {
97+
return parseFloat(cpuString);
98+
}
99+
100+
const number = String(cpuString).replace(suffix, '');
101+
return number * suffixPower;
102+
}
103+
104+
export function getBytes(memoryStr) {
105+
if (!memoryStr) return 0;
106+
107+
const unit = String(memoryStr).match(/[a-zA-Z]+/g)?.[0];
108+
const value = parseFloat(memoryStr);
109+
const bytes = value * (MEMORY_PREFIXES[unit] || 1);
110+
return bytes;
111+
}

0 commit comments

Comments
 (0)