mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-10-27 14:07:31 +00:00
4faba67f66
## What
A merged physical disk that the operator splits ("Split merged
resource", `POST /api/resources/{id}/report-merge`) now stays split for
the PVE disk poller too. #2748 made the registry honour the exclusions
and listed the poller as the part of the split it did not reach:
`mergeHostAgentSMARTIntoDisks` paired the linked agent's SMART row with
the Proxmox disk by WWN, serial or path before the registry saw either,
and read no exclusions. The split Proxmox row kept the agent's
attributes, I/O, health, any serial, WWN, type or temperature it filled,
and `AgentSMARTReported`, which hands the disk's temperature alert to
the agent's `CheckHost`.
## How
- `mergeHostAgentSMARTIntoDisks` asks the resource store
(`MonitorAdapter.ProxmoxDiskAgentSMARTSplit`, new
`internal/unifiedresources/physical_disk_agent_split.go`) once per
matched row, on the full poll and on the skipped polls between. The
answer is `physicalDiskSplitLocked`'s, applied to the agent's disk as
the registry generation holds it and to the Proxmox observation under
its own ID, so the exclusions that keep the registry's rows apart keep
the poller's pair apart, in the same forms:
- an exclusion naming only the agent's candidate splits nothing;
- a replacement disk in the slot inherits no split recorded against the
disk it replaced;
- a manual link that leaves the generation holding both observations as
one disk is the operator's later decision, so the poller pairs them
again.
- A split disk takes nothing from the row: no attributes, I/O, health,
identity, type or temperature, and no `AgentSMARTReported`. It also
takes no agent-supplied node-sensor temperature: the node poll takes the
node's SMART list from the linked agent while the agent is reporting and
its report carries a usable temperature, so `mergeNVMeTempsIntoDisks`
would otherwise hand the agent's row of the other disk to the split one
and the PVE check would alert beside the agent's own alert. An
SSH-supplied reading stays, and the PVE disk check judges it.
- The record is marked `AgentSMARTSplit` (internal poll evidence, never
serialized), so the poll's evidence retention restores nothing into it.
- The Proxmox-query-failure fallback (`physicalDisksFromHostAgentSMART`)
gives a split row no stand-in.
## Limits (named in the unified-resources contract)
- The split applies on the first full disk poll that collects the node
from Proxmox and matches the agent's row; a record already merged keeps
the agent's data until then (five minutes by default).
- A split disk retains no last-known serial or ZFS pool through a poll
that cannot collect them: nothing records which retained value Proxmox
collected and which the agent filled.
- While the Proxmox query fails, a split disk's Proxmox record is not
listed (its stand-in would be the agent's disk again).
- The query-failure fallback judges its stand-in row by the row's own
identity, so it does not apply a split that names identity only the
Proxmox disk carries (an agent disk in standby).
- A split recorded under one key of a controller member (the stand-in's
target-qualified key against a Proxmox poll's device-only key) names an
observation the other key's rows do not carry, as for the registry.
## Verification
- `TestOperatorSplitKeepsAgentSMARTOffTheProxmoxDisk` drives the poller
through four report-merge shapes (both candidates, the Proxmox candidate
alone, the agent's candidate alone, an unrelated exclusion) for three
disks (SAS paired by path, NVMe paired by serial, NVMe whose node
reading is SSH-supplied), on full and skipped polls, with an open PVE
temperature alert that the pairing closes and the split does not bring
back, the health alert the agent's failure raised, and a failing Proxmox
disk query.
- Unit tests pin the merge (including Proxmox's own health and wearout,
fields the agent must not copy, and the own-ID rule for controller
members), the fallback, the node-sensor drop and the source labels it
relies on. `TestOperatorSplitSeparatesDisksJoinedInsideALinkedHost` also
asks the decider at each step (relink, standby, replacement, a
generation that has not ingested the agent's disk).
- Negative controls, one mutation per rule (18), each turned a named
test red; the full `internal/models`, `internal/unifiedresources` and
`internal/monitoring` suites ran on pulse-dev against the merged tree.
`TestGuestWindowsMeminfoPollingContract` failed once in a loaded full
run and also fails on pristine `main` under the same load (it passes
alone on this branch), so it is not part of this change.