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:
@@ -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.
|
||||
Reference in New Issue
Block a user