From 1d6a6d696049e0c48b6f1df7dbe5f224ee1a3f54 Mon Sep 17 00:00:00 2001 From: Benjamin Borbe Date: Thu, 22 Oct 2026 09:38:35 +0200 Subject: [PATCH 1/2] fix(helm): keep agent PVCs on stale apply, chart 0.16.0 --- CHANGELOG.md | 4 ++++ helm/Chart.yaml | 2 +- helm/templates/agents.yaml | 4 ++++ 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b3e21f..20875bf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ Please choose versions by [Semantic Versioning](http://semver.org/). * MINOR version when you add functionality in a backwards-compatible manner, and * PATCH version when you make backwards-compatible bug fixes. +## Unreleased + +- fix(helm): render `helm.sh/resource-policy: keep` on agent PVCs and bump the chart to 0.16.0, so a stale apply whose render drops a claim (2026-10-21: `a2a/update-go-cache` on sun) cannot delete it and deadlock the Jobs that mount it. + ## v0.118.0 - feat(helm): the Config CRD in `helm/crds/config-crd.yaml` now declares `spec.rerunOnLostClaim` as `{type: boolean}` with no schema default, matching the executor binary's `configSpecProperties()` — unset means true, so existing Configs are unaffected; keeps a fresh install's CRD identical to the one the executor installs. Shipped in the published chart 0.15.0 with no version bump of its own, since `clusterAssigner.excludeAssignees` had already taken the chart to 0.15.0. diff --git a/helm/Chart.yaml b/helm/Chart.yaml index 3d5578b..b0cea50 100644 --- a/helm/Chart.yaml +++ b/helm/Chart.yaml @@ -3,7 +3,7 @@ name: agent description: bborbe agent framework — event-driven, Kafka-based, K8s-native task platform (controller, executor, and example agents) type: application # Chart version — bumped on chart changes, independent of appVersion. -version: 0.15.0 +version: 0.16.0 # Default image tag for the framework components when values don't override. appVersion: "0.3.1" home: https://github.com/bborbe/agent diff --git a/helm/templates/agents.yaml b/helm/templates/agents.yaml index 4f2c006..5371d9d 100644 --- a/helm/templates/agents.yaml +++ b/helm/templates/agents.yaml @@ -85,11 +85,15 @@ data: # agent is excluded: the executor's StatefulSet provisions its own volume from # volumeClaimTemplates, so a claim rendered here would be a second, unmounted # one — and spec.volumeClaim is ignored on that path, so it would be invisible. +# resource-policy keep: a stale apply whose render drops this claim must not +# delete it — Helm reads the policy from the release record before pruning. apiVersion: v1 kind: PersistentVolumeClaim metadata: name: {{ $agent.volumeClaim | default $agent.name }} namespace: {{ include "agent.namespace" $ }} + annotations: + helm.sh/resource-policy: keep labels: {{- include "agent.labels" $ | nindent 4 }} spec: From 1cdf4d2453e7468024883de3a7eacb3c0abe0bdb Mon Sep 17 00:00:00 2001 From: Benjamin Borbe Date: Thu, 22 Oct 2026 09:51:27 +0200 Subject: [PATCH 2/2] test(helm): assert PVC keep policy; document live-object and uninstall semantics --- CHANGELOG.md | 2 +- hack/test-helm-render.sh | 36 ++++++++++++++++++++++++++++++++++++ helm/templates/agents.yaml | 5 ++++- 3 files changed, 41 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20875bf..1be916e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ Please choose versions by [Semantic Versioning](http://semver.org/). ## Unreleased -- fix(helm): render `helm.sh/resource-policy: keep` on agent PVCs and bump the chart to 0.16.0, so a stale apply whose render drops a claim (2026-10-21: `a2a/update-go-cache` on sun) cannot delete it and deadlock the Jobs that mount it. +- fix(helm): render `helm.sh/resource-policy: keep` on agent PVCs and bump the chart to 0.16.0, so a stale apply whose render drops a claim (2026-10-21: `a2a/update-go-cache` on sun) cannot delete it and deadlock the Jobs that mount it. The claim is also kept on `helm uninstall` and when its agent leaves values — remove it with `kubectl delete pvc`. Helm reads the policy from the live object, so it protects only after this chart has been applied once. ## v0.118.0 diff --git a/hack/test-helm-render.sh b/hack/test-helm-render.sh index 6b41242..7be6d56 100755 --- a/hack/test-helm-render.sh +++ b/hack/test-helm-render.sh @@ -188,6 +188,42 @@ run_ca_case ca-absent "$tmpdir/ca-absent.yaml" empty run_ca_case ca-one "$tmpdir/ca-one.yaml" "releaser" run_ca_case ca-two "$tmpdir/ca-two.yaml" "releaser,claude" +# Agent PVC: rendered only for a job agent with volumeMountPath, and always +# carries helm.sh/resource-policy: keep so a render that drops it cannot prune it. + +# run_pvc_case <0|1 expected PVC count> +run_pvc_case() { + local name="$1" + local values="$2" + local expect="$3" + local out="$tmpdir/$name.out" + + "$helm_bin" template x "$CHART_DIR" -f "$values" --show-only templates/agents.yaml >"$out" + + local count + count="$(grep -c '^kind: PersistentVolumeClaim$' "$out" || true)" + if [ "$count" -ne "$expect" ]; then + echo "FAIL: $name: expected $expect PersistentVolumeClaim, got $count" + fail=1 + return + fi + if [ "$expect" -eq 1 ] && ! grep -qx ' helm.sh/resource-policy: keep' "$out"; then + echo "FAIL: $name: PVC missing 'helm.sh/resource-policy: keep'" + fail=1 + return + fi + + echo "OK: $name" +} + +write_values "$tmpdir/pvc-job.yaml" "volumeMountPath: /data" +write_values "$tmpdir/pvc-service.yaml" "volumeMountPath: /data" +printf ' type: service\n' >>"$tmpdir/pvc-service.yaml" + +run_pvc_case pvc-job "$tmpdir/pvc-job.yaml" 1 +run_pvc_case pvc-no-mount "$tmpdir/unset.yaml" 0 +run_pvc_case pvc-service "$tmpdir/pvc-service.yaml" 0 + if [ "$fail" -ne 0 ]; then exit 1 fi diff --git a/helm/templates/agents.yaml b/helm/templates/agents.yaml index 5371d9d..2f1b40b 100644 --- a/helm/templates/agents.yaml +++ b/helm/templates/agents.yaml @@ -86,7 +86,10 @@ data: # volumeClaimTemplates, so a claim rendered here would be a second, unmounted # one — and spec.volumeClaim is ignored on that path, so it would be invisible. # resource-policy keep: a stale apply whose render drops this claim must not -# delete it — Helm reads the policy from the release record before pruning. +# delete it. Helm reads the policy from the LIVE object at prune time, so it +# protects only once an apply of this chart has written it onto the claim. It +# also keeps the claim on `helm uninstall` and when the agent leaves values — +# clean up by hand: kubectl delete pvc -n . apiVersion: v1 kind: PersistentVolumeClaim metadata: