v0.42.0: agentic controller update — in-guest image swap + rollback (Phase 1)
New local-API POST /controller/swap (+ GET /controller/swap/status), withGuest- scoped: the agent records the previous image, confirms the target is present, rewrites /etc/felhom-controller-image, restarts felhom-controller-bootstrap.service, verifies the new controller is healthy (docker inspect, <=90s), and ROLLS BACK to the previous image if not. Single-flight per guest; strict image-ref validation; crash-safety state file. GuestBinder.GuestExec is the pct-exec seam. --selftest=controller-swap exercises it directly. Tests: happy/rollback-on-unhealthy(+red-proof)/image-absent/no-healthcheck/ bad-image-400/single-flight-409. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TtXesNa2LGbMmE4DNL6SE7
This commit is contained in:
@@ -3,6 +3,32 @@
|
||||
All notable changes to **felhom-agent** are recorded here. Update on every code
|
||||
change that gets pushed.
|
||||
|
||||
## v0.42.0 — agentic controller update: in-guest image swap + rollback (Phase 1) (2026-06-26)
|
||||
|
||||
The host agent now owns the in-guest controller image **swap** — the new-architecture replacement for
|
||||
the controller's dead in-container `docker compose` self-update. The controller pre-pulls the target
|
||||
image (shared docker socket, its own registry token) then asks the agent to swap; the agent — external
|
||||
to the controller container, so it survives the controller being killed mid-swap — does the rest and
|
||||
**rolls back** if the new controller doesn't come up healthy.
|
||||
|
||||
- **New local-API routes** (`internal/localapi/controllerswap.go`, token-scoped via `withGuest`):
|
||||
- `POST /controller/swap {image}` → **202** `{status:"swapping", previous_image, target_image}`, then
|
||||
async: record previous (crash-safety state file `/var/lib/felhom-agent/controller-swap-<vmid>.json`)
|
||||
→ confirm the target image is present in the guest (else abort, **no swap**) → write
|
||||
`/etc/felhom-controller-image` → `systemctl restart felhom-controller-bootstrap.service` → poll the
|
||||
new controller to **healthy** (`docker inspect`, ≤90s) → **roll back** to the previous image + restart
|
||||
if it doesn't (the guest is never left without a controller). Single-flight per guest (409 if busy).
|
||||
Image ref is strict-validated (`gitea.dooplex.hu/admin/felhom-controller:<semver>`) before any action.
|
||||
- `GET /controller/swap/status` → `{state: swapping|done|failed, current, previous, target, error}`.
|
||||
- **`GuestBinder.GuestExec`** (`internal/localapi/guestbind.go`): the one `pct exec` seam the swap
|
||||
composes over (cat/inspect/write/restart), reusing the fenced root runner.
|
||||
- **`--selftest=controller-swap -vmid -image <ref>`**: exercise the primitive directly (the target image
|
||||
must already be pulled in the guest).
|
||||
- Wired `ControllerSwap: guestBinder` into the local-API server (`cmd/felhom-agent/main.go`).
|
||||
- Tests (`controllerswap_test.go`): happy swap, **rollback-on-unhealthy** (+ companion red-proof:
|
||||
dropping the rollback leaves the guest on the bad image and fails the test), image-absent no-swap,
|
||||
no-healthcheck-running, bad-image 400, single-flight 409.
|
||||
|
||||
## v0.41.0 — provisioned customer guests auto-start after a host reboot (`onboot:1`) (2026-06-24)
|
||||
|
||||
**F3 fix.** The provision back-half now sets **`onboot:1`** on the customer guest, so after a host
|
||||
|
||||
Reference in New Issue
Block a user