Node metrics: the six proposed changes

For PR 19760, which fixes issue 16247

I built changes 1 to 5 on a separate branch and deployed it, so every picture and video here is the real page, not a mock-up. Nothing is pushed: PR 19760 and its preview are as they were. Each change is its own commit, so you can keep some and drop others.

The links at the top use the mf Rancher, so log in as usual. They show real data, so the simulated cases in changes 3 and 4 only appear in the pictures and videos. Node IPs are blurred, and the label rows are hidden in the pictures of the Nodes list. Click a picture to see it full size.

#ChangeWhat you'd noticeTested on
1The same card on node detailNode detail looks like the dashboard. No more Used 0% without metrics.Real data
2Explain Used and ReservedAn info icon next to each, on both pages.Real data
3EKS uses real metricsNodes list and node detail stop showing pod requests as usage.Simulated
4Cluster Used counts only nodes reportingUsed no longer looks low when a node goes silent. A note says so.Simulated
5Two clean-upsNothing. A smaller PR.Code only
6Update the PR descriptionNothing in the UI. Reviewers are told about the older fix it reverses.Text only
1

The same card on node detail

Real data

The problem. The issue asks for the same cards on the cluster dashboard and on node detail. Today both show Reserved and Used, but the order, the number format and the colours are all different. Also, a node with no metrics says Used 0% on node detail, as if it were idle, while the Nodes list says n/a and the dashboard leaves Used out.

The change. Node detail uses the dashboard's card. Same order (Pods, CPU, Memory), same format, same colours. Without metrics, Used is left out.

Video, 1 min 4 s. Today and Proposed, the same steps, then a node with no metrics.

The look

Same cluster and same usage. In Today the two pages look different, and in Proposed they match. The Running count isn't held still, so it can be off by one between pictures.

Today Cluster dashboard
Cluster dashboard
Today Node detail
Node detail
Proposed Cluster dashboard (only the info icons are new, from change 2)
Cluster dashboard (only the info icons are new, from change 2)
Proposed Node detail
Node detail

A node with no metrics

Real: the mf local cluster has no node metrics.

Today Node detail says Used 0 of 4 / 0%
Node detail says Used 0 of 4 / 0%
Proposed Node detail leaves Used out, like the dashboard
Node detail leaves Used out, like the dashboard

What else changes on node detail

2

Explain Used and Reserved

Real data

The problem. The issue says it should be clear what usage and reserved mean. Nothing in the UI explains them, and one card now has two different totals: on the longhorn cluster, Used is out of 22.89 GiB and Reserved is out of 20.89 GiB.

The change. An info icon next to Used and Reserved, on the CPU and Memory cards of both pages. It opens on hover and on keyboard focus.

Used: The amount in use right now, including by the system, out of the total capacity.

Reserved: The amount pods have requested, out of what is available to pods, which is the total capacity minus what is set aside for the system.

Video, 31 s. Hovering the icons on the dashboard and on node detail.
Proposed Used, on the dashboard
Used, on the dashboard
Proposed Reserved, on the dashboard
Reserved, on the dashboard

Worth knowing

3

EKS uses real metrics when it has them

Simulated

The problem. For EKS clusters created from the UI, the Nodes list and node detail show what pods requested as the usage, even when real metrics exist. The dashboard uses the real metrics, so the pages disagree, and on node detail Reserved and Used are the same number.

That comes from a 2022 fix (PR 6915) for clusters with no metrics. But it only checks that the cluster is EKS and was created through Norman, and the UI creates every EKS cluster through Norman.

The change. Use the metrics when they exist. Fall back to pod requests only when there are none.

Nodes list, CPU of the 2 nodesNode detail, CPU Reserved and UsedDashboard, CPU Used
Today82% and 53%53% and 53%20.19%
Proposed8.8% and 26%53% and 26%20.19%
Video, 57 s. A normal cluster made to look like EKS, in my test browser only.
Today Nodes list shows pod requests as CPU and RAM
Nodes list shows pod requests as CPU and RAM
Proposed Nodes list shows the real usage
Nodes list shows the real usage
Today Node detail: Reserved and Used are identical
Node detail: Reserved and Used are identical
Proposed Node detail: Reserved and Used differ
Node detail: Reserved and Used differ

