feat: PXE debug boot mode for rescue/diagnostics #4

Merged
michal merged 16 commits from wip/ks-debugging into main 2026-03-30 02:59:35 +00:00
3 changed files with 95 additions and 2 deletions
Showing only changes of commit 0c1e18cee1 - Show all commits

View File

@@ -34,6 +34,7 @@ async function main(): Promise<void> {
server: { server: {
findMany: () => dbError(), findMany: () => dbError(),
findUnique: () => dbError(), findUnique: () => dbError(),
upsert: () => dbError(),
}, },
joinToken: { joinToken: {
findUnique: () => dbError(), findUnique: () => dbError(),

View File

@@ -80,9 +80,54 @@ export function registerBastionRoutes(app: FastifyInstance, db: DbClient): void
}); });
}); });
// Aggregated machines from all connected bastions // Aggregated machines from all connected bastions + DB fallback
app.get("/api/machines", async () => { app.get("/api/machines", async () => {
return bastionRegistry.getAggregatedState(); const live = bastionRegistry.getAggregatedState();
// Merge DB records for machines not currently in any bastion's live state
try {
const dbServers = (await db.server.findMany({})) as Array<{
mac: string | null; hostname: string; role: string; ip: string | null;
status: string; labels: Record<string, unknown>;
}>;
for (const s of dbServers) {
if (!s.mac) continue;
const mac = s.mac.toLowerCase();
// Only add from DB if not already in live state
if (!(mac in live.discovered) && !(mac in live.install_queue) && !(mac in live.installed)) {
if (s.status === "discovered") {
live.discovered[mac] = {
mac,
product: String(s.labels?.product ?? "unknown"),
board: "unknown",
serial: "unknown",
manufacturer: String(s.labels?.manufacturer ?? "unknown"),
cpu_model: String(s.labels?.cpu ?? "unknown"),
cpu_cores: Number(s.labels?.cores ?? 0),
memory_gb: Number(s.labels?.memory_gb ?? 0),
arch: String(s.labels?.arch ?? "unknown"),
disks: [],
nics: [],
first_seen: "",
last_seen: "",
bastionId: "db",
};
} else if (s.status === "online" || s.status === "offline") {
live.installed[mac] = {
hostname: s.hostname,
role: s.role,
ip: s.ip ?? "",
installed_at: "",
bastionId: "db",
};
}
}
}
} catch {
// DB unavailable — return live state only
}
return live;
}); });
// Queue install — route to correct bastion by MAC // Queue install — route to correct bastion by MAC

View File

@@ -19,6 +19,7 @@ export interface DbClient {
server: { server: {
findMany: (...args: unknown[]) => Promise<unknown[]>; findMany: (...args: unknown[]) => Promise<unknown[]>;
findUnique: (...args: unknown[]) => Promise<unknown>; findUnique: (...args: unknown[]) => Promise<unknown>;
upsert: (...args: unknown[]) => Promise<unknown>;
}; };
joinToken: { joinToken: {
findUnique: (...args: unknown[]) => Promise<unknown>; findUnique: (...args: unknown[]) => Promise<unknown>;
@@ -175,6 +176,52 @@ export async function createApp(_config: LabdConfig, db: DbClient): Promise<{
if (bastionId) { if (bastionId) {
bastionRegistry.updateState(bastionId, msg.state); bastionRegistry.updateState(bastionId, msg.state);
logger.info(`Bastion ${bastionId.slice(0, 8)} state sync: ${Object.keys(msg.state.discovered).length} discovered, ${Object.keys(msg.state.installed).length} installed`); logger.info(`Bastion ${bastionId.slice(0, 8)} state sync: ${Object.keys(msg.state.discovered).length} discovered, ${Object.keys(msg.state.installed).length} installed`);
// Persist machines to DB
void (async () => {
try {
// Upsert discovered machines
for (const [mac, hw] of Object.entries(msg.state.discovered)) {
await db.server.upsert({
where: { mac },
create: {
hostname: hw.product ?? mac,
mac,
role: "unknown",
status: "discovered",
labels: { cpu: hw.cpu_model, cores: hw.cpu_cores, memory_gb: hw.memory_gb, arch: hw.arch, product: hw.product, manufacturer: hw.manufacturer },
},
update: {
status: "discovered",
lastHeartbeat: new Date(),
labels: { cpu: hw.cpu_model, cores: hw.cpu_cores, memory_gb: hw.memory_gb, arch: hw.arch, product: hw.product, manufacturer: hw.manufacturer },
},
});
}
// Upsert installed machines
for (const [mac, info] of Object.entries(msg.state.installed)) {
await db.server.upsert({
where: { mac },
create: {
hostname: info.hostname,
mac,
role: info.role ?? "worker",
ip: info.ip,
status: "online",
},
update: {
hostname: info.hostname,
role: info.role ?? "worker",
ip: info.ip,
status: "online",
lastHeartbeat: new Date(),
},
});
}
} catch (err) {
logger.warn(`Failed to persist machines to DB: ${err instanceof Error ? err.message : String(err)}`);
}
})();
} }
break; break;
} }