feat: enhance database and storage management with Longhorn support
This commit is contained in:
+52
-29
@@ -2,6 +2,7 @@ import { defineCommand } from "citty";
|
||||
import https from "node:https";
|
||||
import { createLogger } from "../lib/logger";
|
||||
import { core, kc } from "../lib/k8s";
|
||||
import { delay, parseRetryAfter } from "../lib/k8s-http";
|
||||
import {
|
||||
getPodContainerName,
|
||||
listManagedDeployments,
|
||||
@@ -13,10 +14,6 @@ function formatError(error: unknown): string {
|
||||
return String(error);
|
||||
}
|
||||
|
||||
function delay(ms: number) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function streamResponseLines(
|
||||
stream: NodeJS.ReadableStream,
|
||||
onLine: (line: string) => void,
|
||||
@@ -49,7 +46,9 @@ async function followPodLogs(
|
||||
const cluster = kc.getCurrentCluster();
|
||||
if (!cluster) throw new Error("No currently active cluster");
|
||||
|
||||
const requestURL = new URL(`${cluster.server}/api/v1/namespaces/${namespace}/pods/${podName}/log`);
|
||||
const requestURL = new URL(
|
||||
`${cluster.server}/api/v1/namespaces/${namespace}/pods/${podName}/log`,
|
||||
);
|
||||
requestURL.searchParams.set("container", containerName);
|
||||
requestURL.searchParams.set("follow", "true");
|
||||
|
||||
@@ -63,30 +62,49 @@ async function followPodLogs(
|
||||
};
|
||||
await kc.applyToHTTPSOptions(options);
|
||||
|
||||
await new Promise<void>((resolve, reject) => {
|
||||
const request = https.request(options, async (response) => {
|
||||
if ((response.statusCode ?? 0) < 200 || (response.statusCode ?? 0) > 299) {
|
||||
const chunks: Buffer[] = [];
|
||||
response.on("data", (chunk) => {
|
||||
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
||||
});
|
||||
response.on("end", () => {
|
||||
reject(Buffer.concat(chunks).toString("utf8") || `HTTP ${response.statusCode}`);
|
||||
});
|
||||
return;
|
||||
}
|
||||
for (let attempt = 0; ; attempt += 1) {
|
||||
const result = await new Promise<{
|
||||
statusCode: number;
|
||||
retryAfter?: string;
|
||||
body?: string;
|
||||
}>((resolve, reject) => {
|
||||
const request = https.request(options, async (response) => {
|
||||
const statusCode = response.statusCode ?? 0;
|
||||
if (statusCode < 200 || statusCode > 299) {
|
||||
const chunks: Buffer[] = [];
|
||||
response.on("data", (chunk) => {
|
||||
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
||||
});
|
||||
response.on("end", () => {
|
||||
resolve({
|
||||
statusCode,
|
||||
retryAfter: response.headers["retry-after"],
|
||||
body: Buffer.concat(chunks).toString("utf8"),
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await streamResponseLines(response, writeLine);
|
||||
resolve();
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
try {
|
||||
await streamResponseLines(response, writeLine);
|
||||
resolve({ statusCode });
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
|
||||
request.on("error", reject);
|
||||
request.end();
|
||||
});
|
||||
|
||||
request.on("error", reject);
|
||||
request.end();
|
||||
});
|
||||
if (result.statusCode >= 200 && result.statusCode <= 299) return;
|
||||
if (result.statusCode !== 429 || attempt >= 3) {
|
||||
throw new Error(result.body || `HTTP ${result.statusCode}`);
|
||||
}
|
||||
|
||||
const retryAfter = parseRetryAfter(result.retryAfter);
|
||||
await delay(retryAfter ?? 250 * 2 ** attempt, signal);
|
||||
}
|
||||
}
|
||||
|
||||
async function followDeploymentLogs(name: string, signal: AbortSignal) {
|
||||
@@ -98,7 +116,11 @@ async function followDeploymentLogs(name: string, signal: AbortSignal) {
|
||||
|
||||
for (const pod of pods) {
|
||||
const podName = pod.metadata?.name;
|
||||
if (!podName || activePods.has(podName) || pod.status?.phase !== "Running") {
|
||||
if (
|
||||
!podName ||
|
||||
activePods.has(podName) ||
|
||||
pod.status?.phase !== "Running"
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -118,7 +140,7 @@ async function followDeploymentLogs(name: string, signal: AbortSignal) {
|
||||
});
|
||||
}
|
||||
|
||||
await delay(2000);
|
||||
await delay(2000, signal);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -127,7 +149,8 @@ async function logDeployment(name: string, follow: boolean) {
|
||||
|
||||
if (!follow) {
|
||||
const pods = await listPodsForDeployment(name);
|
||||
if (pods.length === 0) throw new Error(`No pods found for deployment ${name}`);
|
||||
if (pods.length === 0)
|
||||
throw new Error(`No pods found for deployment ${name}`);
|
||||
|
||||
for (const pod of pods) {
|
||||
const podName = pod.metadata?.name;
|
||||
|
||||
Reference in New Issue
Block a user