docs: SPIKE — SMART coverage on real hw (why the card shows Nincs adat); findings-only

Read-only probes on demo-felhom: both disks (system SSD /dev/sda, USB /dev/sdb) report
PASSED via the exact allowlisted 'smartctl -a -j <dev>'. Card shows Nincs adat because the
agent never reads: 'local' is a dir on LVM pve-root (backing='' + smartDeviceFor has no
dm/LVM branch), and the USB is surfaced via the non-enriched driveTargets.Known union path.
-d sat NOT needed (bridge passes SMART through; sudoers grants only -a -j). Graded fix
directions B(low-risk, USB) > A(system SSD, medium) > C(reject). STOP — no fix implemented.
This commit is contained in:
2026-07-25 07:56:02 +02:00
parent e49f20f581
commit 770ee5a5f6
@@ -0,0 +1,152 @@
# SPIKE — why the v0.169.0 disk-health card shows "Nincs adat" on real hardware, 2026-07-25
**Question:** the new "Lemezek állapota" card (controller v0.169.x) renders **Nincs adat** for both
physical disks on the live demo host (`demo-felhom`, a real N100 — NOT virtualized). Is SMART actually
unavailable on this hardware, or does the agent fail to *read* SMART it could read? If the latter,
where, and what are the fix directions?
**Verdict up front:** SMART is **fully available** on both disks via the *exact* form the sudoers
allowlist already grants (`smartctl -a -j <whole-disk>`) — the system SSD and the USB HDD both report
**PASSED**. The card says "Nincs adat" because the **agent never asks**, for two independent reasons:
1. **`local` (the system SSD) → UNKNOWN:** its storage is a `dir` on `pve-root`, an **LVM logical
volume on `sda3`**. The agent leaves `backing_device` empty for it, and even if it didn't,
`smartDeviceFor` has **no device-mapper/LVM handling** — so the dir → LV → PV → whole-disk (`/dev/sda`)
chain is never resolved and `enrich` skips the SMART read.
2. **The USB HDD (`/dev/sdb`) → ABSENT:** it is surfaced only via the **`driveTargets.Known` union path**
in `handleDisks`, which sets `backing_device=/dev/sdb` but **never calls `enrich`** (no SMART read at
all) → the target's `Smart.Health` stays `""` → the controller (correctly) omits it → "Nincs adat".
**Neither disk needs `smartctl -d sat`** — the USB-SATA bridge passes SMART through with plain
`-a -j`. The `-d sat` candidate is **disproven on this hardware**, and the sudoers allowlist does not
grant it anyway (recorded below). **This is findings-only — no fix implemented; the fix gets its own spec.**
---
## Topology (Probe 1 — `lsblk -o NAME,TYPE,TRAN,MOUNTPOINT,MODEL`)
```
NAME TYPE TRAN MOUNTPOINT MODEL
sda disk sata AirDisk 512GB SSD
|-sda1 part
|-sda2 part /boot/efi
`-sda3 part (LVM PV)
|-pve-swap lvm [SWAP]
|-pve-root lvm / ← the "local" dir storage
`-pve-data-tpool … lvm ← pve-data thin pool (VM disks 9201)
sdb disk usb /mnt/hdd_1 TOSHIBA MQ04ABF100 ← the USB data drive
```
The customer's OS **and** every VM disk live on **`sda`** (SATA SSD, via LVM). The data drive is
**`sdb`** (USB). Both are real, SMART-capable disks.
## The `/disks` payload (Probe 2 — controller-side curl to the agent localapi)
```
local-lvm | type=lvmthin | backing='' | mount='' | smart=UNKNOWN
local | type=local | backing='' | mount='' | smart=UNKNOWN
felhom-pbs | type=pbs | backing='' | mount='' | smart=UNKNOWN
47a3361a-… | type=usb | backing='/dev/sdb' | mount='/mnt/hdd_1' | smart=ABSENT
```
(The controller v0.169.1 already excludes `pbs`/`lvmthin` from the card, so only `local` and the USB
render — both "Nincs adat".)
## Backing-path resolution (Probe 3 — `readlink -f`)
```
readlink -f /dev/sdb → /dev/sdb (already a clean whole-disk path; NOT a symlink)
readlink -f /dev/sda → /dev/sda
/dev/disk/by-uuid/47a3361a-… → ../../sdb (the durable_id's symlink; the payload already carries the resolved /dev/sdb)
```
**The "USB backing is a `by-uuid` symlink the regex can't match" hypothesis does NOT apply here**
the payload's `backing_device` is already the resolved `/dev/sdb`.
## SMART actually works on both (Probe 4 — the EXACT allowlisted form)
```
# smartctl -a -j /dev/sda (system SSD)
model: AirDisk 512GB SSD
smart_status.passed: True
messages: []
# smartctl -a -j /dev/sdb (USB TOSHIBA, behind its USB-SATA bridge)
model: TOSHIBA MQ04ABF100
smart_status.passed: True
messages: ['Warning: This result is based on an Attribute check.']
```
Both return **PASSED** with the plain `-a -j` form — **no `-d sat` needed**. (The USB result is
attribute-based, which is normal for a HDD behind a bridge; still a valid PASSED verdict.)
## Sudoers / capability-manifest (Part 5.4 recording)
- `capability/manifest.go:94` probes with `{"/usr/sbin/smartctl", ["-a","-j","/dev/sda"]}`.
- `/etc/sudoers.d/felhom-agent` grants **only** the `-a -j` form:
```
/usr/sbin/smartctl -a -j /dev/sd[a-z]*,
/usr/sbin/smartctl -a -j /dev/nvme[0-9]*n[0-9]*,
/usr/sbin/smartctl -a -j /dev/vd[a-z]*,
/usr/sbin/smartctl -a -j /dev/hd[a-z]*,
```
→ `/dev/sda` **and** `/dev/sdb` are both permitted (the agent CAN read both today). **`-d sat` is
NOT granted** — a `-d sat` invocation would be denied by sudoers, so any `-d sat` fix needs a
sudoers **and** manifest widening.
## Per-disk table — why the card says what it says
| storage | backing (payload) | whole disk | `smartctl -a -j` | agent read path | card | root cause |
|---|---|---|---|---|---|---|
| `local` (dir/`pve-root`) | `''` | `sda` (via `/`→`pve-root`→`sda3`, **unresolved**) | **PASSED** | `enrich`: `catDir` but `backing_device==''` → SMART skipped | Nincs adat (UNKNOWN) | dir-on-LVM backing never resolved; `smartDeviceFor` has no dm/LVM branch |
| USB `47a3361a` | `/dev/sdb` | `sdb` | **PASSED** | `driveTargets.Known` union path — **`enrich` never called** | Nincs adat (ABSENT) | union path sets `backing` but runs no SMART read; `smartDeviceFor('/dev/sdb')` *would* resolve it |
| `felhom-pbs` / `local-lvm` | `''` | — (logical/network) | n/a | not `catDir` | (excluded, v0.169.1) | correct — not physical disks |
`smartDeviceFor` (source): maps `…/nvme0n1pN → …/nvme0n1` and `…/sdbN → …/sdb`, then
`ValidateSMARTDevice`. A **whole disk** `/dev/sdb` passes through unchanged and validates → it would
resolve fine if `enrich` were ever called on the union path. **There is no branch for `/dev/mapper/*`
or `/dev/dm-*`,** which is why an LVM-backed dir can never resolve.
---
## Fix directions (graded — DO NOT IMPLEMENT; each needs its own spec)
### A — Resolve dm/LVM → whole disk (reaches the SYSTEM SSD `local`)
Resolve the dir's mount → LV → PV → whole disk (e.g. `lsblk -s -no pkname <dev>`, or
`/sys/block/dm-*/slaves`), set `backing_device` accordingly, and add a **dm/LVM branch to
`smartDeviceFor`**.
- **Reach: HIGH** — the system SSD holds the OS *and* all VM data; it is the single most important disk
to monitor. Also covers any other dir-on-LVM storage.
- **Risk: MEDIUM** — an LVM VG can span **multiple** PVs (a dir → N disks, not one); the resolver must
handle the multi-slave/RAID case (probe each, report per-disk) rather than assume one. Must not
mis-resolve stacked dm (thin pools). Needs a focused test over single-PV and multi-PV shapes.
### B — Enrich the `driveTargets.Known` union path (reaches the USB / felhom data drives)
Run the same SMART read on `handleDisks`' union branch when `backing_device != ""`.
- **Reach: GOOD** — the felhom-enrolled *data* drives (the USB here), which is exactly what a customer
cares about most for a health card.
- **Risk: LOW** — the backing path is already a clean whole disk, `smartDeviceFor` already resolves it,
and sudoers already grants `/dev/sd[a-z]*`. Care points: the union path lives in `localapi` while
`enrich`/`SMART` lives in `storage` (reuse the `o.ops.SMART` seam or a small helper, no duplication),
and don't pay smartctl on *every* `/disks` call — the controller's 60s TTL cache already blunts the
storm, but consider a short agent-side memo if `/disks` is hit hard. **Cheapest win; do this first.**
### C — `smartctl -d sat` retry (+ sudoers/manifest widening) — REJECT for now
- **Reach: NONE on this hardware** — the USB bridge already returns PASSED with plain `-a -j`
(disproven above). Would only matter for a *future* bridge that yields UNKNOWN with `-a -j`.
- **Risk: HIGH-relative** — requires adding `smartctl -d sat -a -j /dev/sd[a-z]*` (+ nvme/vd/hd) to
**both** `/etc/sudoers.d/felhom-agent` and `capability/manifest.go` (widening the root-command
allowlist — a privilege-surface change), plus a retry loop. **Keep as a documented fallback**, gated
on an actual UNKNOWN-with-`-a -j` disk appearing in the field.
### D (minor) — `EvalSymlinks` before the partition regex
Not needed here (`backing_device` is already `/dev/sdb`), but cheap insurance for a future payload that
carries a `/dev/disk/by-*` symlink. **Low priority**, fold into A/B if convenient.
**Recommended order (for the follow-up spec):** **B** (low-risk, covers the data drive) → **A**
(higher value, medium risk, covers the system disk) → skip **C** until a bridge demands it.
---
**STOP.** No agent code, sudoers, or capability-manifest change was made in this spike (read-only
probes only). The fix is a separate task.