fix(code-queue): add issue 3 gateway diagnostics

This commit is contained in:
Codex
2026-05-19 03:32:16 +00:00
parent c00c695197
commit 9d46ca2531
18 changed files with 1494 additions and 39 deletions
@@ -430,6 +430,10 @@ function nativeServiceRef(service: ManagedService): { namespace: string; service
};
}
function deploymentName(service: ManagedService): string {
return routeString(service, "deploymentName", service.id);
}
function serviceProxyApiPath(service: ManagedService, targetPath: string): string {
const { serviceName, servicePort } = nativeServiceRef(service);
const safeTargetPath = targetPath.startsWith("/") ? targetPath : `/${targetPath}`;
@@ -922,6 +926,7 @@ async function probeEndpoint(endpoint: ManagedEndpoint): Promise<JsonRecord> {
async function probeKubernetesServiceActive(service: ManagedService): Promise<JsonRecord> {
const endpoint = activeEndpoint(service);
if (endpoint.healthMode === "pod-ready") return await probeKubernetesPodReady(service, endpoint);
return probeKubernetesEndpoint(service, endpoint, true);
}
@@ -995,6 +1000,68 @@ function podSummary(item: unknown): JsonRecord {
};
}
function conditionTrue(item: unknown, type: string): boolean {
const conditions = jsonAtPath(item, "status.conditions");
return Array.isArray(conditions) && conditions.some((condition) => {
const record = typeof condition === "object" && condition !== null ? condition as Record<string, unknown> : {};
return record.type === type && record.status === "True";
});
}
function integerAtPath(item: unknown, path: string): number {
const value = jsonAtPath(item, path);
return typeof value === "number" && Number.isFinite(value) ? Math.floor(value) : 0;
}
async function deploymentAvailabilityCheck(service: ManagedService): Promise<JsonRecord> {
const name = deploymentName(service);
const namespace = service.namespace;
try {
const deployment = await kubeApiJson(`/apis/apps/v1/namespaces/${encodeURIComponent(namespace)}/deployments/${encodeURIComponent(name)}`, config.healthTimeoutMs);
const desiredReplicas = Math.max(1, integerAtPath(deployment, "spec.replicas"));
const availableReplicas = integerAtPath(deployment, "status.availableReplicas");
const readyReplicas = integerAtPath(deployment, "status.readyReplicas");
const updatedReplicas = integerAtPath(deployment, "status.updatedReplicas");
const unavailableReplicas = integerAtPath(deployment, "status.unavailableReplicas");
const available = conditionTrue(deployment, "Available") || availableReplicas >= desiredReplicas;
return {
ok: available,
name,
namespace,
available,
desiredReplicas,
availableReplicas,
readyReplicas,
updatedReplicas,
unavailableReplicas,
};
} catch (error) {
return { ok: false, name, namespace, available: false, error: errorToJson(error) };
}
}
async function endpointNonEmptyCheck(service: ManagedService): Promise<JsonRecord> {
const { namespace, serviceName } = nativeServiceRef(service);
try {
const endpoints = await kubeApiJson(`/api/v1/namespaces/${encodeURIComponent(namespace)}/endpoints/${encodeURIComponent(serviceName)}`, config.healthTimeoutMs);
const subsets = Array.isArray(endpoints.subsets) ? endpoints.subsets : [];
const addresses = subsets.flatMap((subset) => {
const record = typeof subset === "object" && subset !== null ? subset as Record<string, unknown> : {};
return Array.isArray(record.addresses) ? record.addresses : [];
});
const readyAddressCount = addresses.length;
return {
ok: readyAddressCount > 0,
serviceName,
namespace,
readyAddressCount,
subsetCount: subsets.length,
};
} catch (error) {
return { ok: false, serviceName, namespace, readyAddressCount: 0, error: errorToJson(error) };
}
}
async function probeKubernetesPodReady(service: ManagedService, endpoint: ManagedEndpoint): Promise<JsonRecord> {
const checkedAt = new Date().toISOString();
const { namespace } = kubernetesEndpointServiceRef(service, endpoint);
@@ -1195,6 +1262,8 @@ async function serviceDiagnostics(service: ManagedService): Promise<JsonRecord>
status: "unhealthy",
error: errorToJson(error),
} satisfies JsonRecord));
const deployment = await deploymentAvailabilityCheck(service);
const endpoint = await endpointNonEmptyCheck(service);
const kubernetesApiServiceProxyOk = kubernetesApiServiceProxy.ok === true;
const targetServiceOk = targetService.ok === true;
const checks = {
@@ -1212,8 +1281,11 @@ async function serviceDiagnostics(service: ManagedService): Promise<JsonRecord>
},
targetService,
managedService,
deployment,
endpoint,
} satisfies Record<string, JsonValue>;
const ok = kubernetesApiServiceProxyOk && targetServiceOk;
const managedServiceOk = managedService.ok === true;
const ok = kubernetesApiServiceProxyOk && (targetServiceOk || managedServiceOk) && deployment.ok === true && endpoint.ok === true;
return {
ok,
service: "k3sctl-adapter",