From 550eea19d432eb101f8012960694f0852b176830 Mon Sep 17 00:00:00 2001 From: Codex Agent Date: Fri, 5 Jun 2026 08:58:49 +0800 Subject: [PATCH] fix: roll v02 metrics pods on sidecar script changes --- scripts/g14-gitops-render.mjs | 17 ++++++++++++----- scripts/g14-gitops-render.test.ts | 5 +++++ 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/scripts/g14-gitops-render.mjs b/scripts/g14-gitops-render.mjs index b7ee5bc0..9ba05e65 100644 --- a/scripts/g14-gitops-render.mjs +++ b/scripts/g14-gitops-render.mjs @@ -798,6 +798,10 @@ function v02MetricsSidecarVolume() { return { name: "hwlab-metrics-sidecar", configMap: { name: "hwlab-v02-metrics-sidecar" } }; } +function v02MetricsSidecarAnnotations(metricsSidecarSha256) { + return metricsSidecarSha256 ? { "hwlab.pikastech.local/metrics-sidecar-sha256": metricsSidecarSha256 } : {}; +} + function v02MetricsSidecarContainer({ serviceId, namespace, gitopsTarget }) { const service = v02ObservableService(serviceId); assert.ok(service, `unknown v0.2 observable service ${serviceId}`); @@ -837,7 +841,7 @@ function upsertV02MetricsPort(service) { service.spec.ports.push({ name: "metrics", port: 9100, targetPort: "metrics" }); } -function transformWorkloads({ workloads, deploy, catalog, source, sourceBranch = defaultBranch, registryPrefix, runtimeEndpoint, webEndpoint, profile = "dev", useDeployImages = false }) { +function transformWorkloads({ workloads, deploy, catalog, source, sourceBranch = defaultBranch, registryPrefix, runtimeEndpoint, webEndpoint, profile = "dev", useDeployImages = false, metricsSidecarSha256 = null }) { const result = cloneJson(workloads); const deployServices = deployServicesForProfile(deploy, profile); const namespace = namespaceNameForProfile(profile); @@ -888,6 +892,7 @@ function transformWorkloads({ workloads, deploy, catalog, source, sourceBranch = if (profile === "v02" && v02ObservableServiceIds.has(templateServiceId)) { label(item.metadata, v02MetricsLabels(templateServiceId)); label(podTemplate.metadata, v02MetricsLabels(templateServiceId)); + annotate(podTemplate.metadata, v02MetricsSidecarAnnotations(metricsSidecarSha256)); upsertV02MetricsSidecar(podTemplate.spec, { serviceId: templateServiceId, namespace, gitopsTarget }); } if ((item.kind === "Deployment" || item.kind === "StatefulSet") && item.spec?.selector?.matchLabels) { @@ -4046,7 +4051,7 @@ remotePort = ${edgeRemotePort} }; } -function deepSeekProxyManifest({ profile = "dev", source, registryPrefix = defaultRegistryPrefix, catalog = null, useDeployImages = false } = {}) { +function deepSeekProxyManifest({ profile = "dev", source, registryPrefix = defaultRegistryPrefix, catalog = null, useDeployImages = false, metricsSidecarSha256 = null } = {}) { const namespace = namespaceNameForProfile(profile); const bridgeServiceId = "hwlab-cloud-api"; const digestPin = profile === "v02"; @@ -4072,7 +4077,8 @@ function deepSeekProxyManifest({ profile = "dev", source, registryPrefix = defau "hwlab.pikastech.local/source-commit": bridgeCommit, "hwlab.pikastech.local/bridge-source-commit": bridgeCommit, "hwlab.pikastech.local/bridge-image-tag": bridgeImageTag, - "hwlab.pikastech.local/bridge-image": bridgeImage + "hwlab.pikastech.local/bridge-image": bridgeImage, + ...v02MetricsSidecarAnnotations(profile === "v02" ? metricsSidecarSha256 : null) }; return { apiVersion: "v1", @@ -4588,6 +4594,7 @@ async function plannedFiles(args) { const metricsSidecarScript = args.lane === "v02" ? await readFile(path.join(repoRoot, "internal/dev-entrypoint/metrics-sidecar.mjs"), "utf8") : null; + const metricsSidecarSha256 = metricsSidecarScript ? createHash("sha256").update(metricsSidecarScript).digest("hex") : null; const baseLabels = { "hwlab.pikastech.local/gitops-target": settings.gitopsTarget, "hwlab.pikastech.local/source-commit": source.full }; const annotations = { "hwlab.pikastech.local/rendered-by": "scripts/g14-gitops-render.mjs" }; const files = new Map(); @@ -4652,8 +4659,8 @@ async function plannedFiles(args) { if (profile !== "v02") putJson(`${runtimePath}/code-agent-codex-config.yaml`, transformListNamespace(config, namespace, profileLabels, annotations)); putJson(`${runtimePath}/services.yaml`, transformServices({ services, namespace, labels: profileLabels, annotations, profile })); putJson(`${runtimePath}/health-contract.yaml`, transformHealthContract(health, namespace, profileLabels, annotations, endpoints.runtimeEndpoint, endpoints.webEndpoint, profile)); - putJson(`${runtimePath}/workloads.yaml`, transformWorkloads({ workloads, deploy, catalog: artifactCatalog, source, sourceBranch: args.sourceBranch, registryPrefix: args.registryPrefix, runtimeEndpoint: endpoints.runtimeEndpoint, webEndpoint: endpoints.webEndpoint, profile, useDeployImages: args.useDeployImages })); - putJson(`${runtimePath}/deepseek-proxy.yaml`, deepSeekProxyManifest({ profile, source, registryPrefix: args.registryPrefix, catalog: artifactCatalog, useDeployImages: args.useDeployImages })); + putJson(`${runtimePath}/workloads.yaml`, transformWorkloads({ workloads, deploy, catalog: artifactCatalog, source, sourceBranch: args.sourceBranch, registryPrefix: args.registryPrefix, runtimeEndpoint: endpoints.runtimeEndpoint, webEndpoint: endpoints.webEndpoint, profile, useDeployImages: args.useDeployImages, metricsSidecarSha256 })); + putJson(`${runtimePath}/deepseek-proxy.yaml`, deepSeekProxyManifest({ profile, source, registryPrefix: args.registryPrefix, catalog: artifactCatalog, useDeployImages: args.useDeployImages, metricsSidecarSha256 })); if (profile === "v02") putJson(`${runtimePath}/postgres.yaml`, v02PostgresManifest({ migrationSql, source })); if (profile === "v02") putJson(`${runtimePath}/observability.yaml`, observabilityManifest({ namespace, labels: profileLabels, annotations, metricsSidecarScript })); if (includeDeviceAgent) putJson(`${runtimePath}/device-agent-71-freq.yaml`, deviceAgent71FreqManifest({ profile, source, registryPrefix: args.registryPrefix, catalog: artifactCatalog, useDeployImages: args.useDeployImages })); diff --git a/scripts/g14-gitops-render.test.ts b/scripts/g14-gitops-render.test.ts index e4796edb..b82661fe 100644 --- a/scripts/g14-gitops-render.test.ts +++ b/scripts/g14-gitops-render.test.ts @@ -239,6 +239,7 @@ test("v02 render follows TypeScript runtime checks and does not self-patch boots assert.ok(sidecar, `missing metrics sidecar for ${serviceId}`); assert.match(sidecar.image, /hwlab-ci-node-tools:node22-alpine-bun-v1/u); assert.deepEqual(sidecar.command, ["node", "/metrics/metrics-sidecar.mjs"]); + assert.match(workload.spec.template.metadata.annotations["hwlab.pikastech.local/metrics-sidecar-sha256"], /^[a-f0-9]{64}$/u); assert.ok(sidecar.env.some((entry) => entry.name === "HWLAB_METRICS_SERVICE_ID" && entry.value === serviceId)); assert.ok(sidecar.ports.some((port) => port.name === "metrics" && port.containerPort === 9100)); } @@ -247,6 +248,10 @@ test("v02 render follows TypeScript runtime checks and does not self-patch boots assert.ok(deepseekService.spec.ports.some((port) => port.name === "metrics" && port.port === 9100)); const deepseekDeployment = deepseekProxy.items.find((item) => item.kind === "Deployment" && item.metadata?.name === "hwlab-deepseek-proxy"); assert.ok(deepseekDeployment.spec.template.spec.containers.some((container) => container.name === "hwlab-metrics")); + assert.equal( + deepseekDeployment.spec.template.metadata.annotations["hwlab.pikastech.local/metrics-sidecar-sha256"], + workloadsJson.items.find((item) => item.kind === "Deployment" && item.metadata?.name === "hwlab-cloud-api").spec.template.metadata.annotations["hwlab.pikastech.local/metrics-sidecar-sha256"] + ); const observabilityItems = observabilityJson.items ?? []; const metricsConfig = observabilityItems.find((item) => item.kind === "ConfigMap" && item.metadata?.name === "hwlab-v02-metrics-sidecar"); assert.ok(metricsConfig, "missing metrics sidecar ConfigMap");