Go-live package: Day-0 install runbook + clean-room drill + host-install v1.9.1
- documentation/runbooks/day0-install.md (NEW): operator Day-0 guide, every command drill-executed verbatim (Parts A-F incl. the mandatory one-time controller update D.1b and the OQ-3 prereq checklist). - documentation/audits/DRILL-day0-cleanroom-2026-07-03.md (NEW): nested-PVE clean-room drill evidence D0-D6, residue tables, OQ-1/2/3 answers, findings ledger (B1-B5), go/no-go for Peti (GO). - scripts/felhom-host-install.sh v1.9.1: residue-free uninstall (agent config, shared-parent unit/script/mount, mkfs wrapper, hook snippet, dnsmasq snippets; zero-residue diff proven) + post-provision guest reboot (R6) + header/version sync. - CONTEXT.md, REPORT.md, scripts/CHANGELOG.md updated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
#===============================================================================
|
||||
# felhom-host-install.sh v1.8.0
|
||||
# felhom-host-install.sh v1.9.1
|
||||
# Day-0 host-bootstrap for a Felhom Proxmox host (operator-deploy model).
|
||||
#
|
||||
# Run by the operator on a FRESHLY-PVE-INSTALLED box (after a manual PVE install
|
||||
@@ -71,8 +71,9 @@
|
||||
#
|
||||
# Uninstall (local host teardown — no hub contact, no passphrase):
|
||||
# --uninstall cleanly revert an install: destroy the Felhom guest, remove the agent
|
||||
# (unit/sudoers/binary/state/user), the pveum role/user/token/ACL, and the
|
||||
# install state file. Guarded: refuses a non-Felhom guest (no
|
||||
# (unit/sudoers/binary/state/config/user + runtime artifacts: shared-parent
|
||||
# unit, mkfs wrapper, hook snippet, dnsmasq snippets), the pveum
|
||||
# role/user/token/ACL, and the install state file. Refuses a non-Felhom guest (no
|
||||
# /etc/felhom-bootstrap mount) and skips host-level removal if OTHER Felhom
|
||||
# guests remain (both overridable with --force). Typed vmid confirmation
|
||||
# required. Reuses --vmid (else the recorded provisioned_vmid), --force,
|
||||
@@ -104,7 +105,7 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_VERSION="1.9.0"
|
||||
SCRIPT_VERSION="1.9.1" # keep in sync with the header line at the top of this file
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
# Logging (mirrors felhom-controller/scripts/docker-setup.sh)
|
||||
@@ -211,7 +212,7 @@ ART_GOLDEN_SHA=""
|
||||
#-------------------------------------------------------------------------------
|
||||
# Helpers
|
||||
#-------------------------------------------------------------------------------
|
||||
usage() { sed -n '2,94p' "$0" | sed 's/^# \{0,1\}//'; exit 0; }
|
||||
usage() { sed -n '2,95p' "$0" | sed 's/^# \{0,1\}//'; exit 0; }
|
||||
|
||||
run() { # simple (no pipes/redirects) mutating command
|
||||
if $DRY_RUN; then log_dry "$*"; else "$@"; fi
|
||||
@@ -552,7 +553,15 @@ run_uninstall() {
|
||||
# ── host-level removal (reverse of install) ──────────────────────────────────────────────────
|
||||
log_step "host-level removal"
|
||||
|
||||
# 4. Agent removal — service, unit(+.bak), sudoers, binary(+.bak), state dir, user. NEVER `sudo`.
|
||||
# 4. Agent removal — service, unit(+.bak), sudoers, binary(+.bak), state dir, config, user.
|
||||
# NEVER `sudo`. Resolve the agent config path BEFORE the unit is removed (mirrors preflight —
|
||||
# the unit's -config arg is the truth, else the default); the config holds the per-host hub
|
||||
# api_key and must not survive an uninstall (drill finding R1).
|
||||
local agent_cfg=""
|
||||
if systemctl cat felhom-agent >/dev/null 2>&1; then
|
||||
agent_cfg=$(systemctl cat felhom-agent 2>/dev/null | grep -oP '(?<=-config )\S+' | head -1)
|
||||
fi
|
||||
[[ -n "$agent_cfg" ]] || agent_cfg="/etc/felhom-agent/agent.json"
|
||||
if systemctl list-unit-files felhom-agent.service >/dev/null 2>&1; then
|
||||
systemctl is-active --quiet felhom-agent 2>/dev/null && run systemctl stop felhom-agent
|
||||
systemctl is-enabled --quiet felhom-agent 2>/dev/null && run systemctl disable felhom-agent
|
||||
@@ -569,6 +578,36 @@ run_uninstall() {
|
||||
if [[ -d "$AGENT_STATE_DIR" ]]; then run rm -rf "$AGENT_STATE_DIR"; else log_skip " $AGENT_STATE_DIR already absent"; fi
|
||||
if id "$AGENT_USER" >/dev/null 2>&1; then run userdel "$AGENT_USER"; else log_skip " service user $AGENT_USER already absent"; fi
|
||||
|
||||
# 4b. Agent config (pve token + per-host hub api_key — secrets must not survive; drill R1).
|
||||
if [[ -f "$agent_cfg" ]]; then run rm -f "$agent_cfg"; else log_skip " $agent_cfg already absent"; fi
|
||||
run rmdir "$(dirname "$agent_cfg")" 2>/dev/null || true
|
||||
|
||||
# 4c. Shared-parent unit + wrapper + /mnt/felhom-drives (agent-installed at runtime; drill R2).
|
||||
# Stop/disable, remove unit + script, unbind + remove the (empty) parent dir. Tolerate-absent.
|
||||
if systemctl list-unit-files felhom-shared-parent.service 2>/dev/null | grep -q felhom-shared-parent; then
|
||||
systemctl is-active --quiet felhom-shared-parent 2>/dev/null && run systemctl stop felhom-shared-parent
|
||||
systemctl is-enabled --quiet felhom-shared-parent 2>/dev/null && run systemctl disable felhom-shared-parent
|
||||
else
|
||||
log_skip " felhom-shared-parent unit not loaded — skip stop/disable"
|
||||
fi
|
||||
if [[ -f /etc/systemd/system/felhom-shared-parent.service ]]; then run rm -f /etc/systemd/system/felhom-shared-parent.service; else log_skip " felhom-shared-parent.service already absent"; fi
|
||||
if [[ -f /usr/local/sbin/felhom-shared-parent.sh ]]; then run rm -f /usr/local/sbin/felhom-shared-parent.sh; fi
|
||||
run systemctl daemon-reload
|
||||
if mountpoint -q /mnt/felhom-drives 2>/dev/null; then run umount /mnt/felhom-drives; fi
|
||||
if [[ -d /mnt/felhom-drives ]]; then run rmdir /mnt/felhom-drives 2>/dev/null || true; fi
|
||||
|
||||
# 4d. Guarded-mkfs wrapper, guest-hook snippet, lan-resolver dnsmasq snippets (drill R3-R5).
|
||||
if [[ -f /usr/local/sbin/felhom-mkfs-guarded ]]; then run rm -f /usr/local/sbin/felhom-mkfs-guarded; else log_skip " felhom-mkfs-guarded already absent"; fi
|
||||
if [[ -f /var/lib/vz/snippets/felhom-guest-hook.sh ]]; then run rm -f /var/lib/vz/snippets/felhom-guest-hook.sh; fi
|
||||
local dconf _dnsmasq_touched=false
|
||||
for dconf in /etc/dnsmasq.d/felhom-*.conf; do
|
||||
[[ -e "$dconf" ]] || continue
|
||||
run rm -f "$dconf"; _dnsmasq_touched=true
|
||||
done
|
||||
if $_dnsmasq_touched && systemctl is-active --quiet dnsmasq 2>/dev/null; then
|
||||
run systemctl restart dnsmasq || true
|
||||
fi
|
||||
|
||||
# 5. pveum removal (presence-checked; tolerate-absent; roles deleted only after their grants).
|
||||
# Remove the 3-role scoped grants+roles (3b) AND the pre-3b single-role broad grant if present —
|
||||
# both tolerate-absent so --uninstall works on a box of either shape.
|
||||
@@ -624,9 +663,9 @@ run_uninstall() {
|
||||
|
||||
# 8. Summary.
|
||||
echo ""
|
||||
log_success "UNINSTALL complete — removed: guest $vmid, the felhom-agent (unit/sudoers/binary/state/user), the pveum role/user/token/ACL,$( $pool_removed && printf ' the %s pool,' "$PVE_POOL") and $STATE_FILE."
|
||||
log_success "UNINSTALL complete — removed: guest $vmid, the felhom-agent (unit/sudoers/binary/state/config/user + shared-parent/mkfs-wrapper/hook-snippet/dnsmasq-snippets), the pveum role/user/token/ACL,$( $pool_removed && printf ' the %s pool,' "$PVE_POOL") and $STATE_FILE."
|
||||
if $REMOVE_GOLDEN; then log_info " golden vzdump: removed."; else log_info " golden vzdump: left in place (--remove-golden to remove)."; fi
|
||||
log_info " NOTE: the 'sudo' package was left installed (system package); the host record still exists in the hub — remove it there if desired."
|
||||
log_info " NOTE: the 'sudo' and 'dnsmasq' packages were left installed (system packages); the host record still exists in the hub — remove it there if desired."
|
||||
$DRY_RUN && log_warn " DRY-RUN: nothing above was actually executed."
|
||||
return 0
|
||||
}
|
||||
@@ -1439,6 +1478,14 @@ step_provision() {
|
||||
# Record the provisioned vmid so a later --uninstall resolves the target automatically + safely.
|
||||
_state_put provisioned_vmid "$VMID"
|
||||
# (No pool_add_guest here — the agent's restore --pool already made the guest a member.)
|
||||
# Reboot the guest ONCE: the golden's controller-bootstrap unit evaluates its
|
||||
# ConditionPathExists=/etc/felhom-bootstrap/bootstrap.json at BOOT, and the back-half attaches
|
||||
# the bootstrap mount to the ALREADY-RUNNING guest — without a reboot the unit stays skipped and
|
||||
# the controller never deploys (drill finding R6; the agent's own provision output says
|
||||
# "next: reboot the guest"). On fast hosts the first boot sometimes wins the race — the reboot
|
||||
# is idempotent either way (the unit no-ops when the controller already runs).
|
||||
log_info " rebooting guest $VMID so the baked controller-bootstrap unit picks up the mount"
|
||||
run pct reboot "$VMID"
|
||||
}
|
||||
|
||||
#-------------------------------------------------------------------------------
|
||||
@@ -1452,9 +1499,14 @@ step_verify() {
|
||||
[[ "$st" == "running" ]] && log_success " pct status: running" || { log_error " pct status: $st"; ok=false; }
|
||||
if pct config "$VMID" 2>/dev/null | grep -q '^onboot: 1'; then log_success " onboot: 1"; else log_error " onboot NOT 1"; ok=false; fi
|
||||
pct config "$VMID" 2>/dev/null | grep -E '^(rootfs|mp0|mp1|mp8):' | sed 's/^/ /'
|
||||
# controller container healthy in-guest
|
||||
local cstat; cstat=$(pct exec "$VMID" -- docker ps --filter name=felhom-controller --format '{{.Status}}' 2>/dev/null | head -1)
|
||||
if [[ -n "$cstat" ]]; then log_success " controller: $cstat"; else log_warn " controller container not visible yet (may still be starting)"; fi
|
||||
# controller container healthy in-guest — bounded wait (the post-provision reboot + docker start
|
||||
# take a while, especially on modest hardware; drill R6 re-verify)
|
||||
local cstat="" _waited=0
|
||||
while [[ -z "$cstat" && $_waited -lt 180 ]]; do
|
||||
cstat=$(pct exec "$VMID" -- docker ps --filter name=felhom-controller --format '{{.Status}}' 2>/dev/null | head -1)
|
||||
[[ -n "$cstat" ]] || { sleep 5; _waited=$((_waited+5)); }
|
||||
done
|
||||
if [[ -n "$cstat" ]]; then log_success " controller: $cstat (after ~${_waited}s)"; else log_warn " controller container not visible after ${_waited}s — check 'pct exec $VMID -- journalctl -u felhom-controller-bootstrap'"; fi
|
||||
local cver; cver=$(pct exec "$VMID" -- docker ps --filter name=felhom-controller --format '{{.Image}}' 2>/dev/null | head -1)
|
||||
[[ -n "$cver" ]] && log_info " controller image: $cver"
|
||||
# tunnel
|
||||
|
||||
Reference in New Issue
Block a user