Worth knowing

Proposed EKS with no metrics at all: the fall back still works
EKS with no metrics at all: the fall back still works
4

Cluster Used counts only nodes that report metrics

Simulated

The problem. When a counted node stops reporting metrics, for example because it's NotReady, its usage goes away but its capacity stays in the total. So the cluster looks less busy than it is.

The change. Used adds up usage and capacity only for the nodes reporting metrics. When some don't, a note next to Capacity says so. The note is new: it wasn't in my list, I added it because otherwise the total changes with no explanation.

Dashboard, Memory UsedDashboard, CPU UsedNodes list, the node reporting
Today5.63 / 11.37 GiB = 49.52%1.04 / 6 = 17.27%RAM 74%, CPU 26%
Proposed5.63 / 7.63 GiB = 73.79%1.04 / 4 = 25.91%RAM 74%, CPU 26%
Video, 38 s. One of the 2 nodes reports no metrics, in my test browser only.
Today The silent node counts as idle
The silent node counts as idle
Proposed Used matches the node reporting, and the note says why
Used matches the node reporting, and the note says why
Proposed Nodes list, the same on both: n/a for the silent node, 74% RAM for the other
Nodes list, the same on both: n/a for the silent node, 74% RAM for the other

Worth knowing

5

Two clean-ups

Code only

Nothing changes on screen, so there's no video. These only make the PR smaller and easier to review.

Remove the clamp I added to the bar

I clamped the width in Bar.vue because Used could go negative, and a negative width drew a full bar. Used has nothing subtracted now, so it can't go negative. Bar is shared with other pages, so it's better to leave it exactly as it is on master.

Reserved can still go over 100%, but the bar already clips that. Below, without the clamp, 110.14% stops at the end of the bar: the coloured part is 344 px wide inside a 313 px bar, and the extra is cut off.

Proposed Memory Reserved at 110.14%, simulated by setting 1 GiB aside on each node
Memory Reserved at 110.14%, simulated by setting 1 GiB aside on each node

Simplify the rule for which nodes count

The roles list only repeated the check. The result is the same, and the same 11 test cases pass.

Today
const roles = [ETCD, CONTROL_PLANE, CONTROL_PLANE_OLD, WORKER];
const isWorker = WORKER in this.labels
  || !roles.some((role) => role in this.labels);

if (isWorker) {
  return true;
}

const serverRoles = [ETCD, CONTROL_PLANE, CONTROL_PLANE_OLD];
Proposed
const serverRoles = [ETCD, CONTROL_PLANE, CONTROL_PLANE_OLD];
const isWorker = WORKER in this.labels
  || !serverRoles.some((role) => role in this.labels);

if (isWorker) {
  return true;
}
6

Update the PR description

Text onlyReal data

The problem. Reviewers should be told three things that the description doesn't say yet. The first is the important one.

a. Used goes back to capacity, which reverses an older customer fix

In 2023 a customer (issue 7598) set memory aside for the system and found that node detail still showed the node's full memory, while CPU showed the smaller amount left for pods. They expected memory to show that smaller amount too, the allocatable. PR 9014 did that by dividing Used by allocatable. That's why, on master, the same node reads 38% in the list and 51% on node detail.

The PR puts Used back on capacity, so the total on Used is again the node's full memory, which is what that customer complained about. The number they asked for doesn't go away: it's now the total of the new Reserved bar, right above Used. UX asked for exactly that bar in the same issue:

We should add a reserved bar for the memory on the nodes detail page similar to the one on the cluster page.kwwii, issue 7598, February 2023

I think this is the right trade, and it's what Cody asked for, but a reviewer should hear it from us and not find it later.

Video, 27 s. The same real node on master and on the PR. This node has 2 GiB set aside for the system, which is why the two totals differ.
master Node detail: Memory Used 2.9 GiB of 5.63 GiB = 51%, and no Reserved
Node detail: Memory Used 2.9 GiB of 5.63 GiB = 51%, and no Reserved
Today With PR 19760: Used 2.9 GiB of 7.63 GiB = 38%, like the list. The 5.63 GiB is now on Reserved
With PR 19760: Used 2.9 GiB of 7.63 GiB = 38%, like the list. The 5.63 GiB is now on Reserved

