// 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 { 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 }, ], }], }, }, }, }; }