gate: the boot bind gate honours a customer's Stop (R-55, v0.157.0)
shouldRecreateOnBoot keyed on Deployed+drive-present alone. Deployed stays true across a Stop, so a drive-backed app the customer switched off was silently restarted on every guest reboot (proven live: immich). Requires len(Containers)>0 as well - R-52's existing-Exited vs absent distinction. A UI Stop is compose down and removes the containers; a guest that went down under a running app leaves them. Container STATE is still deliberately NOT a filter: that would miss a not-yet-restarted or stuck-Exited app, which is the bug the boot-id path exists to fix. Evidence sampled before any recreate - recreate's own StopStack erases it. Honoured Stops counted and logged separately from no-live-bind skips.
This commit is contained in:
@@ -1113,6 +1113,20 @@ not just those with HDD data. Non-HDD apps can configure destination, method, an
|
||||
> covered; drives that never go live in the window are left to the drive-absent gate. `processGuestBootChange`
|
||||
> also runs on every periodic `driveGateLoop` tick now (idempotent, boot-id gated) so a momentarily-unreachable
|
||||
> agent right after a guest reboot no longer permanently strands recovery.
|
||||
> **v0.157.0 — R-55, the gate now honours a customer's Stop.** Until this version the recreate keyed on
|
||||
> `Deployed && HDD_PATH && drive-present` alone, so a drive-backed app the customer had deliberately
|
||||
> Stopped was silently restarted on every guest reboot (proven live: immich, stopped from the UI seconds
|
||||
> earlier, came back running). `shouldRecreateOnBoot` now also requires the app to still HAVE containers
|
||||
> (`len(Stack.Containers) > 0`, from `docker ps -a`, so `Exited` ones count) — R-52's `existing-Exited vs
|
||||
> absent` distinction (`bootrecon.isBootOrphan`) translated to this gate. A UI Stop is `compose down`,
|
||||
> which REMOVES the containers; a guest that went down under a running app leaves them present. **State is
|
||||
> still NOT a filter** — that part of the original design is load-bearing and unchanged; `hasContainers`
|
||||
> answers a different question ("does docker still have records of it") which, unlike liveness, survives a
|
||||
> reboot as a statement of intent. The evidence is sampled BEFORE any recreate, because recreate's own
|
||||
> `StopStack` erases it. Apps stopped by the drive-absent gate are also at zero containers and are likewise
|
||||
> left alone here — they are restored by `ReconcileDriveGates`' `Return` branch from
|
||||
> `StoragePath.StoppedStacks`, on the same loop tick. Honoured Stops are logged at INFO (`left stopped …`),
|
||||
> counted separately from the "no live bind" skips so an intended outcome never fires a WARN.
|
||||
> **Agent-path prerequisite (also v0.71.0):** the whole drive gate needs `cfg.LocalAPI.Endpoint` (the
|
||||
> per-guest agent local API). `bootstrap.MaybeIngest` now calls `ensureLocalAPI` on the already-configured
|
||||
> path — merging `local_api` from `bootstrap.json` into an existing controller.yaml that lacks it (seeded
|
||||
|
||||
Reference in New Issue
Block a user