feat(ui): admin manual-failover control on the health page
CentralFailoverControl lives in Components/Health/ (matching AuditKpiTiles / SiteCallKpiTiles) rather than inline in Health.razor, so it is testable without standing up the whole dashboard's DI graph. - Admin-gated via AuthorizeView + RequireAdmin. The Health page itself is intentionally all-roles, so the gate belongs on the control, not the page. - Disabled with an explanatory title when the pair has no online standby; the authoritative guard remains server-side against live cluster membership. - Confirmation dialog (IDialogService, the page idiom) warns that singletons hand over, in-flight work on the active node is interrupted, and THIS PAGE will disconnect and reconnect against the new active node -- Traefik routes the UI to the node being restarted, so a working failover otherwise reads as a crash the admin caused. - A refused failover (service returns null) surfaces the refusal; the UI never reports a failover that did not happen. 7 bUnit tests. Two harness requirements that bit first: AuthorizeView needs a cascading AuthenticationState (the app supplies it from the layout), and BunitContext pre-registers a placeholder IAuthorizationService that throws on policy evaluation -- both handled the same way NavMenuTests documents. Runbook paragraphs added to Component-ClusterInfrastructure.md (new Manual Failover section) and docker/README.md.
This commit is contained in:
@@ -327,6 +327,14 @@ open http://localhost:9002
|
||||
docker start scadabridge-central-a
|
||||
```
|
||||
|
||||
**Manual failover from the UI (admin-only).** Instead of stopping a container, an Administrator can trigger a planned role swap from the **Trigger failover** button on the central-cluster card at `/monitoring/health` (via Traefik, `http://localhost:9000`). The active (oldest Up) node leaves the cluster **gracefully**, so singletons hand over rather than being killed; the node then restarts under `restart: unless-stopped` and rejoins as the standby.
|
||||
|
||||
- The button is disabled when the pair has no online standby — the same guard is re-enforced server-side, since failing over a lone node is an outage, not a failover.
|
||||
- Triggering it **disconnects the page you clicked it on**: Traefik routes the UI to the active node, which is the node being restarted. The page reconnects against the new active node.
|
||||
- Each invocation writes one `Cluster` / `ManualFailover` row to `dbo.AuditLog` naming the admin and the target address, written before the Leave is issued.
|
||||
|
||||
To verify on the rig: press the button, watch `central-a` restart and `central-b`'s badge flip to Primary, then confirm the audit row landed.
|
||||
|
||||
### Site Failover
|
||||
|
||||
```bash
|
||||
|
||||
Reference in New Issue
Block a user