Skip to content
This repository was archived by the owner on Jun 26, 2026. It is now read-only.

Commit fc63158

Browse files
authored
fix(cluster-usage): parse nano/micro CPU quantities from metrics-server (#22)
parseQuantity handled milli, binary Ki..Ei and decimal k/M/G suffixes but had no branch for the decimal sub-units n (nano) and u (micro). metrics.k8s.io reports NodeMetrics.usage.cpu in nanocores (e.g. "2785315627n"), so the trailing n was ignored and the raw integer was returned as if it were cores. The Cluster Usage CPU Used value and bar inflated by ~1e9x in both the aggregate card and the per-node table. Add the n and u branches next to milli, and pin the parser plus the aggregate and per-node surfaces with nanocore fixtures. Assisted-By: Claude <noreply@anthropic.com> Signed-off-by: Aleksei Sviridkin <f@lex.la>
1 parent 4570d44 commit fc63158

4 files changed

Lines changed: 39 additions & 3 deletions

File tree

apps/console/src/lib/cluster-usage/aggregate.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,16 @@ describe("aggregateNodeResources", () => {
135135
expect(a.standard.memory.used).toBe(4 * 1024 ** 3)
136136
})
137137

138+
it("reports cpu used in cores from nanocore metrics, not raw nanocores", () => {
139+
const a = aggregateNodeResources(
140+
[node("a", { cpu: "288", memory: "256Gi" })],
141+
[],
142+
[metric("a", "2785315627n", "14417112Ki")],
143+
)
144+
expect(a.standard.cpu.used).toBeCloseTo(2.785, 3)
145+
expect(a.standard.memory.used).toBe(14417112 * 1024)
146+
})
147+
138148
it("leaves used undefined when metrics is undefined", () => {
139149
const a = aggregateNodeResources(
140150
[node("a", { cpu: "8", memory: "16Gi" })],

apps/console/src/lib/cluster-usage/per-node.test.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,16 @@ describe("derivePerNodeRows", () => {
194194
expect(rows[0].standard.memory.used).toBe(4 * 1024 ** 3)
195195
})
196196

197+
it("reports cpu used in cores from nanocore metrics, not raw nanocores", () => {
198+
const rows = derivePerNodeRows(
199+
[nodeWith("a", { capacity: { cpu: "288", memory: "256Gi" } })],
200+
[],
201+
[metric("a", "2785315627n", "14417112Ki")],
202+
)
203+
expect(rows[0].standard.cpu.used).toBeCloseTo(2.785, 3)
204+
expect(rows[0].standard.memory.used).toBe(14417112 * 1024)
205+
})
206+
197207
it("leaves used undefined per node when metrics are undefined", () => {
198208
const rows = derivePerNodeRows(
199209
[nodeWith("a", { capacity: { cpu: "8", memory: "16Gi" } })],

apps/console/src/lib/k8s-quantity.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,18 @@ describe("parseQuantity", () => {
5050
expect(parseQuantity("1G")).toBe(1_000_000_000)
5151
})
5252

53+
it("parses nano suffix — metrics-server reports CPU usage in nanocores", () => {
54+
expect(parseQuantity("2785315627n")).toBeCloseTo(2.785315627, 6)
55+
})
56+
57+
it("parses micro suffix as a millionth", () => {
58+
expect(parseQuantity("500u")).toBe(500 / 1e6)
59+
})
60+
61+
it("parses zero nanocores", () => {
62+
expect(parseQuantity("0n")).toBe(0)
63+
})
64+
5365
it("parses a bare integer", () => {
5466
expect(parseQuantity("42")).toBe(42)
5567
})

apps/console/src/lib/k8s-quantity.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
/**
22
* Parse a Kubernetes resource.Quantity string into a numeric value in
3-
* the canonical units (cores for CPU, bytes for memory). Behaviour is
4-
* preserved verbatim from the QuotaDisplay helpers this module was
5-
* extracted from; see the test file for the pinned edge cases.
3+
* the canonical units (cores for CPU, bytes for memory). Extracted from
4+
* the QuotaDisplay helpers; nano/micro (n/u) support was added on top for
5+
* the nanocore CPU values metrics-server reports. See the test file for
6+
* the pinned edge cases.
67
*/
78
export function parseQuantity(s: string): number {
89
if (!s) return 0
@@ -11,6 +12,9 @@ export function parseQuantity(s: string): number {
1112
const n = parseFloat(s)
1213
if (!Number.isFinite(n)) return 0
1314
if (s.endsWith("m")) return n / 1000
15+
// Decimal SI sub-units — metrics-server reports CPU usage in nanocores
16+
if (s.endsWith("n")) return n / 1e9
17+
if (s.endsWith("u")) return n / 1e6
1418
// Binary SI suffixes (powers of 1024)
1519
if (s.endsWith("Ki")) return n * 1024
1620
if (s.endsWith("Mi")) return n * 1024 ** 2

0 commit comments

Comments
 (0)