docs: REPORT.md for v0.81.0 (server-reboot button / banner retirement)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017PsnU2ASocYrvzqE82YDYW
This commit is contained in:
@@ -1,60 +1,46 @@
|
||||
# REPORT — controller v0.80.0: disk card shows + acts on the stable path
|
||||
# REPORT — retire drive-activation banner; add standalone "Kiszolgáló újraindítása" button
|
||||
|
||||
## Baseline
|
||||
- felhom-controller `main` @ `9596c8e`, **v0.79.0 → v0.80.0**. Trunk-based, `main`.
|
||||
- Follow-up to v0.78.0 (stable-path registration) + v0.79.0 (registered badge on stable path).
|
||||
**Repo:** felhom-controller · **Baseline:** `main` @ `7cce19797` (v0.80.0) → **v0.81.0**
|
||||
**Commit:** `242b835` (code + CHANGELOG + README). **Date:** 2026-06-23.
|
||||
|
||||
## Problem (operator-reported, screenshot)
|
||||
The storage disk card still displayed each external drive's **raw** host PVE mount `/mnt/<name>`
|
||||
(`usb · /dev/sdc1 · /mnt/felhom-flash`). Inside the guest/controller the drive lives at the **stable**
|
||||
path `/mnt/felhom-drives/<name>` (the agent's `guest_path`) — which is what the registry, app `HDD_PATH`,
|
||||
and FileBrowser use; the raw path doesn't even exist in the guest. Two latent bugs rode on the same
|
||||
mismatch: the Leválasztás/Törlés buttons posted the **raw** path, so `handleStorageEject`/`handleStorageWipe`
|
||||
would unmount the drive but `RemoveStoragePath(raw)` would miss the **stable** registry entry (orphan);
|
||||
and the impact warning `/api/storage/impact?where=raw` found no apps (HDD_PATH is the stable path).
|
||||
## Why
|
||||
In the intermediary-mount model an enrolled drive binds **live** into the running guest (agent
|
||||
`disks.go` — no `pct set -mpN`, no slot, no reboot), so the "… meghajtó aktiválásra vár /
|
||||
Újraindítás most (~30 mp)" banner was an obsolete relic of the old per-drive reboot model. It was
|
||||
also effectively **dead since v0.78**: `pendingActivationDrives` keyed `attached` by the agent's RAW
|
||||
`MountPath` but compared it to the now-STABLE `sp.Path`. Retired it; added a deliberate full-server
|
||||
restart affordance in its place (sibling to the controller-only restart).
|
||||
|
||||
## Fix
|
||||
**`controller/internal/web/templates/settings.html`** (disk-view JS):
|
||||
- Card sub-line now shows `regKey(d)` (= `d.guest_path || d.mount_path`) — the stable in-guest path.
|
||||
- `actions()` passes the **stable** path to `confirmEject`/`confirmWipe` (handlers map it to raw for the
|
||||
agent via `agentWhere()` AND deregister the stable registry entry). `registerDrive` keeps the **raw**
|
||||
`mount_path` (its agent guest-attach operates on raw; `handleStorageRegister` maps to stable).
|
||||
- `confirmEject`/`confirmWipe` derive the type-to-confirm name from the **basename**
|
||||
(`where.split('/').filter(Boolean).pop()`) so it still equals the server's `path.Base(where)` check
|
||||
when `where` is the stable path.
|
||||
## Files changed
|
||||
- `controller/internal/web/storage_handlers.go`
|
||||
- Removed dead `pendingActivationDrives` helper + the now-unused `internal/system` import.
|
||||
- Renamed `handleStorageActivate` → `HandleServerReboot`; split out testable `serverReboot(w,r,agent)` core.
|
||||
- Added `GuestReboot(ctx) error` to the `diskAgent` interface (`*agentapi.Client` already satisfies it).
|
||||
- Removed the `/api/storage/activate` case from `ServeStorageAPI` (→ 404).
|
||||
- `controller/cmd/controller/main.go` — mounted `/api/server/reboot` (`RequireAuth`+`CsrfProtect`) next to the storage route.
|
||||
- `controller/internal/web/handlers.go` — removed the `data["PendingDrives"]` feed.
|
||||
- `controller/internal/web/templates/settings.html` — removed the `{{if .PendingDrives}}` banner block and `window.activatePendingDrives`; added the **"Kiszolgáló újraindítása"** settings card + `restartServer()` JS (reuses the existing `pollRestart()` loop).
|
||||
- `controller/internal/web/storage_handlers_test.go` — `mockAgent` gained `GuestReboot`; new test.
|
||||
- `CHANGELOG.md` (v0.81.0 entry), `controller/README.md` (full-server-restart section).
|
||||
|
||||
**`controller/internal/web/storage_handlers.go`** (`handleStorageWipe`):
|
||||
- The agent eject now uses `agentWhere(req.Where)` (was `req.Where` verbatim), matching
|
||||
`handleStorageEject`. So a stable registered path maps to the raw mount for the agent while
|
||||
`RemoveStoragePath(req.Where)` deregisters the stable entry. Agent op is the identical raw path as
|
||||
before; only the registry bookkeeping is corrected. The format step is unchanged (keyed on `device`).
|
||||
### Note on naming
|
||||
The HTTP handler is **exported** (`HandleServerReboot`), not the lowercase name in the spec snippet:
|
||||
`cmd/controller/main.go` wires it cross-package, and every web handler mounted there is exported. The
|
||||
unexported `serverReboot` core carries the logic and is what the test exercises (same split-out pattern
|
||||
as `runStorageInit`).
|
||||
|
||||
Agent-facing operations (eject unmount, format) produce the IDENTICAL raw paths/device as before — only
|
||||
the controller's display + its own registry bookkeeping/impact lookups now use the stable path.
|
||||
## Test
|
||||
`TestHandleServerReboot_CallsGuestReboot` (`storage_handlers_test.go`): a fake `diskAgent` asserts
|
||||
`GuestReboot` is invoked **exactly once** and the response is **202** with `{ok:true, rebooting:true}`.
|
||||
|
||||
## Tests
|
||||
- `go build ./... && go vet ./... && go test ./...` — **all green** (incl. `TestTemplatesParse`).
|
||||
- `handleStorageWipe`'s new mapping rides on `agentWhere`, already covered by `TestAgentWhere`
|
||||
(stable→raw, raw idempotent). JS changes covered by template parse (no JS unit harness — existing
|
||||
pattern).
|
||||
```
|
||||
go build ./... → BUILD_OK
|
||||
go vet ./... → VET_OK
|
||||
go test ./... → ok (internal/web 1.640s, new test PASS); all packages ok
|
||||
```
|
||||
|
||||
## Deploy (v0.80.0 → guest 9201)
|
||||
- Built + pushed `gitea.dooplex.hu/admin/felhom-controller:0.80.0` on 192.168.0.180; deployed to 9201
|
||||
(pull → `/etc/felhom-controller-image` → restart bootstrap unit); `docker ps` → `:0.80.0 Up (healthy)`.
|
||||
Grep confirmed **zero** remaining references to `PendingDrives`, `pendingActivationDrives`,
|
||||
`activatePendingDrives`, `activate-drives-btn`, `/api/storage/activate`, `handleStorageActivate`.
|
||||
|
||||
## Verification (served page JS + data the card renders from)
|
||||
- Served `/settings` JS (the disk card is built client-side from these): sub-line
|
||||
`… +(d.mount_path?' · '+esc(regKey(d)):'')` (stable); `confirmEject('+reg+')` and
|
||||
`confirmWipe('+dev+','+reg+')` (stable); `registerDrive('+mpRaw+')` (raw). Confirms v0.80.0 shipped.
|
||||
- `GET /api/disks`: `felhom-flash → guest_path=/mnt/felhom-drives/felhom-flash`,
|
||||
`felhom-usb → guest_path=/mnt/felhom-drives/felhom-usb` ⇒ the card renders the stable path and the
|
||||
eject/wipe buttons carry it.
|
||||
- Regression: `[PASS] Storage paths: 2 connected, 0 disconnected`; `[PASS] System data path: /mnt/sys_drive`.
|
||||
- NOT live-clicked: the destructive eject/wipe buttons (would unmount/format the demo drives). Verified
|
||||
the path-mapping logic by inspection + the agent ops are unchanged (raw via `agentWhere`/device); the
|
||||
rendering is pure client-side JS over the confirmed-correct inputs (bridge not attached this session).
|
||||
|
||||
## Observations (recorded, NOT acted on)
|
||||
- `pendingActivationDrives` still keys off the agent's raw `MountPath` (the "~30 mp újraindítás" banner);
|
||||
obsolete in the live-activating intermediary model — key off `GuestPath`/`BoundUnderParent` or retire.
|
||||
- Free-form settings storage-add (`handlers.go`) registers a user-typed path verbatim (advanced flow).
|
||||
## Deploy + live verification
|
||||
_To be filled after the build/deploy + §9 verification (banner gone, button present, route 200/404, regression)._
|
||||
|
||||
Reference in New Issue
Block a user