b. Reserved differs from what the issue suggested

The issue suggested dividing Reserved by capacity. We divide by allocatable, following Cody's recommendation, because pods can only get the allocatable. The description should say that, so it doesn't look like a mistake.

c. The test steps must name the kubectl flag

Plain kubectl top node divides by allocatable, so anyone comparing with it on a node like this one would think the UI is wrong. --show-capacity is the one that matches Used. CPU matches either way here because this node sets aside only memory.

$ kubectl top node longhorn-pool1-r54vx-828jd
NAME                         CPU(cores)   CPU(%)   MEMORY(bytes)   MEMORY(%)   
longhorn-pool1-r54vx-828jd   1238m        61%      2881Mi          49%         

$ kubectl top node longhorn-pool1-r54vx-828jd --show-capacity
NAME                         CPU(cores)   CPU(%)   MEMORY(bytes)   MEMORY(%)   
longhorn-pool1-r54vx-828jd   1238m        61%      2881Mi          36%         

$ kubectl describe node longhorn-pool1-r54vx-828jd   (Allocated resources)
  Resource           Requests    Limits
  cpu                480m (24%)  0 (0%)
  memory             128Mi (2%)  0 (0%)

I ran this live, after the numbers in the pictures were frozen, so memory reads 49% and 36% instead of 51% and 38%. The gap between the two is what matters.

The new description

Not posted. It assumes you keep all of changes 1 to 5, and I'd adjust it to what you pick. removed added

### Summary
Fixes #16247
 
The node list, node detail and cluster dashboard each worked out CPU and memory usage differently, so the same node showed different numbers on each page (e.g. 74% in the list, 85% on detail and 51.87% on the dashboard). The dashboard could also show a negative Used, and its totals changed after visiting the Nodes page.
 
### Occurred changes and/or fixed issues
I'm using the model codyrancher asked for in the review of PR 18858, the same for CPU and memory on every page:
- Used = node usage ÷ capacity, with nothing subtracted. Usage comes from the whole machine, so dividing it by allocatable can go over 100% on a healthy node.
- Reserved = pod requests ÷ allocatable. Node detail now shows a Reserved gauge above Used in its CPU and Memory cards.
- Reserved = pod requests ÷ allocatable. The issue suggested capacity here, but pods can only get the allocatable, and the dashboard already used it.
- Node detail now has the same cards as the dashboard: same order, format and colours, and a Reserved bar. A node without metrics leaves Used out instead of showing 0%.
- An info icon next to Used and Reserved says what each one means, since their totals differ.
- The cluster dashboard adds these up over the same nodes Rancher counts in `cluster.status`. That leaves out cordoned nodes, and control plane or etcd nodes tainted so they don't run workloads. When nodes are left out, a note next to Capacity says how many are counted.
- The node list now sorts CPU and RAM by the percentage it shows, and the bar no longer draws a negative or over 100% value at full width.
- Used only counts the nodes reporting metrics, so a node that stops reporting doesn't make the cluster look less used. A note says so when that isn't all of them.
- EKS clusters created through Norman use their metrics when they have them. They only fall back to pod requests without metrics, which is the case PR 6915 was for.
- The node list now sorts CPU and RAM by the percentage it shows.
 
One to look at closely: PR 9014 (issue 7598) moved node detail's memory total to allocatable, because a customer who set memory aside still saw the node's full memory there. Used moves it back to capacity. The allocatable they expected is now the total of the Reserved bar, which is the bar UX asked for in that issue.
 
