mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 07:41:27 +00:00
feat: high-availability page (/ha)
Platform-level HA surface: manager enable/disable toggle, status cards (nodes, health checks, active alerts), manual failover with confirmation, per-service failover policy CRUD with project/service picker, active alert resolution, and health check result list. Verified live: status, enable/disable, policy set/list/get/disable, manual failover, alerts and health results endpoints. HA state is in-memory — noted in roadmap alongside autoscaling persistence debt. Authored By: TDvorak <[email protected]> Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
1 parent
44a1b09dad
commit
d5c99acb8c
5 files changed
+496
-3
No files matched your search
@@ -1535,3 +1535,70 @@ export async function manualScaleService(serviceId: string, replicas: number, re
|
||||
body: JSON.stringify({ replicas, reason }),
|
||||
});
|
||||
}
|
||||
|
||||
export type FailoverPolicy = components['schemas']['FailoverPolicy'];
|
||||
|
||||
export type HAStatus = {
|
||||
enabled?: boolean;
|
||||
nodes?: { total?: number; healthy?: number; unhealthy?: number };
|
||||
health_checks?: { total?: number; healthy?: number; unhealthy?: number };
|
||||
alerts?: { active?: number };
|
||||
};
|
||||
|
||||
export type HAAlert = {
|
||||
id?: string;
|
||||
rule_id?: string;
|
||||
status?: string;
|
||||
severity?: string;
|
||||
message?: string;
|
||||
starts_at?: string;
|
||||
ends_at?: string;
|
||||
};
|
||||
|
||||
export type HAHealthResult = {
|
||||
check_id?: string;
|
||||
status?: string;
|
||||
message?: string;
|
||||
latency?: number;
|
||||
timestamp?: string;
|
||||
};
|
||||
|
||||
export async function getHAStatus(): Promise<HAStatus> {
|
||||
const payload = await requestJson<{ status?: HAStatus }>('/ha/status');
|
||||
return payload.status ?? {};
|
||||
}
|
||||
|
||||
export async function setHAEnabled(enabled: boolean): Promise<void> {
|
||||
await requestJson(enabled ? '/ha/enable' : '/ha/disable', { method: 'POST' });
|
||||
}
|
||||
|
||||
export async function triggerFailover(reason: string): Promise<void> {
|
||||
await requestJson('/ha/failover', { method: 'POST', body: JSON.stringify({ reason }) });
|
||||
}
|
||||
|
||||
export async function listFailoverPolicies(): Promise<FailoverPolicy[]> {
|
||||
const payload = await requestJson<{ policies?: FailoverPolicy[] }>('/ha/failover/policies');
|
||||
return payload.policies ?? [];
|
||||
}
|
||||
|
||||
export async function setFailoverPolicy(policy: FailoverPolicy): Promise<void> {
|
||||
await requestJson('/ha/failover/policies', { method: 'POST', body: JSON.stringify(policy) });
|
||||
}
|
||||
|
||||
export async function deleteFailoverPolicy(serviceId: string): Promise<void> {
|
||||
await requestJson(`/ha/failover/policies/${encodeURIComponent(serviceId)}`, { method: 'DELETE' });
|
||||
}
|
||||
|
||||
export async function listActiveAlerts(): Promise<HAAlert[]> {
|
||||
const payload = await requestJson<{ alerts?: HAAlert[] }>('/ha/alerts/active');
|
||||
return payload.alerts ?? [];
|
||||
}
|
||||
|
||||
export async function resolveAlert(alertId: string): Promise<void> {
|
||||
await requestJson(`/ha/alerts/${encodeURIComponent(alertId)}/resolve`, { method: 'POST' });
|
||||
}
|
||||
|
||||
export async function listHealthResults(): Promise<HAHealthResult[]> {
|
||||
const payload = await requestJson<{ results?: HAHealthResult[] }>('/ha/health/results');
|
||||
return payload.results ?? [];
|
||||
}
|
||||
Reference in new issue
Block a user