diff options
| author | Tim Keller <tjk@tjkeller.xyz> | 2026-09-02 11:22:36 -0500 |
|---|---|---|
| committer | Tim Keller <tjk@tjkeller.xyz> | 2026-09-02 11:22:36 -0500 |
| commit | a74c2877571afbfd04584b8821c754e9050b9e72 (patch) | |
| tree | 2296d2d49285d2d2bd55e641f46bb3387c861108 /README.md | |
| parent | fe770e9f386e091dbca7cf587cfe0131f10bd728 (diff) | |
| download | telemetry-flake-a74c2877571afbfd04584b8821c754e9050b9e72.tar.xz telemetry-flake-a74c2877571afbfd04584b8821c754e9050b9e72.zip | |
fix drive rows surviving a drive replacement
The repeated per-drive sections are driven by $ata_device/$sas_device, which
were label_values(smartctl:row{...}, row). label_values resolves against
/api/v1/label/<l>/values over the *dashboard's* time range -- 24h by default --
so it returns every row line seen in that window, not the ones that exist now.
Replace a drive and the window still holds the line the old drive produced.
Both lines carry the same variable value, because the regex reduces them to the
bare device name that the panels select on, and Grafana's
metricNamesToVariableValues ends in uniqBy(options, 'value'), which keeps
whichever series Prometheus returned first. The dashboard then renders one row
headed with the removed drive's model and serial, no row for its replacement,
and panels underneath showing the new drive's numbers.
query_result() is the only variable form the Prometheus datasource evaluates as
an instant query (metric_find_query.ts: queryResultQuery hits /api/v1/query at
range.to), so switch both device variables to it and re-anchor the regex on the
row= label in the line Grafana renders for a vector result.
Verified against a real Prometheus loading rules/smartctl.yml, with a fixture
that replaces a SAS drive and a SATA drive in place: the old form headed sde
with OLDBAD99 and sdz with the 870 EVO it no longer contains, the new form
lists exactly the drives in the machine.
The host variable deliberately stays on label_values -- its window covering the
time range is what keeps an unreachable machine selectable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JKczN1f66kmLxNBLX37voQ
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 14 |
1 files changed, 14 insertions, 0 deletions
@@ -366,6 +366,20 @@ inventing placeholder values. SCSI from the Background Scan Results log page, which is not the drive's lifetime meter and often reads far too low. Drive Health takes the larger of that and the lifetime stamp in the drive's own self-test log — so it can exceed what `smartctl -x` prints. +- **Swap a drive and the identity in its row header may lag.** The header comes from + `smart_drive_label`, written by the self-test collector on a 15 minute timer, so a + replacement shows the removed drive's model and serial until the next run. It is only + *stuck* if the unit is failing — the collector rewrites the whole file atomically, so a + crash leaves the previous one in place indefinitely. Check with + `systemctl status smart-selftest-collector.service`, and `systemctl start` it to refresh + immediately. +- **The per-drive sections list the drives that are there *now*.** `$ata_device` and + `$sas_device` are instant queries rather than `label_values`, so removed drives stop + getting a row instead of lingering for the dashboard's whole time range — see the + comment on `DEVICE_QUERY` in `dashboards/gen_smart.py`. The trade is that they need a + sample within Prometheus' 5 minute lookback: when a machine has been unreachable longer + than that, its sections disappear rather than rendering empty. Fleet Overview and the + history graphs still work, because they read the range. - **IPv6 literals need help.** The `host` label is built by stripping the port off `__address__` with `([^:]+)(?::[0-9]+)?`, which a bracketed IPv6 address does not match. Use `prometheus.extraScrapeConfigs` with an explicit label for those. |
