Add deploy + destroy server flow; migrate to t5_<mode>_<slug>_<n> naming
Full server lifecycle management from Electric Cherry: pick game/mode/map/pluto key in the Fleet page, EC provisions the deployment via Komodo, allocates a port in 28960-28980, creates the 0o777 host dir, and starts the container. Destroy button tears everything down (Komodo Destroy+Delete, rm -rf host dir, transactional DB cleanup) and surfaces any partial-failure warnings inline. Same phase cuts over to the new naming scheme (t5_zombie_cosmodrome_1 etc.). Komodo entity names now match EC server names 1:1 (no more _/- transform), and the map catalog carries friendly/slug/canonical for each of the 11 t5 zombie maps. Server rows gain game_mode, map_slug, host_dir, config_file, game_id, image, created_by, and destroyed_at columns for provisioning + audit. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -76,18 +76,36 @@ export interface ServerRow {
|
||||
last_seen_at: string | null;
|
||||
last_error: string | null;
|
||||
last_reply_snippet: string | null;
|
||||
game_mode: string | null;
|
||||
map_slug: string | null;
|
||||
host_dir: string | null;
|
||||
config_file: string | null;
|
||||
game_id: string | null;
|
||||
image: string | null;
|
||||
created_by: string | null;
|
||||
destroyed_at: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export async function seedServerRegistry(): Promise<number> {
|
||||
const rows = await allServers();
|
||||
// Under the new naming scheme Komodo entities match EC server names 1:1
|
||||
// (both underscore-separated), so komodo_name = name — no transformation.
|
||||
const insert = db().prepare(
|
||||
'INSERT OR IGNORE INTO servers (name, komodo_type, komodo_name, game, map) VALUES (?, ?, ?, ?, ?)'
|
||||
`INSERT OR IGNORE INTO servers
|
||||
(name, komodo_type, komodo_name, game, map, game_mode, map_slug, host_dir)
|
||||
VALUES (?, 'deployment', ?, ?, ?, ?, ?, ?)`
|
||||
);
|
||||
// Also backfill existing rows where game/map were never set (upgrade path
|
||||
// from before name-based auto-derivation existed).
|
||||
// Backfill existing rows where derived columns were never set. game_mode
|
||||
// and map_slug are new; older rows can still surface them from the name.
|
||||
const backfill = db().prepare(
|
||||
'UPDATE servers SET game = COALESCE(game, ?), map = COALESCE(map, ?) WHERE name = ? AND (game IS NULL OR map IS NULL)'
|
||||
`UPDATE servers
|
||||
SET game = COALESCE(game, ?),
|
||||
map = COALESCE(map, ?),
|
||||
game_mode = COALESCE(game_mode, ?),
|
||||
map_slug = COALESCE(map_slug, ?),
|
||||
host_dir = COALESCE(host_dir, ?)
|
||||
WHERE name = ?`
|
||||
);
|
||||
let n = 0;
|
||||
const tx = db().transaction((names: string[]) => {
|
||||
@@ -95,14 +113,19 @@ export async function seedServerRegistry(): Promise<number> {
|
||||
const parsed = parseServerName(name);
|
||||
const game = parsed?.game ?? null;
|
||||
const map = parsed?.mapCanonical ?? null;
|
||||
const res = insert.run(name, 'deployment', name.replace(/_/g, '-'), game, map);
|
||||
const gameMode = parsed?.gameMode ?? null;
|
||||
const mapSlug = parsed?.mapSlug ?? null;
|
||||
const hostDir = `${config.serversRoot}/${name}`;
|
||||
const res = insert.run(name, name, game, map, gameMode, mapSlug, hostDir);
|
||||
if (res.changes > 0) {
|
||||
n++;
|
||||
} else {
|
||||
backfill.run(game, map, name);
|
||||
backfill.run(game, map, gameMode, mapSlug, hostDir, name);
|
||||
}
|
||||
if (parsed && !parsed.mapCanonical) {
|
||||
console.warn(`[servers] unknown map alias '${parsed.mapAlias}' for ${name} — add to T5_MAP_ALIASES`);
|
||||
console.warn(
|
||||
`[servers] unknown map slug '${parsed.mapSlug}' for ${name} — add to T5_ZOMBIE_MAPS`
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -138,7 +161,15 @@ export function setServerField(
|
||||
'last_roster',
|
||||
'last_seen_at',
|
||||
'last_error',
|
||||
'last_reply_snippet'
|
||||
'last_reply_snippet',
|
||||
'game_mode',
|
||||
'map_slug',
|
||||
'host_dir',
|
||||
'config_file',
|
||||
'game_id',
|
||||
'image',
|
||||
'created_by',
|
||||
'destroyed_at'
|
||||
];
|
||||
if (!allowed.includes(field)) throw new Error(`refusing to set ${field}`);
|
||||
db().prepare(`UPDATE servers SET ${field} = ? WHERE name = ?`).run(value, name);
|
||||
|
||||
Reference in New Issue
Block a user