Skip to content

feat(helm): add persistence.existingClaim support#166

Open
white1033 wants to merge 2 commits intoopenabdev:mainfrom
white1033:feat/persistence-existing-claim
Open

feat(helm): add persistence.existingClaim support#166
white1033 wants to merge 2 commits intoopenabdev:mainfrom
white1033:feat/persistence-existing-claim

Conversation

@white1033
Copy link
Copy Markdown

@white1033 white1033 commented Apr 9, 2026

What problem does this solve?

When upgrading from an older Helm release name (e.g. agent-broker) to openab, the automatically generated PVC name changes — Helm creates a new PVC and the old one (containing CLI auth tokens and session data) is left behind. There is no built-in way to tell the chart to adopt a pre-existing PVC. Users either lose persistent state or have to manually edit the deployment after install.

The same problem occurs in environments with pre-provisioned storage (storage classes that require administrator allocation, or organizations with specific storage policies).

Closes #120

At a Glance

Before this PR:

  helm install openab ./charts/openab
        │
        ▼
  ┌──────────────────────────────┐
  │ pvc.yaml                     │
  │ always creates:              │
  │   name: {{ fullname }}-kiro  │◄── hardcoded, no escape hatch
  └──────────────┬───────────────┘
                 │
                 ▼
  deployment.yaml → claimName: {{ fullname }}-kiro


After this PR:

  helm install openab ./charts/openab \
    --set agents.kiro.persistence.existingClaim=my-old-pvc
        │
        ▼
  ┌─────────────────────────────────────────┐
  │ pvc.yaml                                │
  │ if existingClaim → skip (no PVC)        │
  │ if empty        → create PVC (default)  │
  └────────────────┬────────────────────────┘
                   │
                   ▼
  deployment.yaml → claimName: my-old-pvc (or generated name)

Prior Art & Industry Research

OpenClaw:

OpenClaw ships no Helm chart. It handles persistence via Docker Compose bind-mounts configured through environment variables — docker-compose.yml mounts ${OPENCLAW_CONFIG_DIR}:/home/node/.openclaw and ${OPENCLAW_WORKSPACE_DIR}:/home/node/.openclaw/workspace. Users control the storage path by setting env vars before running Compose. This approach gives full flexibility but is entirely outside the Kubernetes/PVC model.

Hermes Agent:

Hermes Agent also ships no Helm chart. Its Dockerfile declares VOLUME ["/opt/data"] and the docker/entrypoint.sh handles UID/GID remapping and chown when a volume is mounted at runtime. Storage identity is carried through the volume mount — if you want to migrate data you mount the same volume. Again, no PVC or existingClaim concept.

Other references:

Since neither reference project ships a Helm chart, the canonical prior art for this specific pattern is the Kubernetes Helm ecosystem itself:

  • Bitnami chartspersistence.existingClaim is a first-class value in virtually every stateful chart (PostgreSQL, Redis, WordPress, etc.)
  • Grafana Helm chart — uses identical persistence.existingClaim field and skip-PVC-if-set logic
  • Kubernetes docs on PVC reuse — the underlying mechanism this pattern relies on

The existingClaim name and semantics are a de facto Helm community standard.

Proposed Solution

Add persistence.existingClaim (default: "") to the Helm values. When set:

  1. pvc.yaml skips PVC creation entirely (the resource is not rendered)
  2. deployment.yaml uses existingClaim as the claimName instead of the generated name
# values.yaml
agents:
  kiro:
    persistence:
      existingClaim: ""   # set to adopt a pre-existing PVC

Also adds helm.sh/resource-policy: keep annotation to pvc.yaml as a passive safety net — prevents accidental PVC deletion on helm uninstall or release name changes, using the same pattern already present in secret.yaml.

Files changed

File Change
charts/openab/values.yaml Add persistence.existingClaim: "" to both active kiro block and commented multi-agent example
charts/openab/templates/pvc.yaml Skip PVC creation when existingClaim is set; add helm.sh/resource-policy: keep annotation
charts/openab/templates/deployment.yaml Use existingClaim as claimName when set, fall back to generated name

Why this approach?

