mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-08-11 01:53:57 +00:00
Fix Thresholds page crash on guest filesystems with omitted usage
The unified resources payload serializes guest filesystem numerics with omitempty, so a disk whose usage is exactly zero arrives with the field absent. The guest filesystem projection guarded with usage < 0, which undefined passes, then dereferenced usage.toFixed and took down the whole Alerts > Thresholds page behind the error boundary (#1663). Treat absent numerics as zero and derive the percentage from used/total when the serialized value is missing; a negative usage still means the poller could not read the filesystem and stays excluded.
This commit is contained in:
parent
a90d5c907a
commit
15bb0c217e
2 changed files with 74 additions and 2 deletions
|
|
@ -72,6 +72,69 @@ describe('useThresholdsGuestData guest filesystems', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('projects filesystems whose serialized usage was omitted without crashing', () => {
|
||||
createRoot((dispose) => {
|
||||
const props = {
|
||||
allGuests: () => [
|
||||
{
|
||||
id: 'cluster-a:node-1:101',
|
||||
name: 'files',
|
||||
platformId: 'cluster-a',
|
||||
status: 'online',
|
||||
type: 'ct',
|
||||
lastSeen: 1,
|
||||
proxmox: {
|
||||
instance: 'cluster-a',
|
||||
node: 'node-1',
|
||||
vmid: 101,
|
||||
// The unified resources payload drops zero-valued numerics, so
|
||||
// an untouched filesystem arrives with no usage/used fields.
|
||||
disks: [
|
||||
{
|
||||
device: 'rootfs',
|
||||
mountpoint: '/',
|
||||
total: 107374182400,
|
||||
type: 'ext4',
|
||||
},
|
||||
{
|
||||
device: 'mp0',
|
||||
mountpoint: '/data',
|
||||
total: 214748364800,
|
||||
used: 107374182400,
|
||||
free: 107374182400,
|
||||
type: 'ext4',
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
backupDefaults: () => ({ enabled: false }),
|
||||
guestDefaults: { disk: 85 },
|
||||
nodes: [],
|
||||
overrides: () => [],
|
||||
snapshotDefaults: () => ({ enabled: false }),
|
||||
} as unknown as ThresholdsTableProps;
|
||||
|
||||
const data = useThresholdsGuestData({
|
||||
props,
|
||||
editingId: () => null,
|
||||
searchTerm: () => '',
|
||||
});
|
||||
|
||||
expect(data.guestDisksWithOverrides()).toEqual([
|
||||
expect.objectContaining({
|
||||
name: '/',
|
||||
subtitle: '0.0 / 100.0 GB · 0.0%',
|
||||
}),
|
||||
expect.objectContaining({
|
||||
name: '/data',
|
||||
subtitle: '100.0 / 200.0 GB · 50.0%',
|
||||
}),
|
||||
]);
|
||||
dispose();
|
||||
});
|
||||
});
|
||||
|
||||
it('keeps a persisted filesystem override visible after its guest disappears', () => {
|
||||
createRoot((dispose) => {
|
||||
const props = {
|
||||
|
|
|
|||
|
|
@ -117,7 +117,16 @@ export function useThresholdsGuestData(inputs: ThresholdsDataInputs) {
|
|||
const guestIdentity = getGuestOverrideIdentity(guest);
|
||||
|
||||
disks.forEach((disk: Disk) => {
|
||||
if (!disk || disk.total <= 0 || disk.usage < 0) return;
|
||||
// The unified resources payload omits zero-valued numerics, so
|
||||
// total/used/usage may all be absent; usage < 0 is the poller's
|
||||
// "unknown" sentinel and stays excluded.
|
||||
const total = disk?.total ?? 0;
|
||||
const used = disk?.used ?? 0;
|
||||
if (!disk || total <= 0 || (typeof disk.usage === 'number' && disk.usage < 0)) return;
|
||||
const usagePercent =
|
||||
typeof disk.usage === 'number' && Number.isFinite(disk.usage)
|
||||
? disk.usage
|
||||
: (used / total) * 100;
|
||||
|
||||
const candidates = guestDiskOverrideIdCandidates(guest, disk.mountpoint, disk.device);
|
||||
const storageId = guestDiskOverrideStorageId(guest, disk.mountpoint, disk.device);
|
||||
|
|
@ -153,7 +162,7 @@ export function useThresholdsGuestData(inputs: ThresholdsDataInputs) {
|
|||
disabled: override?.disabled || false,
|
||||
thresholds: override?.thresholds || {},
|
||||
defaults: { disk: props.guestDefaults.disk },
|
||||
subtitle: `${(disk.used / 1024 / 1024 / 1024).toFixed(1)} / ${(disk.total / 1024 / 1024 / 1024).toFixed(1)} GB · ${disk.usage.toFixed(1)}%`,
|
||||
subtitle: `${(used / 1024 / 1024 / 1024).toFixed(1)} / ${(total / 1024 / 1024 / 1024).toFixed(1)} GB · ${usagePercent.toFixed(1)}%`,
|
||||
} satisfies TableResource);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue