Files
felhom.eu/REPORT-ep0-datastore-volume-2026-07-27.md
T
admin 2b24c70536 docs(ep0): hub PBS-DR capacity gauge verified correct after the volume move
The last open item from the datastore relocation. Hub operator UI
(Offsite -> PBS DR) reports felhom-offsite (ep0) at 97.9 GB capacity,
12.6 GB used, 13% full - agreeing with the on-box df (98 G / 13 G / 13%).

The gauge follows the datastore's CONFIGURED PATH, so the relocation
required no hub-side change. RUNBOOK section 10.3 warned that a stale
37.2 GB reading would mean the gauge reads the wrong filesystem and
would be a real bug worth a roadmap item - it does not, and there is
no bug.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018ARoadHBf8rHoscfiqeVZn
2026-07-27 09:39:44 +02:00

5.4 KiB
Raw Blame History

REPORT — ep0 PBS datastore relocated onto the 100 GB volume (2026-07-27)

Class: supervised operational run (RUNBOOK execution). No code changed. No version bump. Written as REPORT-<topic>.md per the parallel-session rule — the shared REPORT.md was not touched.

Full record with all evidence: documentation/runbooks/RUNBOOK-ep0-datastore-volume-2026-07-27.md


Outcome: DONE and verified

felhom-offsite now lives on a dedicated 100 GB Hetzner Cloud Volume instead of ep0's 40 GB root disk.

Before After
Path /srv/pbs-felhom (root disk) /mnt/pbs-datastore (volume)
Datastore total 37.2 GB 98 GB (hub gauge: 97.9 GB)
Used 28.9 % 13 % (hub gauge: 12.6 GB, 13 %)
Headroom to the 80 % warn 19 GB ≈65 GB
Additional customers before warn ≈2 ≈713

Datastore name unchanged — the PBS-DR descriptors, per-box storage ids, ACLs and namespace layout that R-39/R-82 made self-healing are untouched.

Window: 06:58 → 07:19 UTC (PBS down 07:00 → 07:17). Nothing was deleted.

Acceptance evidence

Gate Result
Copy integrity 13,242,207,822 = 13,242,207,822 B · 9,748 = 9,748 chunks · 7 = 7 snapshots · backup:backup · itemised dry-run 0 lines
Snapshot counts per ns demo-felhom 2=2, demo-felhom-01 3=3, demo-hp 2=2
atime semantics rw,relatime,discardrelatime present, noatime absent (GC correctness)
Verify job TASK OK, 3/3 groups, forced re-verification of every snapshot, 0 errors
§6 mount guard refusal observedJob … failed with result 'dependency'; mountpoint stayed empty
§8 restore round-trip source_tier: pbs, pass: true, mount_parity: ok, clean teardown, 12m1s

Three findings the operator should act on

  1. scratch datastore is configured at a path that does not exist (/srv/pbs-scratch). Pre-existing, not caused here, but now logs ENOENT on every PBS start. This is the PRIME RISK shape ("reports fine, is not there") already live in the config. Decision needed: remove the stanza or create the directory.

  2. The runbook's §6 acceptance test proves the wrong proposition. RequiresMountsFor is a mount-first ordering guarantee, not a refusal — systemd silently re-mounts an unmounted volume and PBS then starts safely. The test only bites when the device is genuinely unavailable, which is how it was re-run and passed. Amendment recommended in the runbook record.

  3. §11 — storage box u629193 is NOT simply unused. No live backup path references it (no datastore, no restic repo, no fstab, no known_hosts pin; R-17 already deleted u629193-sub1), but ep0 carries an enabled, currently-mounted sshfs unit mnt-pbs\x2dstoragebox.mount/mnt/pbs-storagebox, holding spike leftovers. Disable and remove that unit before deleting the box, or ep0 logs a failed mount every boot. The deletion is the operator's console click.

Deviations from the runbook as written

  • The volume arrived already formatted and mounted by Hetzner at /mnt/HC_Volume_106469259 (§2 assumed neither). Operator ruled: reformat + repath. The 5 % reserve was reclaimed (-m 0).
  • §8 ran on demo-felhom, not demo-hp — DooPlex holds no SSH key for demo-hp (the G1 gap). Same tier, same relocated datastore, larger archive.
  • The window was contended by a stale 10-minute restore-test cadence on demo-felhom: the config had already been reverted to 3.5 days on disk, but the cadence is read once at daemon start and NRestarts=0. Restarting the agent applied it (cadence=84h0m0s). The in-flight test was allowed to finish rather than aborted.

Process errors made during this run (recorded deliberately)

  • rsync -aHAX OOM-killed ep0 (3.7 GB RAM, no swap). Cause: a PBS .chunks/ tree pre-creates all 65536 shard dirs → 75,341 inodes, and -H retains the whole inode map. -H was dropped only after proving no hardlinks exist (-links +1 → 0; max link count → 1); PBS references chunks by digest, never by hardlink.
  • /usr/bin/time -v is not installed on ep0 → exit 127, rsync never ran, and a | grep … || true wrapper swallowed it while printing a success-looking line.
  • rsync --version | head -1 reported a working rsync 3.4.1 as "missing" — the §12 pipe-into-head trap, fourth recorded instance in this project. Both fixed by capturing the command's own $?.

Deferred

  1. Old copy retained at /srv/pbs-felhom (13 GB, 9,748 chunks) as the rollback. Rollback is a two-line datastore.cfg revert. Reclaim only after a new weekly offsite backup lands on the volume, with explicit go-ahead.
  2. GC not run — now unblocked by the round-trip, but left for a separate deliberate run. No GC schedule is configured on this PBS at all.
  3. Hub PBS-DR capacity gauge not re-read. CLOSED — verified correct. The hub operator UI (Offsite → PBS DR) reports felhom-offsite (ep0) at 97.9 GB capacity, 12.6 GB used, 13 % full, agreeing with the on-box df. The gauge follows the datastore's configured path, so the move needed no hub-side change and the suspected "wrong filesystem" bug does not exist.
  4. ep0 has no swap (temporary 4 GB file removed; box left as found). Worth a small permanent swapfile — outside this runbook's scope.