feat: add maintenance toggle command

This commit is contained in:
2026-09-18 15:21:28 +00:00 Unverified
parent e3df2f4d76
commit dcdacd5c04
12 changed files with 712 additions and 7 deletions
+2
View File
@@ -18,6 +18,7 @@ import { stop } from "./stop";
import { up } from "./up";
import { users } from "./users";
import { trust } from "./trust";
import { maintenance } from "./maintenance";
export const main = defineCommand({
meta: {
@@ -39,6 +40,7 @@ export const main = defineCommand({
export: exportCommand,
exec,
logs,
maintenance,
login,
logout,
operations,
+75
View File
@@ -0,0 +1,75 @@
import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { defineCommand } from "citty";
import { apiRequest, type ApiRequestInit } from "../lib/api";
import type { MaintenanceStatus } from "../shared/api";
type Request = <T>(path: string, init?: ApiRequestInit) => Promise<T>;
type Confirmation = (host: string) => Promise<boolean>;
const confirmationPath = join(
process.env.XDG_RUNTIME_DIR ?? "/tmp",
"kuber",
"maintenance-confirmation",
);
const TTL_MS = 60_000;
async function confirmed(host: string): Promise<boolean> {
try {
const value = JSON.parse(await readFile(confirmationPath, "utf8")) as {
host?: string;
expiresAt?: number;
};
if (
value.host === host &&
typeof value.expiresAt === "number" &&
value.expiresAt > Date.now()
) {
await rm(confirmationPath, { force: true });
return true;
}
} catch {}
await mkdir(join(confirmationPath, ".."), { recursive: true, mode: 0o700 });
await writeFile(
confirmationPath,
JSON.stringify({ host, expiresAt: Date.now() + TTL_MS }),
{ mode: 0o600 },
);
return false;
}
export async function runMaintenance(
host: string,
request: Request = apiRequest,
confirm: Confirmation = confirmed,
): Promise<MaintenanceStatus> {
const status = await request<MaintenanceStatus>(
`/maintenance/${encodeURIComponent(host)}`,
);
if (!(await confirm(status.host))) {
console.log(
`${status.host} maintenance is currently ${status.enabled ? "\x1b[31mON\x1b[0m" : "\x1b[32mOFF\x1b[0m"}, run this command again to toggle.`,
);
return status;
}
const result = await request<MaintenanceStatus>(
`/maintenance/${encodeURIComponent(status.host)}`,
{ method: "POST", json: { enabled: !status.enabled } },
);
console.log(
`${result.host} maintenance is now ${result.enabled ? "\x1b[31mON\x1b[0m" : "\x1b[32mOFF\x1b[0m"}`,
);
return result;
}
export const maintenance = defineCommand({
meta: {
name: "maintenance",
description: "Toggle a global hostname maintenance override",
},
args: {
host: { type: "positional", required: true, description: "DNS hostname" },
},
async run({ args }) {
await runMaintenance(args.host);
},
});