Files
kuber/command/exec.ts
T
2026-08-28 21:19:50 +07:00

61 lines
1.8 KiB
TypeScript

import { defineCommand } from "citty";
import { getPodContainerName, getPodForDeployment } from "../lib/shared";
import { execClient } from "../lib/k8s";
function prepareInteractiveStdin(): (() => void) | undefined {
if (!process.stdin.isTTY) return;
process.stdin.setRawMode?.(true);
process.stdin.resume();
return () => {
process.stdin.setRawMode?.(false);
process.stdin.pause();
};
}
export const exec = defineCommand({
meta: {
name: "exec",
description: "Execute a command inside a deployment pod",
},
async run({ args }) {
const [deployment, ...command] = args._;
if (!deployment) throw new Error("Deployment name is required");
if (command.length === 0) throw new Error("Command is required");
const pod = await getPodForDeployment(deployment);
if (pod.status?.phase !== "Running") {
throw new Error(
`Deployment ${deployment} has no running pod to exec into (${pod.metadata?.name ?? "unknown pod"} is ${pod.status?.phase ?? "not ready"})`,
);
}
const namespace = pod.metadata?.namespace ?? "default";
const podName = pod.metadata?.name;
if (!podName) throw new Error(`No pod name found for deployment ${deployment}`);
const restoreStdin = prepareInteractiveStdin();
try {
const socket = await execClient.exec(
namespace,
podName,
getPodContainerName(pod),
command,
process.stdout,
process.stderr,
process.stdin,
Boolean(process.stdin.isTTY),
);
await new Promise<void>((resolve, reject) => {
socket.onclose = () => resolve();
socket.onerror = (event: { error?: unknown }) =>
reject(event.error ?? new Error("Exec failed"));
});
} finally {
restoreStdin?.();
}
},
});