mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-23 20:25:56 +00:00
Pin disk heat parity for canonical and linked-guest overrides
A second review of the per-host Disk Temp change found two gaps. The parity test did not cover an override stored under the canonical resource an agent ID resolves to, or one inherited from a linked guest. The documented browser limits also listed only two cases where the browser cannot see CheckHost's chain. The parity test now checks both overrides, and a disabled linked guest, against what CheckHost fires. storage-recovery.md lists every case where the browser's keys can differ from alerts and Patrol: manually merged agent and VM disks on the Storage page, overrides inherited through unpublished link hints or stored under a linked node's canonical ID, and guest keys for an agent merged into a guest it is not automatically linked to.
This commit is contained in:
@@ -1780,14 +1780,16 @@ override on that host, or one inherited from its linked node or guest, replaces
|
||||
the per-type entry, the first override in that chain decides even when it sets
|
||||
no Disk Temp, and an override that switches the host's alerts off leaves no
|
||||
threshold. `TestHostDiskTemperatureThresholdMatchesCheckHostOverrides` pins each
|
||||
case against what `CheckHost` fires. `Manager.DiskTemperatureThreshold(diskType)`
|
||||
case against what `CheckHost` fires, including an override under the canonical
|
||||
resource the agent ID resolves to and one inherited from a linked guest. `Manager.DiskTemperatureThreshold(diskType)`
|
||||
is the hostless case. Patrol reads the policy through
|
||||
`AlertThresholdAdapter.GetDiskTemperatureThreshold`.
|
||||
`DefaultDiskTemperatureThreshold` serves callers with no manager. Disk risk
|
||||
(`internal/storagehealth`) judges no temperature. The Physical Disks Temp cell
|
||||
and Health verdict mirror the policy in `resolveDiskTemperatureDisplayThresholds`
|
||||
under the override keys of the machine whose agent reports the disk, in the
|
||||
order `CheckHost` reads them. That resolver returns null when the agent Disk
|
||||
order `CheckHost` reads them as far as the browser can see that chain
|
||||
(`storage-recovery.md` lists where it cannot). That resolver returns null when the agent Disk
|
||||
Temp default is off or an override or agent default switches the host's alerts
|
||||
off. The global alerts switch and the agent alert-type switch stop `CheckHost`
|
||||
without changing the policy.
|
||||
|
||||
@@ -6799,12 +6799,18 @@ judges the current reading, with no memory of an alert. A disk temperature
|
||||
alert held between its clear value and trigger shows an amber Temp cell, not
|
||||
`Running Hot`. A switched-off agent Disk Temp default resolves to null, which
|
||||
leaves the reading uncoloured and never hot, as alerting is off for it.
|
||||
Two cases stay on the per-type trigger in the browser while alerts and Patrol
|
||||
apply the override: on the Storage page, a disk whose agent an operator
|
||||
manually linked into a VM (the page loads agents and pools, not guests; the
|
||||
guest drawer applies it), and an override an agent inherits from a guest it is
|
||||
linked to without a merge, because agent link hints are not published to the
|
||||
browser. PDF performance
|
||||
The browser rebuilds that chain from what it loads, so it can differ from
|
||||
alerts and Patrol, which read the agent's own link hints and resolve every key
|
||||
to its canonical resource. On the Storage page, a disk whose agent an operator
|
||||
manually linked into a VM keeps the per-type trigger, because the page loads
|
||||
agents and pools, not guests. An override the agent inherits from a node or
|
||||
guest it is linked to without a merge, or one stored under that node's own
|
||||
canonical resource ID, does not reach the browser, because agent link hints
|
||||
are not published. The guest drawer applies the guest's own override keys,
|
||||
which `CheckHost` reads only when the agent is also linked to that guest
|
||||
automatically. Overrides set on the reporting agent's own row, or on the node
|
||||
or guest it is merged with, reach the browser through the keys above. PDF
|
||||
performance
|
||||
reports colour a disk reading by the same per-type thresholds, which
|
||||
`reporting.DiskInfo` carries.
|
||||
`frontend-modern/src/features/storageBackups/__tests__/diskPresentation.test.ts`
|
||||
|
||||
@@ -1448,18 +1448,23 @@ func TestDiskTemperatureThresholdMatchesCheckHostPolicy(t *testing.T) {
|
||||
|
||||
// HostDiskTemperatureThreshold is the disk heat policy for a disk a host agent
|
||||
// reports, so it must agree with CheckHost on every host-level override: an
|
||||
// explicit Disk Temp override on the host, or inherited from its linked node,
|
||||
// replaces the per-type entry; the first override in the chain decides even
|
||||
// when it sets no Disk Temp; and a host whose alerts are off judges no heat.
|
||||
// explicit Disk Temp override on the host (or the canonical resource its ID
|
||||
// resolves to), or inherited from its linked node or guest, replaces the
|
||||
// per-type entry; the first override in the chain decides even when it sets no
|
||||
// Disk Temp; and a host whose alerts are off judges no heat.
|
||||
func TestHostDiskTemperatureThresholdMatchesCheckHostOverrides(t *testing.T) {
|
||||
const hostID = "host-temp-policy"
|
||||
const nodeID = "pve1-node1"
|
||||
const vmID = "pve1-node1-105"
|
||||
const canonicalID = "agent-canonical-temp-policy"
|
||||
perType := &HysteresisThreshold{Trigger: 70, Clear: 65}
|
||||
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
overrides map[string]ThresholdConfig
|
||||
linkNode bool
|
||||
linkVM bool
|
||||
canonical bool
|
||||
want *HysteresisThreshold
|
||||
off bool
|
||||
}{
|
||||
@@ -1489,6 +1494,24 @@ func TestHostDiskTemperatureThresholdMatchesCheckHostOverrides(t *testing.T) {
|
||||
linkNode: true,
|
||||
want: perType,
|
||||
},
|
||||
{
|
||||
// The agent ID resolves to the machine's canonical resource ID.
|
||||
name: "canonical machine disk temp override",
|
||||
overrides: map[string]ThresholdConfig{canonicalID: {DiskTemperature: &HysteresisThreshold{Trigger: 82, Clear: 77}}},
|
||||
canonical: true,
|
||||
want: &HysteresisThreshold{Trigger: 82, Clear: 77},
|
||||
},
|
||||
{
|
||||
name: "linked guest disk temp override",
|
||||
overrides: map[string]ThresholdConfig{vmID: {DiskTemperature: &HysteresisThreshold{Trigger: 76, Clear: 71}}},
|
||||
linkVM: true,
|
||||
want: &HysteresisThreshold{Trigger: 76, Clear: 71},
|
||||
},
|
||||
{
|
||||
name: "linked guest alerts disabled",
|
||||
overrides: map[string]ThresholdConfig{vmID: {Disabled: true}},
|
||||
linkVM: true,
|
||||
},
|
||||
{
|
||||
name: "host disk temp switched off",
|
||||
overrides: map[string]ThresholdConfig{hostID: {DiskTemperature: &HysteresisThreshold{}}},
|
||||
@@ -1511,11 +1534,19 @@ func TestHostDiskTemperatureThresholdMatchesCheckHostOverrides(t *testing.T) {
|
||||
m.config.Overrides[id] = override
|
||||
}
|
||||
m.mu.Unlock()
|
||||
if tc.canonical {
|
||||
m.SetResourceIntentIdentityResolver(func(resourceID string) (string, bool) {
|
||||
return canonicalID, resourceID == hostID
|
||||
})
|
||||
}
|
||||
|
||||
owner := DiskTemperatureHost{ID: hostID}
|
||||
if tc.linkNode {
|
||||
owner.LinkedNodeID = nodeID
|
||||
}
|
||||
if tc.linkVM {
|
||||
owner.LinkedVMID = vmID
|
||||
}
|
||||
got := m.HostDiskTemperatureThreshold(owner, "nvme")
|
||||
switch {
|
||||
case tc.off:
|
||||
@@ -1529,6 +1560,7 @@ func TestHostDiskTemperatureThresholdMatchesCheckHostOverrides(t *testing.T) {
|
||||
check := func(temperature int) bool {
|
||||
host := hostWithSMARTDiskTemp(hostID, "nvme", temperature)
|
||||
host.LinkedNodeID = owner.LinkedNodeID
|
||||
host.LinkedVMID = owner.LinkedVMID
|
||||
m.CheckHost(host)
|
||||
_, exists := testLookupActiveAlert(t, m, hostDiskTempAlertID(host))
|
||||
return exists
|
||||
|
||||
Reference in New Issue
Block a user