diff --git a/hips/hip-0027.md b/hips/hip-0027.md new file mode 100644 index 00000000..8a7cf800 --- /dev/null +++ b/hips/hip-0027.md @@ -0,0 +1,171 @@ +--- +hip: 0027 +title: "Expose Previously Installed Chart Metadata During Template Rendering" +authors: [ "Andrew Shoell " ] +created: "2025-11-12" +type: "feature" +status: "draft" +--- + +## Abstract + +This HIP proposes exposing metadata from the currently deployed chart version during template rendering. Currently, Helm templates have access to `.Chart` for the chart being installed but no equivalent access to the currently deployed release. This forces chart authors to use complex workarounds like post-renderers, pre-upgrade hooks, or manual values conventions to implement version-aware upgrade logic. + +The proposal introduces a new `.DeployedChart` object available in all template contexts, populated with the deployed chart's metadata during `helm upgrade` and `helm rollback` operations. When no deployed release exists, `.DeployedChart` is nil, allowing safe checks with `{{ if .DeployedChart }}`. An optional `--disable-deployed-chart` flag provides opt-out capability. + +## Motivation + +### Current Limitations + +Helm provides comprehensive chart metadata through `.Chart` but offers no native way to access deployed release metadata during template evaluation. Chart developers must resort to problematic workarounds: + +**Post-Renderers:** External tools that query the cluster, parse manifests, and make version-aware modifications. This moves upgrade logic outside the chart, requires additional tooling, and breaks Helm's self-contained design. + +**Pre-Upgrade Hooks:** Store version metadata in ConfigMaps via hooks, creating ordering dependencies and potential failure points. + +**Manual Values:** Require users to specify previous versions in values files—error-prone and defeats Helm's release tracking. + +### Real-World Impact + +This limitation prevents or complicates legitimate use cases: + +- **Breaking Changes:** No clean migration path for renamed resources or changed structures +- **Conditional Resources:** Cannot create migration Jobs based on version deltas +- **Smart Defaults:** Cannot distinguish fresh installs from upgrades for intelligent defaults +- **Advanced Deployments:** Blue-green and similar strategies require external orchestration + +Post-rendering solutions violate Helm's design philosophy that template rendering should be deterministic and self-contained. Making deployed chart metadata available at template time keeps upgrade logic in the chart itself, maintaining Helm's portability, testability, and transparency. + +## Rationale + +### Naming: `.DeployedChart` + +Alternatives considered and rejected: +- `.PreviousChart` - Ambiguous during rollbacks +- `.InstalledChart` - Confusing with current installation +- `.CurrentChart` - Ambiguous which is "current" +- `.Release.Deployed.Chart` - Unnecessarily nested + +`.DeployedChart` unambiguously means "what is currently running in the cluster" and maintains consistency with Helm terminology. + +### Always Available as Template Object + +`.DeployedChart` is always present (though possibly nil) to ensure consistent template behavior, prevent undefined variable errors, and enable testing with `helm template`. + +### Populated Only During Upgrades/Rollbacks + +`.DeployedChart` contains chart metadata only during `helm upgrade` and `helm rollback` when a deployed release exists. It's nil for: +- `helm install` - No deployed release +- `helm template` / dry-runs - No cluster context +- When `--disable-deployed-chart` is used + +### Chart Metadata Only + +This proposal exposes only Chart.yaml metadata (same structure as `.Chart`), not values, manifests, or release metadata. This maintains security (values may contain secrets), performance (manifests can be large), and simplicity while solving 90% of use cases. Future HIPs could extend this if needed. + +### Opt-Out Flag + +The `--disable-deployed-chart` flag allows organizations to disable the feature for security or determinism requirements. A CLI flag was chosen over environment variables for explicitness and consistency with Helm's patterns. + +### Design Decisions + +- **Different Chart Names:** Still populates `.DeployedChart` even if chart names differ—templates can detect and handle this +- **Helm's Record:** Reflects Helm's stored release record, not actual cluster state (use `lookup()` for that) +- **Dry-Run/Template:** Always nil to maintain cluster-agnostic, deterministic behavior + +## Specification + +### New Template Object: `.DeployedChart` + +A top-level template object available in all contexts. Populated with deployed chart metadata during upgrade/rollback; nil otherwise. + +**Metadata Structure:** Identical to `.Chart`, including `Name`, `Version`, `AppVersion`, and other [Chart.yaml fields](https://helm.sh/docs/topics/charts/#the-chartyaml-file). + +**Usage Example:** +```yaml +{{- if .DeployedChart }} +{{- if and (semverCompare ">=2.0.0" .Chart.Version) (semverCompare "<2.0.0" .DeployedChart.Version) }} +# Migration logic for 1.x -> 2.x upgrade +apiVersion: batch/v1 +kind: Job +metadata: + name: {{ include "mychart.fullname" . }}-migration + annotations: + "helm.sh/hook": pre-upgrade +spec: + template: + spec: + containers: + - name: migrate + image: myapp/migrator:{{ .Chart.AppVersion }} + command: ["migrate", "v1-to-v2"] +{{- end }} +{{- end }} +``` + +### Command-Line Flag + +```bash +helm upgrade myrelease mychart --disable-deployed-chart +``` + +### Behavior Matrix + +| Operation | `.DeployedChart` Value | +|-----------|------------------------| +| `helm install` | `nil` (no deployed release) | +| `helm upgrade` (new) | `nil` (no deployed release) | +| `helm upgrade` (existing) | Populated with deployed metadata | +| `helm rollback` | Populated with deployed metadata | +| `helm template` / dry-runs | `nil` (no cluster context) | +| With `--disable-deployed-chart` | `nil` (explicitly disabled) | + +## Backwards Compatibility + +Fully backwards compatible. The `.DeployedChart` object is purely additive—existing charts work unchanged. Go templates handle nil safely; the recommended `{{ if .DeployedChart }}` pattern works in all scenarios. + +## Security Implications + +**Not Exposed:** Previous values (may contain secrets) or previous manifest (may contain sensitive data). Only Chart.yaml metadata is exposed. + +**Considerations:** Chart authors should not store sensitive data in Chart.yaml. The `--disable-deployed-chart` flag provides opt-out for security-sensitive environments. + +## How to Teach This + +### Documentation Additions + +1. **Template Objects Reference:** Add `.DeployedChart` to built-in objects with availability details +2. **Upgrade Guide:** "Implementing Version-Aware Upgrades" covering nil checks, version comparisons, and best practices +3. **Migration Examples:** Show replacement of post-renderers and pre-upgrade hooks with `.DeployedChart` +4. **Chart Linting:** Update `helm lint` to warn on `.DeployedChart` usage without nil checks + +### Key Example Pattern + +```yaml +{{- if and .DeployedChart (semverCompare "<3.0.0" .DeployedChart.Version) }} +# Handle breaking change from versions < 3.0.0 +{{- end }} +``` + +## Reference Implementation + +A future pull request will: +1. Extend template rendering context to include `.DeployedChart` +2. Populate from release records during upgrade/rollback +3. Add `--disable-deployed-chart` flag +4. Include comprehensive unit and integration tests + +## Rejected Ideas + +- **Full Release Object:** Security/performance concerns; chart metadata sufficient +- **Only Version Strings:** Inconsistent with `.Chart`; prevents access to other metadata +- **Environment Variable Control:** Less explicit than CLI flag +- **Cluster Query During `helm template`:** Violates cluster-agnostic design principle +- **Mutable `.DeployedChart`:** Violates read-only template model; no clear use case + +## References + +- [Helm Built-in Objects](https://helm.sh/docs/chart_template_guide/builtin_objects/) +- [Helm Chart.yaml](https://helm.sh/docs/topics/charts/#the-chartyaml-file) +- [Go Templates](https://pkg.go.dev/text/template) +- [Semantic Versioning](https://semver.org/)