Tag Komodo deployments with game + canonical map name

New deployments get two tags attached (e.g. "t5" and "zombie_pentagon")
so operators can filter the Komodo deployment list by game and by map.
Tags are ensured via read/ListTags + write/CreateTag fallback, then
attached with write/UpdateTagsOnResource against the deployment name.

Tag application runs fire-and-forget after CreateDeployment: any failure
logs a warning and the server creation proceeds. Tags are cosmetic
organization inside Komodo, not a correctness requirement.
This commit is contained in:
2026-09-17 09:15:00 -04:00
parent 5142a672ee
commit 5c674615d3
2 changed files with 122 additions and 2 deletions
+37 -2
View File
@@ -9,6 +9,8 @@ import {
komodoDestroyDeployment,
komodoDeleteDeployment,
komodoInspectHealthy,
komodoEnsureTag,
komodoUpdateTagsOnResource,
type CreateDeploymentSpec,
type DeploymentEnvVar
} from '../integrations/komodo.js';
@@ -198,7 +200,13 @@ export async function createServer(input: CreateServerInput): Promise<CreateServ
return { ok: false, kind: 'db', message: `failed to insert server row: ${(err as Error).message}` };
}
// Step 4: execute/Deploy — actually start the container.
// Step 4: apply Komodo tags so operators can filter the deployment list
// by game/map. Best-effort — a tag failure doesn't roll back the server;
// the deployment is fully functional without cosmetic tags. Fires in
// parallel to keep the create latency down.
void applyDeploymentTags(name, 't5', mapEntry.canonical);
// Step 5: execute/Deploy — actually start the container.
const deployRes = await komodoDeploy(name);
if (!deployRes.ok) {
// Container never started — undo everything so retrying is clean.
@@ -208,13 +216,40 @@ export async function createServer(input: CreateServerInput): Promise<CreateServ
return { ok: false, kind: 'komodo', message: `Deploy: ${deployRes.message}` };
}
// Step 5: kick the sweep so RCON status polling for this server starts
// Step 6: kick the sweep so RCON status polling for this server starts
// now instead of on the next 15s tick.
void kick().catch((err) => console.error('[createServer] post-create kick failed:', err));
return { ok: true, name, port };
}
/**
* Ensure `game` and `map` tags exist in Komodo, then attach both to the given
* deployment. Purely cosmetic — any failure here logs and returns; the caller
* treats it as fire-and-forget.
*/
async function applyDeploymentTags(deployment: string, gameTagName: string, mapTagName: string): Promise<void> {
try {
const [gameTag, mapTag] = await Promise.all([
komodoEnsureTag(gameTagName),
komodoEnsureTag(mapTagName)
]);
const tagIds: string[] = [];
if (gameTag.ok) tagIds.push(gameTag.id);
else console.warn(`[createServer] tag "${gameTagName}": ${gameTag.message}`);
if (mapTag.ok) tagIds.push(mapTag.id);
else console.warn(`[createServer] tag "${mapTagName}": ${mapTag.message}`);
if (tagIds.length === 0) return;
const res = await komodoUpdateTagsOnResource('Deployment', deployment, tagIds);
if (!res.ok) {
console.warn(`[createServer] UpdateTagsOnResource for ${deployment}: ${res.message}`);
}
} catch (err) {
console.warn(`[createServer] tag application for ${deployment} threw:`, err);
}
}
export async function destroyServer(name: string): Promise<DestroyServerResult> {
const row = getServer(name);
if (!row) {