configs: build-golden.sh v2.0.0 — mandatory controller tag (B5) + bootstrap .path unit (B1)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PSK5g6qYLknKj8u3QAFEr6
This commit is contained in:
@@ -1,3 +1,31 @@
|
||||
## configs: build-golden.sh v2.0.0 — mandatory controller tag + bootstrap .path unit (B5 + B1) (2026-07-03)
|
||||
|
||||
Golden-bake script only — **no agent code, no binary, no agent version bump** (docs/config
|
||||
precedent). Resolves drill findings B5 + B1
|
||||
(`felhom.eu/documentation/audits/DRILL-day0-cleanroom-2026-07-03.md` §9) and closes the stale
|
||||
backlog note `FOLLOWUP-golden-default-controller-tag.md`.
|
||||
|
||||
- **B5 — `CONTROLLER_IMAGE` (arg 6) is now MANDATORY** — the hand-bumped default rotted twice
|
||||
(0.43.0 → 0.85.1 → stale again; 0.85.1 predates the v0.86.0 floor-honoring code, which is why
|
||||
every fresh install needed the manual D.1b update). No 6th arg → die with usage (red-proofed:
|
||||
exits 1 before any `pct` op). Auto-resolving "latest" was rejected — it could bake an unvouched
|
||||
tag.
|
||||
- **B1 — baked `felhom-controller-bootstrap.path` unit** (`PathExists=/etc/felhom-bootstrap/
|
||||
bootstrap.json`, enabled next to the service): the service's `ConditionPathExists` is evaluated
|
||||
only at boot, but the agent back-half hot-plugs the bootstrap mount into the already-running
|
||||
guest — the path unit starts the service when the file APPEARS, so the controller deploys with
|
||||
NO reboot (isolated systemd proof + full Day-0 proof on the clean-room drill VM; the installer's
|
||||
v1.9.1 post-provision reboot is now a redundant belt, kept). `RemainAfterExit=yes` on the service
|
||||
prevents re-trigger loops; the service itself stays unchanged.
|
||||
- `GOLDEN_SCRIPT_VERSION` (2.0.0) + a `[golden]` provenance line (script version + baked controller
|
||||
tag) now open every bake transcript.
|
||||
- Baked + published with controller **0.98.3**: golden `0.98.3` /
|
||||
sha256 `b9a02ef1b6f02b9b58babc4c6aad9cf6c053ebdfba116c78c8e7830de757fd01` (Gitea generic package,
|
||||
201 + sha round-trip). Clean-room validation: bake integrity (mp0+mp1 included), isolated
|
||||
hot-plug proof, full local-golden Day-0 install (first boot = 0.98.3, self-update reports
|
||||
up-to-date, app deploy OK) — evidence:
|
||||
`felhom.eu/documentation/audits/DRILL-golden-098-2026-07-03.md`.
|
||||
|
||||
## v0.63.0 — B3 + B2: fresh-install fixes — token reload-on-miss + guesthook snippets dir (2026-07-03)
|
||||
|
||||
The two agent-side gaps the Day-0 clean-room drill surfaced
|
||||
|
||||
+40
-5
@@ -20,7 +20,9 @@
|
||||
# config mount (/etc/felhom-bootstrap/bootstrap.json) — no docker login/pull at deploy. Refreshing
|
||||
# the golden bumps the controller baseline; controller self-update covers in-between drift.
|
||||
#
|
||||
# Usage: build-golden.sh [VMID] [TEMPLATE_VOLID] [ROOTFS_STORAGE] [ARCHIVE_STORAGE] [BRIDGE] [CONTROLLER_IMAGE]
|
||||
# Usage: build-golden.sh [VMID] [TEMPLATE_VOLID] [ROOTFS_STORAGE] [ARCHIVE_STORAGE] [BRIDGE] CONTROLLER_IMAGE
|
||||
# CONTROLLER_IMAGE is REQUIRED (no default) — pass the released controller tag explicitly,
|
||||
# e.g. gitea.dooplex.hu/admin/felhom-controller:0.98.3.
|
||||
# Build-time registry login for the controller pull (used ONCE inside the build guest, then logged
|
||||
# out — never baked): set REGISTRY_USER + REGISTRY_TOKEN in the environment.
|
||||
#
|
||||
@@ -35,15 +37,27 @@
|
||||
# so the archive would carry NO images and provisioned guests would boot imageless.
|
||||
set -euo pipefail
|
||||
|
||||
# Script provenance — logged into every bake transcript next to the baked controller tag, so an
|
||||
# archive can always be traced to the script that produced it. Bump on any behavior change.
|
||||
GOLDEN_SCRIPT_VERSION="2.0.0"
|
||||
|
||||
VMID="${1:-9100}"
|
||||
TEMPLATE="${2:-local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst}"
|
||||
ROOTFS_STORAGE="${3:-local-lvm}"
|
||||
ARCHIVE_STORAGE="${4:-local}"
|
||||
BRIDGE="${5:-vmbr0}"
|
||||
# Default to the CURRENT controller so an argument-less build is never wildly stale. ALWAYS pass the
|
||||
# controller version explicitly at each rebuild (this default only bounds the worst case); a future
|
||||
# `make golden` that resolves the latest pullable tag would remove the need for a hand-bumped default.
|
||||
CONTROLLER_IMAGE="${6:-gitea.dooplex.hu/admin/felhom-controller:0.85.1}"
|
||||
# CONTROLLER_IMAGE is MANDATORY — no default. The hand-bumped default rotted twice (0.43.0 →
|
||||
# 0.85.1 → stale again): each time, a fresh provision would have booted a pre-floor controller
|
||||
# needing a manual install-day update (drill finding B5). A required argument cannot rot, and
|
||||
# auto-resolving "latest" could bake a tag the hub manifest never vouched — so the caller states
|
||||
# the released controller tag explicitly at every rebuild.
|
||||
CONTROLLER_IMAGE="${6:-}"
|
||||
if [ -z "$CONTROLLER_IMAGE" ]; then
|
||||
echo "[golden] FATAL: CONTROLLER_IMAGE (argument 6) is required — pass the released controller tag explicitly." >&2
|
||||
echo "Usage: build-golden.sh [VMID] [TEMPLATE_VOLID] [ROOTFS_STORAGE] [ARCHIVE_STORAGE] [BRIDGE] CONTROLLER_IMAGE" >&2
|
||||
echo " e.g.: build-golden.sh 9100 local:vztmpl/debian-13-standard_13.1-2_amd64.tar.zst local-lvm local vmbr0 gitea.dooplex.hu/admin/felhom-controller:0.98.3" >&2
|
||||
exit 1
|
||||
fi
|
||||
REGISTRY_HOST="${CONTROLLER_IMAGE%%/*}"
|
||||
# OS rootfs size (GiB) and the golden's Docker-data volume size (GiB). Keep GOLDEN_DOCKER_GB just
|
||||
# large enough for the baked images + headroom; provision grows it to the per-customer target.
|
||||
@@ -56,6 +70,7 @@ GOLDEN_DOCKER_GB="${GOLDEN_DOCKER_GB:-16}"
|
||||
# storage-split B3) and the user-data area would silently fall out of PBS coverage.
|
||||
GOLDEN_SYSDATA_GB="${GOLDEN_SYSDATA_GB:-8}"
|
||||
|
||||
echo "[golden] build-golden.sh v${GOLDEN_SCRIPT_VERSION} — baking controller ${CONTROLLER_IMAGE}"
|
||||
echo "[golden] creating build LXC $VMID (nesting=1,keyctl=1, unprivileged; rootfs ${OS_SIZE_GB}G + Docker-data ${GOLDEN_DOCKER_GB}G @ /var/lib/docker + user-data ${GOLDEN_SYSDATA_GB}G @ /mnt/sys_drive, both backup=1) …"
|
||||
pct create "$VMID" "$TEMPLATE" \
|
||||
--hostname felhom-golden --unprivileged 1 \
|
||||
@@ -217,6 +232,26 @@ WantedBy=multi-user.target
|
||||
UNIT
|
||||
systemctl enable felhom-controller-bootstrap.service'
|
||||
|
||||
# B1 (DRILL-day0-cleanroom-2026-07-03 R6/B1): the service's ConditionPathExists is evaluated only
|
||||
# when the service is STARTED — i.e. at boot via multi-user.target — but the agent back-half
|
||||
# hot-plugs the bootstrap mount into the ALREADY-RUNNING guest, so on a provision the boot-time
|
||||
# start races the mount and loses on slow hardware. This path unit watches for bootstrap.json and
|
||||
# starts the service when it APPEARS — covering the provision hot-plug without a reboot. The boot
|
||||
# case is still served by the enabled service itself; RemainAfterExit=yes on the service means the
|
||||
# path unit cannot re-trigger it in a loop once it has run.
|
||||
echo "[golden] baking the controller-bootstrap PATH unit (starts the service on bootstrap-mount hot-plug — B1) …"
|
||||
pct exec "$VMID" -- bash -c 'cat > /etc/systemd/system/felhom-controller-bootstrap.path <<UNIT
|
||||
[Unit]
|
||||
Description=Watch for the agent-populated bootstrap config; start the controller bootstrap when it appears
|
||||
|
||||
[Path]
|
||||
PathExists=/etc/felhom-bootstrap/bootstrap.json
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
UNIT
|
||||
systemctl enable felhom-controller-bootstrap.path'
|
||||
|
||||
echo "[golden] baking the first-boot SSH host-key regeneration unit (F3) …"
|
||||
pct exec "$VMID" -- bash -c 'cat > /etc/systemd/system/felhom-regen-hostkeys.service <<UNIT
|
||||
[Unit]
|
||||
|
||||
Reference in New Issue
Block a user