### Technical notes summary
- The node set is worked out by `isCountedInClusterResources` on the node model. It follows Rancher's stats aggregator and uses only kube node labels and taints. The dashboard no longer loads management nodes, which is why its totals used to depend on whether you had visited Nodes.
- Until the whole node list has loaded, or if it can't be loaded (e.g. a project member, or the request fails), Reserved and Pods come from `cluster.status`, as before. Used is left out then, because without the nodes the metrics can't be matched to the same set.
- `systemReservedCpu` and `systemReservedRam` are removed from the node model, since nothing uses them now.
- Node detail keeps `ConsumptionGauge`, so the per-value memory units stay as they are.
- I left the existing EKS case alone: nodes of EKS clusters migrated from Norman still use pod requests as their usage, since they may have no metrics.
- Node detail uses `HardwareResourceGauge`. Its memory values keep their own units through `formattedUseful` and `formattedTotal`, so the fix from PR 18360 stays. The new tooltip props are optional, so other users of the gauge don't change.
 
### Areas or cases that should be tested
- On a cluster with metrics, compare one node's CPU and memory % in the node list, on node detail (Used) and in the dashboard's Used when it's the only node counted. They should match.
- On a cluster with metrics, compare one node's CPU and memory % in the node list, on node detail (Used) and in the dashboard's Used when it's the only node counted. They should match, and match `kubectl top node --show-capacity`. Plain `kubectl top node` divides by allocatable, so it reads higher on a node with memory set aside.
- Node detail's Reserved should match the requests in `kubectl describe node`.
- Cordon a node: the dashboard totals should drop it and the "x of y nodes" note should show up next to Capacity.
- On RKE2/k3s, a tainted control plane or etcd node shouldn't be counted, but an untainted server node should.
- Open the cluster dashboard, visit Nodes, then go back: the numbers shouldn't change.
- Log in as a project member, who can't list nodes: Reserved and Pods should still show, without Used.
- On a cluster without metrics, node detail and the dashboard should both leave Used out.
- If you have an EKS cluster created through the UI: with metrics, the three pages should agree. Without metrics, the list and node detail should show pod requests.
 
I tested in Chrome.
 
### Areas which could experience regressions
- Cluster dashboard Capacity section (Pods, CPU and Memory gauges).
- Node list CPU and RAM columns and their sorting.
- Node detail CPU and Memory cards.
- Anything else using the `Bar` graph component.
- Node detail CPU, Memory and Pods cards.
- Anything else using `HardwareResourceGauge`, e.g. the Harvester dashboard.
 
### Screenshot/Video
I'll add before/after screenshots.
 
### Checklist
- [x] The PR is linked to an issue and the linked issue has a Milestone, or no issue is needed
- [x] The PR has a Milestone <!-- The milestone should automatically be assigned if the linked issue has one, but does not always happen (incorrectly linked, issue has no milestone, etc) -->
- [x] The PR template has been filled out
- [x] The PR has been self reviewed <!-- There are no TODOs, no incorrect files in the PR, all the required files are there, no commented out code, etc-->
- [ ] The PR has a reviewer assigned
- [x] The PR has automated tests or clear instructions for manual tests and the linked issue has appropriate QA labels, or tests are not needed
- [ ] The PR has reviewed with UX and tested in light and dark mode, or there are no UX changes
- [ ] The PR has been reviewed in terms of Accessibility
- [ ] The PR has considered, and if applicable tested with, the three Global Roles `Admin`, `Standard User` and `User Base`

What I checked, and what I didn't

Check on the proposed branchResult
Full unit test suite868 suites passed, 15,971 tests passed
Type checkNo new errors (baseline 301, now 300)
Lint on the changed filesClean
No access to nodes (stubbed, not a real project member login), or the node list failsReserved and Pods still show, without Used
Node list slow to loadReserved and Pods show first, Used appears once the nodes have loaded
Node detail's Used follows the 30-second metric refreshYes: went from 25.00% to 75.00% when the metric changed
Tooltips open with the keyboardYes, on focus
Browser errors on the pages above, on all previewsNone
Dark modeLooks fine

Not checked: a real EKS cluster, a real node stopping, a real project member login, and the Harvester dashboard with the changed card (nothing it passes changes, but I didn't run it).

What I need from you

Full code of changes 1 to 5: the diff. One commit each: change 1 71e3e8750, change 2 9c0a7c4e6, change 3 c0de5d000, change 4 016eb8ec7, change 5 ba77892c3. Local branch node-metrics-proposal, not pushed.