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
+34 -18
View File
@@ -6,6 +6,7 @@ import {
type V1LabelSelector,
} from "@kubernetes/client-node";
import { PassThrough } from "node:stream";
import { logKubernetesRequest } from "../lib/request-log";
import {
KubernetesLogError,
type ContainerLogRequest,
@@ -19,7 +20,9 @@ function selector(labels: Readonly<Record<string, string>>): string {
.join(",");
}
function matchLabels(value: V1LabelSelector | undefined): Record<string, string> {
function matchLabels(
value: V1LabelSelector | undefined,
): Record<string, string> {
if (value?.matchExpressions?.length) return {};
return value?.matchLabels ?? {};
}
@@ -62,7 +65,9 @@ export class KubernetesLogs implements KubernetesLogsBackend {
return deployments.items.flatMap((deployment) => {
const name = deployment.metadata?.name;
const labels = matchLabels(deployment.spec?.selector);
return name && Object.keys(labels).length ? [{ name, selector: labels }] : [];
return name && Object.keys(labels).length
? [{ name, selector: labels }]
: [];
});
} catch (error) {
throw logError(error);
@@ -71,7 +76,10 @@ export class KubernetesLogs implements KubernetesLogsBackend {
async getService(namespace: string, name: string) {
try {
const service = await this.core.readNamespacedService({ namespace, name });
const service = await this.core.readNamespacedService({
namespace,
name,
});
return { name, selector: service.spec?.selector ?? {} };
} catch (error) {
if (statusCode(error) === 404) return;
@@ -79,10 +87,7 @@ export class KubernetesLogs implements KubernetesLogsBackend {
}
}
async listPods(
namespace: string,
labels: Readonly<Record<string, string>>,
) {
async listPods(namespace: string, labels: Readonly<Record<string, string>>) {
try {
const pods = await this.core.listNamespacedPod({
namespace,
@@ -92,7 +97,9 @@ export class KubernetesLogs implements KubernetesLogsBackend {
name: pod.metadata?.name ?? "",
uid: pod.metadata?.uid ?? "",
phase: pod.status?.phase,
containers: (pod.spec?.containers ?? []).map((container) => container.name),
containers: (pod.spec?.containers ?? []).map(
(container) => container.name,
),
}));
} catch (error) {
throw logError(error);
@@ -126,18 +133,27 @@ export class KubernetesLogs implements KubernetesLogsBackend {
};
signal.addEventListener("abort", abort, { once: true });
try {
upstream = await this.logger.log(
request.namespace,
request.pod,
request.container,
output,
upstream = await logKubernetesRequest(
{
follow: true,
tailLines: request.tailLines,
sinceSeconds: request.sinceSeconds,
sinceTime: request.sinceTime,
timestamps: request.timestamps,
method: "GET",
pathname: `/api/v1/namespaces/${request.namespace}/pods/${request.pod}/log`,
body: undefined,
attempt: 1,
},
() =>
this.logger.log(
request.namespace,
request.pod,
request.container,
output,
{
follow: true,
tailLines: request.tailLines,
sinceSeconds: request.sinceSeconds,
sinceTime: request.sinceTime,
timestamps: request.timestamps,
},
),
);
if (signal.aborted) abort();
for await (const chunk of output) yield new Uint8Array(chunk);