Operator-run Day-0 automation for a fresh PVE host: pveum token -> hub POST /host-enroll (single secret, option C) -> agent config -> felhom-agent --selftest=provision -> verify. Idempotent/resumable (state.json), --dry-run, --resume, --force, --preserve-from; --mode dr is a documented 10D stub. Live-validated on felhom-pve: authorized wipe of demo guest 9201 + full re-provision from the golden -> controller config-pull + public tunnel HTTP 200 + host-report of 9201; idempotent --resume no-op. Found+fixed one ordering bug during the run (token ACL must be applied AFTER token rotation — token-remove purges the ACL). Adds scripts/README.md (operator runbook) + scripts/CHANGELOG.md; REPORT overwritten; spike doc pointer added. No service code changed. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TtXesNa2LGbMmE4DNL6SE7
7.2 KiB
felhom.eu — task reports
Overwrite this file with a summary of the most recent task only (uniform with the other repos; not cumulative). The cumulative hub history lives in hub/CHANGELOG.md.
Day-0 host-bootstrap script — built + live wipe-and-provision test — 2026-06-26
Task: Deliver scripts/felhom-host-install.sh (operator-run Day-0 bootstrap) and validate it with
an operator-authorized destructive live test: wipe demo guest 9201 and re-provision it from scratch
via the script. Single repo (felhom.eu, new scripts/).
Confirmed baselines
- hub
1539746v0.14.0 (/host-enrolloption C, just shipped) · felhom-agent4725396v0.41.0 (--selftest=provision) · felhom-controllere0cf78bv0.84.0. - Live host
felhom-pve(192.168.0.162): PVE 9.2.2, nodedemo-felhom, agent v0.41.0 at/root/.config/felhom-agent/agent.json(systemd unit-configpath — not/etc/felhom-agent/), goldenlocal:backup/vzdump-lxc-9100-2026_06_23-16_38_49.tar.zst(rootfs 32 / docker 16 / sysdata 8 GiB base).
Deliverable
scripts/felhom-host-install.shv1.0.0 — 7 idempotent/resumable steps (pre-flight → pveum token → grows → host-enroll → agent config → provision → verify), single-secret (passphrase no-echo/0600 file),--dry-run/--resume/--force/--preserve-from,--mode drdocumented stub.scripts/README.md(operator runbook),scripts/CHANGELOG.md(v1.0.0).documentation/audits/SPIKE-…-2026-06-26.md— pointer added (script ships the gap inventory).bash -npasses (Windows + host). shellcheck unavailable on dev box, build box, and felhom-pve — not run.
Live supervised test (felhom-pve, customer demo-felhom, authorized destructive)
Passphrase sourced operator-side from the hub DB into a 0600 file on the host (never printed); deleted (shredded) after. Methods noted per check.
A. Pre-wipe snapshot: saved pct config 9201, controller 0.84.0 Up (healthy), agent.json.bak
(1574 B), token list. Confirmed demo-felhom host exists in hub (demo-felhom-01, plus two stale
dr-drill-host* cruft rows — demo-felhom-01 has today's updated_at, so GetHostByCustomer returns it).
B. Wipe (authorized): pct stop 9201 + pct destroy 9201 --purge (all 3 volumes removed); moved
agent.json + cleared state to simulate a fresh host.
C. Dry-run: every mutating command printed correctly — pveum role-modify (16 privs), both ACL lines, token rotate, enroll curl, agent.json write, provision call. Pre-flight green (golden auto-found, passphrase valid, vmid free).
D. Real run — found + fixed a bug, then SUCCESS:
- Bug found live: first run failed the post-config agent selftest with
HTTP 403 … missing privilege Sys.Audit. Root cause: the script applied the token ACL before rotating the token, andpveum user token removepurges the token's ACL — so the new token had no ACL. Fix: apply both ACL grants after the token is (re)created. (scripts/felhom-host-install.shstep 2.) - Re-run green: token rotated (old config token failed selftest → rotate → ACL → selftest passed);
host-enroll→ 200 REUSE ofdemo-felhom-01(idempotency confirmed); agent.json written 0600 + read-only selftest passed + daemon restarted; provision front-half bring-up (1m11s) + back-half bootstrap mountmp9→/etc/felhom-bootstrap+ local-api token minted; guest 9201 running, onboot:1, layout rootfs 32G / mp0 200G / mp1 50G / mp8 bind — exactly the standard appliance.
E. Verify (method per check):
| Check | Method | Result |
|---|---|---|
| guest running + onboot:1 + volumes | pct status/config |
✅ running, onboot 1, 32/200/50G + mp8 bind |
| controller healthy | pct exec docker ps |
✅ Up (healthy), image felhom-controller:0.77.0 (from golden) |
| controller pulled config from hub | controller logs (pct exec) |
✅ bootstrap: pulled config from hub for demo-felhom, merged local_api … coming up configured; Hub connectivity … HTTP 200 |
| serving | pct exec curl :80 |
✅ HTTP 301 (traefik) |
| Cloudflare tunnel connected | cloudflared logs | ✅ 4 Registered tunnel connection (vie06, bud01) |
| public URL | curl from build box (public DNS) | ✅ felhom.demo-felhom.eu → HTTP 200 via Cloudflare 188.114.97.11 (ingress *.demo-felhom.eu → traefik) |
| real dashboard | curl public | ✅ <title>Vezérlőpult — Felhom.eu</title> |
| host-report includes guest 9201 | hub sqlite | ✅ demo-felhom-01/9201 status running, last_seen current |
| storage plane (functional touch) | pct exec ls |
✅ /mnt/felhom-drives bound, felhom-flash + felhom-usb visible (data intact); local-api drive plane reachable |
Public URL returned
000from felhom-pve and the Windows dev box — split-horizon (the agent's LAN resolver points*.demo-felhom.euat the guest's LAN IP, which serves:80not:443). Through the Cloudflare edge (build box) it is 200. Not a provision fault.
F. Idempotency: plain re-run refused to clobber the live 9201 (exit 1, "pass --force");
--resume re-run skipped token/grows/enroll/agent_config/provision → verify-only no-op, token
not rotated (selftest still passes), guest not re-provisioned.
G. Cleanup: passphrase file shredded; agent.json.bak + snapshot retained; final state — 9201
running, host_id demo-felhom-01, agent active.
pveum / token automation result
Role FelhomAgent normalised to the authoritative 16 privileges (incl. Sys.Audit, SDN.Use); user
felhom-agent@pve; privsep token rotated; both ACL grants (user and token) applied after token
creation. Read-only felhom-agent --selftest passed against the live API with the minted token.
Observations (out-of-scope — not acted on)
-hub-passwordon argv: the agent's only input for the retrieval passphrase during provision is the-hub-passwordflag → briefly visible inpsduring--selftest=provision. Candidate agent follow-up: accept it via env/stdin. (Not fixed here — would modify the agent.)- Golden freshness: the golden bakes controller 0.77.0; the freshly provisioned demo runs 0.77.0 (pre-wipe was 0.84.0, and the v0.78.0 drive-register stable-path fix is newer than the golden). Rebuild the golden at the current controller for parity; full drive re-enroll via the UI needs controller ≥0.78.0. The Day-0 script itself is version-agnostic.
- Multi-host cruft:
demo-felhomcarries two staledr-drill-host*rows.GetHostByCustomer(most-recent-updated) correctly returneddemo-felhom-01here, but the Day-0 invariant is one host per customer — drill artifacts should be cleaned up (left untouched; out of scope). - Serving + binary/golden delivery: the script lives in
scripts/; serving it athttps://felhom.eu/scripts/…, plus agent-binary and golden central delivery, are documented productionization hooks (the test used the local binary + golden).
Commits
<this commit>— script v1.0.0 + scripts/README + scripts/CHANGELOG + spike pointer + REPORT.
No secrets in any committed file. PVE-token secret + host api_key live only in the host's 0600 agent config.