Initial commit — SvelteKit fleet manager for T5 Plutonium servers
Ports push_scripts.sh (1497 lines of bash) to a SvelteKit + SQLite web app that manages a fleet of T5 Plutonium servers running on Komodo. Same push and beta workflow as the shell script, with a live SSE pipeline view, a !rt-token-gated auth modal that hard-pauses deployments on stale tokens, per-file audit diffs, and a Komodo-container deployment target. - Push/beta engines port the exact filter, held-by-beta, conflict, and stale-backup rules from the shell script - SQLite (better-sqlite3) replaces script_metadata.json; a one-shot importer moves legacy state over on first boot - 16 vitest tests cover push add/update/skip, beta open→rollback, open→promote, conflict guards, sweep frozen/manual branches, and IW4M login/status parsing - docker/ + komodo/stack.toml deploy as a managed container on the same host as the game servers, /root/zombies bind-mounted at the same path the shell script used
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
import { config, komodoConfigured } from '../config.js';
|
||||
import { getServer } from '../fleet/servers.js';
|
||||
|
||||
// Ports `komodo_restart` in push_scripts.sh:622. Three shapes depending on
|
||||
// the tracked komodo_type: deployment | container | stack.
|
||||
|
||||
export type KomodoRestartResult =
|
||||
| { ok: true }
|
||||
| { ok: false; kind: 'unconfigured' | 'no-name' | 'http-error' | 'unreachable'; message: string };
|
||||
|
||||
async function komodoCall(path: string, body: unknown): Promise<Response> {
|
||||
const url = `${config.komodo.address.replace(/\/+$/, '')}/${path}`;
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), config.httpTimeoutMs);
|
||||
try {
|
||||
return await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-Api-Key': config.komodo.apiKey,
|
||||
'X-Api-Secret': config.komodo.apiSecret
|
||||
},
|
||||
body: JSON.stringify(body),
|
||||
signal: controller.signal
|
||||
});
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
|
||||
export async function komodoRestart(serverName: string): Promise<KomodoRestartResult> {
|
||||
if (!komodoConfigured()) {
|
||||
return { ok: false, kind: 'unconfigured', message: 'komodo not configured' };
|
||||
}
|
||||
const row = getServer(serverName);
|
||||
if (!row?.komodo_name) return { ok: false, kind: 'no-name', message: 'no komodo_name set for server' };
|
||||
|
||||
const type = row.komodo_type ?? 'deployment';
|
||||
let path: string;
|
||||
let body: Record<string, string>;
|
||||
|
||||
switch (type) {
|
||||
case 'stack':
|
||||
path = 'execute/RestartStack';
|
||||
body = { stack: row.komodo_name };
|
||||
break;
|
||||
case 'container':
|
||||
if (!row.komodo_server) return { ok: false, kind: 'no-name', message: 'container type needs komodo_server' };
|
||||
path = 'execute/RestartContainer';
|
||||
body = { server: row.komodo_server, container: row.komodo_name };
|
||||
break;
|
||||
case 'deployment':
|
||||
default:
|
||||
path = 'execute/RestartDeployment';
|
||||
body = { deployment: row.komodo_name };
|
||||
break;
|
||||
}
|
||||
|
||||
let res: Response;
|
||||
try {
|
||||
res = await komodoCall(path, body);
|
||||
} catch (err) {
|
||||
return { ok: false, kind: 'unreachable', message: (err as Error).message };
|
||||
}
|
||||
if (!res.ok) {
|
||||
return { ok: false, kind: 'http-error', message: `HTTP ${res.status}` };
|
||||
}
|
||||
|
||||
// The script also checks the response body: if it's an object with
|
||||
// .success === false, treat as failure. If .success is absent, trust the
|
||||
// HTTP status (line 646).
|
||||
try {
|
||||
const json = await res.json();
|
||||
if (json && typeof json === 'object' && 'success' in json && json.success === false) {
|
||||
return { ok: false, kind: 'http-error', message: 'komodo returned success=false' };
|
||||
}
|
||||
} catch {
|
||||
// Non-JSON body is fine — HTTP 2xx already indicates success.
|
||||
}
|
||||
return { ok: true };
|
||||
}
|
||||
Reference in New Issue
Block a user