fix: migrate JD01 registry to k3s workload

This commit is contained in:
Codex
2026-06-29 12:11:40 +00:00
parent 50bb9fbfe8
commit 912090ecd4
6 changed files with 405 additions and 17 deletions
+52 -2
View File
@@ -5,6 +5,7 @@ import { runCommand, type CommandResult } from "./command";
import { egressBenchmarkCompactResult, egressBenchmarkDryRun, egressBenchmarkStartScript, egressBenchmarkStatusScript, type EgressBenchmarkSpec } from "./egress-proxy-benchmark";
import { resolveEgressProxySourceRef } from "./egress-proxy-sources";
import { hwlabRuntimeLaneSpecForNode, isHwlabRuntimeLane, type HwlabRuntimeLaneSpec } from "./hwlab-node-lanes";
import { registryInfraManifest } from "./hwlab-node-control-plane-registry";
import {
HWLAB_NODE_CONTROL_PLANE_CONFIG_PATH,
type ArgoOptions,
@@ -21,6 +22,7 @@ import {
type ControlPlaneK3sNodeSpec,
type ControlPlaneK8sServiceEgressProxySpec,
type ControlPlaneNodeSpec,
type ControlPlaneRegistrySpec,
type ControlPlaneRuntimeProxySpec,
type ControlPlaneTargetSpec,
type ControlPlaneTektonArgoObserverRbacSpec,
@@ -1523,11 +1525,50 @@ function nodeSpec(id: string, raw: Record<string, unknown>): ControlPlaneNodeSpe
route: stringField(raw, "route", `nodes.${id}`),
kubeRoute: stringField(raw, "kubeRoute", `nodes.${id}`),
k3s,
registry: { endpoint: stringField(registry, "endpoint", `nodes.${id}.registry`) },
registry: registrySpec(registry, `nodes.${id}.registry`),
egressProxy,
};
}
function registrySpec(raw: Record<string, unknown>, path: string): ControlPlaneRegistrySpec {
const mode = stringField(raw, "mode", path);
const endpoint = stringField(raw, "endpoint", path);
if (mode === "host-docker") return { mode, endpoint };
if (mode !== "k8s-workload") throw new Error(`${path}.mode must be host-docker or k8s-workload`);
const imagePullPolicy = optionalStringField(raw, "imagePullPolicy", path) ?? "IfNotPresent";
if (imagePullPolicy !== "Always" && imagePullPolicy !== "IfNotPresent" && imagePullPolicy !== "Never") {
throw new Error(`${path}.imagePullPolicy must be Always, IfNotPresent, or Never`);
}
const namespace = stringField(raw, "namespace", path);
const deploymentName = stringField(raw, "deploymentName", path);
const serviceName = stringField(raw, "serviceName", path);
const pvcName = stringField(raw, "pvcName", path);
validateKubernetesName(namespace, `${path}.namespace`);
validateKubernetesName(deploymentName, `${path}.deploymentName`);
validateKubernetesName(serviceName, `${path}.serviceName`);
validateKubernetesName(pvcName, `${path}.pvcName`);
const image = stringField(raw, "image", path);
validatePublicBaseImage(image, `${path}.image`);
const hostNetwork = booleanField(raw, "hostNetwork", path);
const listenHost = stringField(raw, "listenHost", path);
if (listenHost !== "127.0.0.1" && listenHost !== "0.0.0.0") throw new Error(`${path}.listenHost must be 127.0.0.1 or 0.0.0.0`);
return {
mode,
endpoint,
namespace,
deploymentName,
serviceName,
pvcName,
storage: stringField(raw, "storage", path),
image,
imagePullPolicy,
containerPort: numberField(raw, "containerPort", path),
listenHost,
listenPort: numberField(raw, "listenPort", path),
hostNetwork,
};
}
function k3sNodeSpec(raw: Record<string, unknown>, path: string): ControlPlaneK3sNodeSpec {
const kubelet = asRecord(raw.kubelet, `${path}.kubelet`);
const serviceName = stringField(raw, "serviceName", path);
@@ -1872,7 +1913,7 @@ function targetSpec(raw: Record<string, unknown>, index: number): ControlPlaneTa
serviceWriteName,
cachePvcName: stringField(gitMirror, "cachePvcName", `${path}.gitMirror`),
cachePvcStorage: stringField(gitMirror, "cachePvcStorage", `${path}.gitMirror`),
cacheHostPath: optionalStringField(gitMirror, "cacheHostPath", `${path}.gitMirror`) ?? null,
cacheHostPath: nullableStringField(gitMirror, "cacheHostPath", `${path}.gitMirror`),
servicePort: numberField(gitMirror, "servicePort", `${path}.gitMirror`),
readContainerPort: numberField(gitMirror, "readContainerPort", `${path}.gitMirror`),
writeContainerPort: numberField(gitMirror, "writeContainerPort", `${path}.gitMirror`),
@@ -1923,6 +1964,8 @@ function renderInfraManifest(_node: ControlPlaneNodeSpec, target: ControlPlaneTa
addNamespace(target.ciNamespace);
addNamespace(target.runtimeNamespace);
addNamespace(target.gitMirror.namespace);
if (_node.registry.mode === "k8s-workload") addNamespace(_node.registry.namespace);
manifests.push(...registryInfraManifest(_node.registry, labels));
manifests.push(
{ apiVersion: "v1", kind: "ServiceAccount", metadata: { name: target.tekton.serviceAccountName, namespace: target.ciNamespace, labels } },
tektonRuntimeObserverRole(target, labels),
@@ -2791,6 +2834,13 @@ function optionalStringField(obj: Record<string, unknown>, key: string, path: st
return value;
}
function nullableStringField(obj: Record<string, unknown>, key: string, path: string): string | null {
const value = obj[key];
if (value === undefined || value === null) return null;
if (typeof value !== "string" || value.length === 0) throw new Error(`${path}.${key} must be a non-empty string when set`);
return value;
}
function absoluteConfigPathField(obj: Record<string, unknown>, key: string, path: string): string {
const value = stringField(obj, key, path);
if (!value.startsWith("/") || value.includes("\0") || value.includes("..")) throw new Error(`${path}.${key} must be an absolute path without '..'`);