770ee5a5f6
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.
153 lines
8.8 KiB
Markdown
153 lines
8.8 KiB
Markdown
# 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.
|