existingClaim as the field name: Follows the Bitnami/Grafana de facto standard. Helm users already know this field — choosing a different name (adoptClaim, externalPvc, etc.) would surprise them and make it harder to find in docs.

Skip PVC entirely vs create then ignore: When existingClaim is set, pvc.yaml renders no resource at all. An alternative would be to always render the PVC and just swap the claimName. That alternative is wrong: creating an unused PVC wastes storage quota and could confuse operators who see two PVCs in the namespace.

helm.sh/resource-policy: keep: Without this annotation, helm uninstall deletes the PVC and its data. The annotation makes data loss opt-in (user must delete the PVC manually) rather than opt-out. The pattern was already used in secret.yaml for the same reason.

No API or behavior change: existingClaim defaults to "" (falsy), so existing values files work without modification — the chart behaves identically to before.

Alternatives Considered

  1. persistence.claimName (rename instead of existingClaim) — Confusingly implies the chart-generated PVC also uses this field. existingClaim signals "this PVC already exists outside this chart." Rejected.

  2. Separate persistence.adopt: true boolean + keep persistence.claimName — Two fields for one feature. More config surface, same result. Rejected.

  3. Data migration Job in the chart — A Kubernetes Job that copies data from the old PVC to the new one during upgrade. Much more complex, error-prone, and outside the scope of what a Helm chart should own. Rejected.

Validation

All scenarios verified with helm template and helm lint.

Scenario A — no existingClaim (default, backward compatible)

PVC is created and the deployment references it by its generated name.

helm template myrelease charts/openab \
  --set agents.kiro.discord.botToken=fake \
  --set-string 'agents.kiro.discord.allowedChannels[0]=111111'
Output (pvc + deployment volume section)
# Source: openab/templates/pvc.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: myrelease-openab-kiro
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi
# Source: openab/templates/deployment.yaml
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: myrelease-openab-kiro

Scenario B — existingClaim=my-old-pvc (core feature)

No PVC is created. The deployment references the pre-existing PVC by name.

helm template myrelease charts/openab \
  --set agents.kiro.discord.botToken=fake \
  --set-string 'agents.kiro.discord.allowedChannels[0]=111111' \
  --set agents.kiro.persistence.existingClaim=my-old-pvc
Output (no PVC resource, deployment uses existing claim)
# ← no PersistentVolumeClaim resource rendered
# Source: openab/templates/deployment.yaml
      volumes:
        - name: data
          persistentVolumeClaim:
            claimName: my-old-pvc

Scenario C — persistence.enabled=false

No PVC, no volume mount — unchanged behavior. ✅

Helm lint

helm lint charts/openab/  # ✅ 1 chart(s) linted, 0 chart(s) failed

@white1033 white1033 requested a review from thepagent as a code owner April 9, 2026 15:56
@shaun-agent
Copy link
Copy Markdown
Contributor

Hey @white1033 — nice PR, this is exactly what's needed for the migration path.

One suggestion: could we also add helm.sh/resource-policy: keep to the PVC template? This way even users who don't know to set existingClaim won't silently lose data on upgrade.

metadata:
  name: {{ include "openab.agentFullname" $d }}
  labels:
    {{- include "openab.labels" $d | nindent 4 }}
  annotations:
    "helm.sh/resource-policy": keep

The two fixes are complementary:

  • existingClaim = explicit migration path (user opts in)
  • resource-policy: keep = passive safety net (prevents accidental PVC deletion even when user doesn't know about the rename)

This is the same pattern already used on the Secret template in this chart. Context: #117, and this writeup on the exact data loss scenario.

Happy to open a follow-up PR if you'd prefer to keep this one scoped, but it's a one-line addition so might be easiest to include here.

Prevent accidental PVC deletion on helm uninstall or upgrade.
This complements the existingClaim migration path by acting as
a passive safety net for users who may not be aware of the rename.

Same pattern already used in secret.yaml.
@white1033
Copy link
Copy Markdown
Author

Hey @shaun-agent — great suggestion! I've added the helm.sh/resource-policy: keep annotation to the PVC template in 354f898. The two safeguards are now in place together.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: add persistence.existingClaim support to Helm chart

2 participants