562c0dfeb6
Part A (hub): move the global-floor + Day-0-artifacts cards from the Customers
page to the Configuration tab; routes → /configuration/{global-floor,artifacts};
redirects + flashes to /configuration. Customers page back to list + Add.
Part B: online setup command on the customer page (download-then-run, passphrase
at prompt, not templated); serve /scripts/ from the website (sparse-checkout +
nginx location) so felhom.eu/scripts/felhom-host-install.sh resolves; script
passphrase prompt reads < /dev/tty (works for pipe-to-bash too).
Part C (script): --vmid auto-detect — default 9201 in use + no --force → pick the
next free id from pct+qm and confirm; explicit --vmid stays die-unless-force.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
83 lines
6.3 KiB
Markdown
83 lines
6.3 KiB
Markdown
# Felhom scripts — Changelog
|
|
|
|
## felhom-host-install.sh v1.2.0 — /dev/tty passphrase read + vmid auto-detect (2026-07-01)
|
|
|
|
Two operator-experience fixes so a colleague can install online (via the hub's new "Option 1: Online
|
|
install" one-liner) and onto a host that already runs a guest at 9201.
|
|
|
|
- **Passphrase prompt reads from `/dev/tty`, not stdin** (`read_passphrase`). `read -rsp … < /dev/tty`
|
|
makes the no-echo prompt work regardless of how stdin is wired — both download-then-run **and**
|
|
`curl … | sudo bash` (where stdin is the pipe). Strictly more correct; the `--passphrase-file` path is
|
|
unchanged. The passphrase is still never on argv / in logs / in the state file.
|
|
- **VMID auto-detect (`--vmid` now optional-smart).** New `VMID_EXPLICIT` flag (set by `--vmid`). The
|
|
pre-flight vmid guard now determines "in use" against the **`pct list` + `qm list`** id-set (LXC and
|
|
VMs share the id space — more complete than the old `pct status`, which only knew LXC):
|
|
- **explicit `--vmid`** → unchanged deterministic behavior: die if the id is in use unless `--force`
|
|
(destructive over-provision).
|
|
- **default 9201, in use, no `--force`** → **auto-pick the next free id** (scan upward from 9201 over
|
|
the used-set) and **ask to confirm** from the terminal (`read … < /dev/tty`, `[y/N]`); proceed on
|
|
yes, `die "no free vmid confirmed"` otherwise. Never a silent auto-pick.
|
|
- **default 9201 + `--force`** → over-provision 9201 (destructive) without prompting, as before.
|
|
- New helpers `used_vmids` / `_vmid_in_use` / `next_free_vmid`. `--vmid` help text + `usage()` updated.
|
|
|
|
## felhom-host-install.sh v1.1.0 — self-install the agent + fetch the golden from Gitea (2026-06-28)
|
|
|
|
The script now **installs the agent itself** (the last big manual Day-0 prerequisite is gone). It
|
|
fetches the agent binary + golden from Gitea generic packages and **verifies each against the
|
|
hub-vouched artifact manifest** before installing/using it. BUNDLE slice; pairs with hub v0.16.0
|
|
(artifact manifest endpoint + operator UI) and felhom-agent v0.43.0 (canonical unit + publish).
|
|
|
|
- **New step `5/8 agent install`** (before agent-config): resolves the manifest
|
|
(`GET /api/v1/artifacts/{id}`, passphrase) + the git fetch token (from the customer's
|
|
`controller.yaml` via config-retrieve — **NO new credential**); fetches
|
|
`/api/packages/admin/generic/felhom-agent/<ver>/felhom-agent`, **verifies sha256 vs the hub
|
|
manifest** (aborts on mismatch — verify-before-use), backs up any existing binary, installs
|
|
`0755 /usr/local/bin/felhom-agent`; ensures the non-root `felhom-agent` system user; installs the
|
|
canonical sudoers (`0440`, `visudo -cf`-validated) + systemd unit; `daemon-reload` + enable. Idempotent:
|
|
same version already installed + service active → skip.
|
|
- **`--skip-provision`:** install + configure + verify the agent (incl. golden fetch+verify) but do NOT
|
|
provision a guest — the agent-only path for re-installing/upgrading the agent on a host that already
|
|
has live guests. Adds an agent-only `step_verify_agent` (binary + non-root service active + a
|
|
`--selftest=hub` collect-report).
|
|
- **New step `7/8 golden`:** local auto-discovery stays the default/fallback; otherwise fetches
|
|
`/api/packages/admin/generic/felhom-golden/<ver>/golden.tar.zst`, **verifies sha256**, and imports it
|
|
into the archive storage's dump dir for the restore. `--force-gitea-golden` forces the Gitea path.
|
|
- **Non-root agent model:** the agent now runs as `felhom-agent` with `privileged.mode: "sudo"` (was the
|
|
dev/CI `direct`+root shortcut). The config is `chown`ed to the service user (0600) so the daemon can
|
|
read it; `systemctl is-active` after restart is the real proof the non-root user can read the config.
|
|
- **Pre-flight relaxed:** a missing agent binary is no longer fatal (step 5 installs it); the local
|
|
golden requirement is deferred to step 7.
|
|
- **Trust model:** checksum **trust root = the hub** (manifest), not Gitea; the fetch credential is the
|
|
existing config-retrieve git token; artifacts are pinned to a version (never `:latest`).
|
|
- **Secrets:** the git token is a never-logged runtime carrier (cleared on EXIT alongside the passphrase
|
|
/ pve-token / hub api_key); the sudoers is `0440` and `visudo -cf`-validated before install.
|
|
- `bash -n` + `shellcheck` clean.
|
|
|
|
## felhom-host-install.sh v1.0.0 — Day-0 host bootstrap (provision mode) (2026-06-26)
|
|
|
|
First release. A single operator-run script that automates Day-0 on a freshly-PVE-installed
|
|
host: Proxmox API token → hub host enrollment (option C, single secret) → agent config →
|
|
guest provision → verify. Composes proven mechanisms (the `pveum` role/token sequence, hub
|
|
`POST /host-enroll`, `felhom-agent --selftest=provision`); grounded by
|
|
`documentation/audits/SPIKE-day0-firstboot-handshake-2026-06-26.md`.
|
|
|
|
- **7 steps, idempotent + resumable** via `/var/lib/felhom-install/state.json`: pre-flight →
|
|
Proxmox token → compute grows → host-enroll → agent config → provision → verify.
|
|
- **Single-secret** (the retrieval passphrase): read no-echo or from a 0600 file, never on
|
|
argv/logs/state. The global operator key never touches the box.
|
|
- **pveum automation:** 16-priv `FelhomAgent` role (create-or-modify), `felhom-agent@pve` user,
|
|
privsep token (reuse-if-working else rotate), and **both** ACL grants applied **after** the
|
|
token exists (token-remove purges the token ACL).
|
|
- **Auto-discovery:** golden archive (newest `vzdump-lxc-<golden-vmid>`), PVE node name, vmbr0
|
|
bridge IP for the local-api, and the served-leaf TLS fingerprint pin.
|
|
- **Safety:** pre-flight fails fast (root, PVE 9.x, local-lvm headroom, hub reachable,
|
|
customer+passphrase valid via read-only `GET /config/{id}`, golden resolvable); refuses to
|
|
clobber an existing `--vmid` without `--force`; `--dry-run` previews every mutation;
|
|
`--preserve-from` keeps operator infra (PBS/local_api/privileged/authz) on re-deploys.
|
|
- **`--mode dr`:** documented 10D stub (restore customer PBS snapshot instead of golden) — not
|
|
implemented.
|
|
- **Live-validated** end-to-end on `felhom-pve`: authorized wipe of demo guest 9201 →
|
|
re-provision from the golden → controller config-pull + public tunnel `HTTP 200` →
|
|
host-report of guest 9201 → idempotent `--resume` no-op. (One ordering bug — token ACL
|
|
applied before rotation — was found and fixed during the live run.)
|