Files
pikasTech-unidesk/scripts/src/cicd-hwlab-refresh.ts
T

95 lines
4.3 KiB
TypeScript

// SPEC: PJ2026-01060703 CI/CD branch follower HWLAB native refresh.
// Responsibility: create the Kubernetes Job that refreshes HWLAB node Tekton Pipeline from a git-mirror snapshot.
import { runNativeK8sJob } from "./cicd-native";
import type { BranchFollowerRegistry, FollowerSpec, NativeK8sJobResult } from "./cicd-types";
import type { HwlabRuntimeLaneSpec } from "./hwlab-node-lanes";
import { nodeRuntimeGitMirrorTarget, nodeRuntimeRenderOverlay } from "./hwlab-node/web-probe";
export function runNativeHwlabControlPlaneRefresh(
registry: BranchFollowerRegistry,
follower: FollowerSpec,
spec: HwlabRuntimeLaneSpec,
observedSha: string,
timeoutSeconds: number,
jobName: string,
): { jobName: string; namespace: string; result: NativeK8sJobResult } {
const namespace = registry.controller.namespace;
const result = runNativeK8sJob(namespace, jobName, nativeHwlabControlPlaneRefreshJobManifest(registry, follower, spec, observedSha, jobName, timeoutSeconds), timeoutSeconds, "control-plane-refresh", registry.controller.budgets);
return { jobName, namespace, result };
}
export function nativeHwlabControlPlaneRefreshJobManifest(
registry: BranchFollowerRegistry,
follower: FollowerSpec,
spec: HwlabRuntimeLaneSpec,
observedSha: string,
jobName: string,
timeoutSeconds: number,
): Record<string, unknown> {
const mirror = nodeRuntimeGitMirrorTarget(spec);
const overlay = Buffer.from(JSON.stringify(nodeRuntimeRenderOverlay(spec)), "utf8").toString("base64");
const sourceStageRef = `${follower.source.snapshotPrefix.replace(/\/+$/u, "")}/${observedSha}`;
const tektonNamespace = follower.nativeStatus.tekton?.namespace;
if (tektonNamespace === undefined) throw new Error(`follower ${follower.id} nativeStatus.tekton.namespace is required for HWLAB control-plane refresh`);
return {
apiVersion: "batch/v1",
kind: "Job",
metadata: {
name: jobName,
namespace: registry.controller.namespace,
labels: {
"app.kubernetes.io/name": "hwlab-node-control-plane-refresh",
"app.kubernetes.io/part-of": "unidesk-cicd-branch-follower",
"app.kubernetes.io/component": "control-plane-refresh",
"hwlab.pikastech.local/node": spec.nodeId,
"hwlab.pikastech.local/lane": spec.lane,
"hwlab.pikastech.local/source-commit": observedSha,
},
},
spec: {
backoffLimit: follower.budgets.capabilityJobBackoffLimit,
ttlSecondsAfterFinished: follower.budgets.capabilityJobTtlSeconds,
template: {
metadata: {
labels: {
"app.kubernetes.io/name": "hwlab-node-control-plane-refresh",
"app.kubernetes.io/part-of": "unidesk-cicd-branch-follower",
"app.kubernetes.io/component": "control-plane-refresh",
"hwlab.pikastech.local/node": spec.nodeId,
"hwlab.pikastech.local/lane": spec.lane,
"hwlab.pikastech.local/source-commit": observedSha,
},
},
spec: {
restartPolicy: "Never",
serviceAccountName: registry.controller.serviceAccountName,
hostNetwork: true,
dnsPolicy: "ClusterFirstWithHostNet",
volumes: [
{ name: "native-scripts", configMap: { name: registry.controller.configMapName, defaultMode: 0o755 } },
],
containers: [{
name: "control-plane-refresh",
image: mirror.toolsImage,
imagePullPolicy: mirror.toolsImagePullPolicy,
command: ["node", "/etc/unidesk-cicd-branch-follower/hwlab-node-control-plane-refresh.mjs"],
volumeMounts: [
{ name: "native-scripts", mountPath: "/etc/unidesk-cicd-branch-follower", readOnly: true },
],
env: [
{ name: "SOURCE_COMMIT", value: observedSha },
{ name: "SOURCE_STAGE_REF", value: sourceStageRef },
{ name: "GIT_READ_URL", value: spec.gitReadUrl },
{ name: "FIELD_MANAGER", value: spec.controlPlaneFieldManager },
{ name: "TEKTON_NAMESPACE", value: tektonNamespace },
{ name: "KUBE_REQUEST_TIMEOUT_SECONDS", value: String(timeoutSeconds) },
{ name: "RUNTIME_GITOPS_CONFIGMAP_NAME", value: `${spec.pipeline}-runtime-gitops-scripts` },
{ name: "HWLAB_RENDER_OVERLAY_B64", value: overlay },
],
}],
},
},
},
};
}