feat: improve resource reconciliation and observability

This commit is contained in:
2026-09-11 10:51:57 +00:00 Unverified
parent 0067a2cdcd
commit e3df2f4d76
28 changed files with 2407 additions and 217 deletions
+51 -41
View File
@@ -7,6 +7,7 @@ import {
type V1Status,
} from "@kubernetes/client-node";
import { PassThrough } from "node:stream";
import { logKubernetesRequest } from "../lib/request-log";
import {
type ExecDeployment,
type ExecPod,
@@ -17,18 +18,14 @@ import {
type KubernetesExecRequest,
} from "./exec-service";
function selectorString(
labels: Readonly<Record<string, string>>,
): string {
function selectorString(labels: Readonly<Record<string, string>>): string {
return Object.entries(labels)
.sort(([left], [right]) => left.localeCompare(right))
.map(([key, value]) => `${key}=${value}`)
.join(",");
}
function matchLabels(
deployment: V1Deployment,
): Record<string, string> {
function matchLabels(deployment: V1Deployment): Record<string, string> {
const matchExpressions = deployment.spec?.selector?.matchExpressions;
if (matchExpressions?.length) return {};
return deployment.spec?.selector?.matchLabels ?? {};
@@ -37,11 +34,13 @@ function matchLabels(
async function ownerDeploymentUid(
apps: AppsV1Api,
namespace: string,
ownerReferences: Array<{
kind?: string;
name?: string;
uid?: string;
}> | undefined,
ownerReferences:
| Array<{
kind?: string;
name?: string;
uid?: string;
}>
| undefined,
): Promise<string> {
if (!ownerReferences?.length) return "";
for (const ref of ownerReferences) {
@@ -153,27 +152,25 @@ export class KubernetesExec implements KubernetesExecBackend {
pod.metadata?.ownerReferences,
);
const containerStatuses = pod.status?.containerStatuses ?? [];
const containers: ExecPodContainer[] = (
pod.spec?.containers ?? []
).map((container) => {
const status = containerStatuses.find(
(item) => item.name === container.name,
);
return {
name: container.name ?? "",
running: status?.state?.running !== undefined,
ready: status?.ready,
};
});
const containers: ExecPodContainer[] = (pod.spec?.containers ?? []).map(
(container) => {
const status = containerStatuses.find(
(item) => item.name === container.name,
);
return {
name: container.name ?? "",
running: status?.state?.running !== undefined,
ready: status?.ready,
};
},
);
pods.push({
name,
uid,
deploymentUid,
phase: pod.status?.phase,
deletionTimestamp: pod.metadata?.deletionTimestamp
? new Date(
pod.metadata.deletionTimestamp,
).toISOString()
? new Date(pod.metadata.deletionTimestamp).toISOString()
: undefined,
containers,
});
@@ -206,22 +203,35 @@ export class KubernetesExec implements KubernetesExecBackend {
signal.addEventListener("abort", abort, { once: true });
try {
const ws = await this.execClient.exec(
request.namespace,
request.pod,
request.container,
[...request.command],
stdout,
stderr,
stdin,
request.tty,
(status) => {
completed({
exitCode: exitCodeFromStatus(status) ?? 1,
reason: status.reason,
message: status.message,
});
const ws = await logKubernetesRequest(
{
method: "GET",
pathname: `/api/v1/namespaces/${request.namespace}/pods/${request.pod}/exec`,
body: {
container: request.container,
command: request.command,
tty: request.tty,
},
attempt: 1,
},
() =>
this.execClient.exec(
request.namespace,
request.pod,
request.container,
[...request.command],
stdout,
stderr,
stdin,
request.tty,
(status) => {
completed({
exitCode: exitCodeFromStatus(status) ?? 1,
reason: status.reason,
message: status.message,
});
},
),
);
close = () => {
try {