fix(platform): declare the injected _cluster values in system charts - #4102
Conversation
Ten system charts cannot be rendered on their own. They read the
platform-injected _cluster channel, and two of them (bucket,
monitoring) also read _namespace, without declaring either key in
values.yaml. On a cluster the platform supplies both through the
cozystack-values Secret, so installs are unaffected, but rendering a
chart by itself dies before a single template is emitted: on "index of
untyped nil" for a missing _cluster, and on "nil pointer evaluating
interface {}.host" for a missing _namespace.
Declare the keys with empty defaults. Helm merges chart defaults under
the supplied values, so an injected _cluster still wins and rendered
output does not change. Each of the ten also gets a suite that renders
with nothing injected; drop a declaration again and that chart's suite
goes red.
This makes `helm template` succeed for all ten. `helm lint` also
reports a missing cozy-lib dependency on keycloak and monitoring,
which is a separate pre-existing defect and survives this change.
etcd-operator reads _cluster too and stays undeclared here: its single
call site already guards with `| default dict`, so the chart renders
standalone as it is.
Assisted-by: LLM
Signed-off-by: Aleksei Sviridkin <[email protected]>
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Team Run ID: 📒 Files selected for processing (21)
Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review. 📝 WalkthroughWalkthroughThe charts add empty defaults for platform-injected values and new standalone Helm render tests. The tests cover absent ChangesStandalone Helm rendering
Estimated code review effort: 3 (Moderate) | ~25 minutes Merge Risk: ⚪ Minimal · up to System charts can now render without platform-injected cluster or namespace values while retaining their injected-value configuration path. No current merge-blocking risk is identified. 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
IvanHunters
left a comment
There was a problem hiding this comment.
Verdict
LGTM with non-blocking notes
Reviewed at eef5fe690 against merge-base 86d62bbb2.
The mechanism holds up. I could not find a way for this to change what an installed release renders: across five configuration corners times ten charts, base and head produce identical manifests apart from randAlphaNum secrets, and those differ between two renders of the same tree anyway. Both notes below are about the standalone render this PR creates, not about anything that reaches a cluster.
Findings
- [MINOR]
packages/system/monitoring/values.yaml:4, the empty-map default renders%!s(<nil>)where a host belongs - [MINOR]
packages/system/kubevirt/tests/standalone_render_test.yaml:16, the two asserts onvm-exportproxycannot fail if those templates go permanently dead
Claim mismatches
[PARTIAL] "82 charts across packages/{system,apps,extra,core} fail lint the same way". I count 33, and the tier breakdown differs. find packages -maxdepth 4 -path "*/charts/cozy-lib" returns 35 charts, 33 of which never declare the dependency in Chart.yaml, and helm lint puts those at 22 in apps, 8 in extra, 2 in system, 1 in tests, none in core. 85 charts fail helm lint for one reason or another on helm v4.0.4, which is probably where 82 came from. Does not change the decision to defer it: 33 is still not a two-chart item.
Caveats
- I did not replay an upgrade through helm-controller, and a green render does not prove one converges. The argument standing in for it: since no rendered field changes, there is no newly set or newly conditional field for server-side apply to conflict on, no immutable field to diverge, no admission-defaulted field to drift.
- The new
monitoringsuite sets the release namespace tocozy-monitoring, while the chart's existing suites usetenant-root, which is where its HelmRelease actually gets created. No assert in the new suite depends on the namespace, so nothing is wrong today. A content assert added there later would be exercising a namespace the chart does not install into. - Versions: helm v4.0.4, helm-unittest v1.0.3, kubeconform v0.7.0. All local against the clone, no cluster contacted.
Recommended follow-ups
packages/system/kubevirt-cdi/Makefile'supdate:target still opens withrm -rf templates, andtemplates/holdscdi-uploadproxy-ingress.yamlandcdi-uploadproxy-tlsroute.yamlnext to the upstreamcdi-cr.yaml, so a refresh deletes both cozystack-authored templates. The siblingkubevirtMakefile solved this with an idempotent re-apply plus per-marker sanity checks. Addingtest:here at least turns that loss into a red suite instead of a silent one, but the destructiveupdate:deserves its own change.- The body names the structural fix, routing these reads through
cozy-libwhose helpers already guard with| default dict, then declares the keys per chart instead. Reasonable for ten charts. The fifteen remaining ones inapps/andextra/are where the per-chart shape stops paying, and I confirmed that list matches the one the body gives.
| # Injected by the platform from the cozystack-values Secret. The empty | ||
| # defaults keep the chart renderable on its own, outside a cluster. | ||
| _cluster: {} | ||
| _namespace: {} |
There was a problem hiding this comment.
[MINOR] the empty-map default renders %!s(<nil>) where a host belongs
A bare {} makes .Values._namespace.host an untyped nil, and the call sites that build hostnames with printf "%s" write Go's own formatting error into the manifest rather than an empty string. Nine occurrences across three of the ten charts:
$ helm template monitoring packages/system/monitoring --namespace cozy-monitoring | grep -n '%!'
197: - "alerta.%!s(<nil>)"
200: - host: "alerta.%!s(<nil>)"
280: root_url: "https://grafana.%!s(<nil>)"
337: - host: "grafana.%!s(<nil>)"
349: - "grafana.%!s(<nil>)"
$ helm template bucket packages/system/bucket --namespace cozy-bucket | grep -n '%!'
36: value: "s3.%!s(<nil>)"
$ helm template keycloak packages/system/keycloak --namespace cozy-keycloak | grep -n '%!'
133: value: https://keycloak.%!s(<nil>)
181: - keycloak.%!s(<nil>)
184: - host: keycloak.%!s(<nil>)
Inside bucket the two code paths disagree about what unset looks like: the Ingress rule comes out host: cozystack. because {{ $host }} interpolates nil as empty, while the Deployment env comes out s3.%!s(<nil>) because that one goes through printf. Nothing in the PR notices either: the new suites assert document counts only, and kubeconform -strict -ignore-missing-schemas reports every one of these renders valid, since a formatting error is still a legal string. So the follow-up helm template gate the PR proposes would go green on this too.
Seeding the one key each printf path reads fixes it. I ran _cluster: {root-host: ""} and _namespace: {host: ""} on the three charts in isolated checkouts: the artifact count drops to zero, every suite stays green (keycloak 6/6, monitoring 8/8, bucket 3/3), and the render under a realistic injected _cluster/_namespace stays byte-identical to this PR's, because an injected key still wins the merge.
| # same breakage unseen. | ||
|
|
||
| tests: | ||
| - it: exposes no vm-exportproxy route when _cluster is absent |
There was a problem hiding this comment.
[MINOR] the two asserts on vm-exportproxy cannot fail if those templates go permanently dead
kubevirt-cdi got a positive counterpart in this PR and kubevirt did not, and kubevirt is the one chart where nothing else in the tree renders the templates in question (grep -rl vm-exportproxy packages/system/kubevirt/tests/ matches only the new suite). I forced both exposure gates to false so the templates emit nothing under any input, then ran each chart's whole suite:
$ review-helper mutate /tmp/pr-review-cozystack-cozystack-4102 --mutations gatemut.json
GAPS: 1 answered: 2 of 2
kubevirt: vm-exportproxy ingress can never render GAP: the suite stayed green without the fix
| Test Suites: 2 passed, 2 total
kubevirt-cdi: uploadproxy ingress can never render covered: the suite went red
| Test Suites: 1 failed, 0 passed, 1 total
The count: 0 asserts are not entirely inert: I renamed a template out from under one and helm-unittest failed with template "..." not exists or not selected in test suite, so a delete or rename is caught. What they cannot separate is "correctly absent because _cluster is empty" from "never renders again under any input". The fourteen lines that close it are already written next door in kubevirt-cdi/tests/standalone_render_test.yaml.
What this PR does
Ten charts under
packages/systemread_cluster, andbucketandmonitoringalso read_namespace. The platform injects both through thecozystack-valuesSecret, so installs never notice. Rendering a chart on its own does:helm template packages/system/kubevirtdies onindex of untyped nilbefore it emits anything, and the_namespacereaders die onnil pointer evaluating interface {}.host.Each of the ten now declares the keys it reads, with an empty default. Injected values merge over chart defaults, so an installed release renders exactly what it rendered before. Checked per chart against a realistic injected
_cluster/_namespace: six came out byte-identical, and the other four differ only inrandAlphaNumsecrets, which also differ between two renders of the same tree.The declaration on its own is not worth much, so every chart also gets a suite that renders with nothing injected. The existing suites all set
_clusterthemselves and cannot see whethervalues.yamlstill declares it. Drop a declaration and exactly that chart's suite goes red, with the error its comment quotes; I ran that for all twelve. None of the new suites carries a suite-leveltemplates:list, on purpose: that list narrows what helm-unittest renders, and would hide the same breakage in a template added later.kubevirt-cdihad notests/and notest:target, so it gets both.etcd-operatorreads_clustertoo and stays as it is, since its one call site already guards with| default dict.cozystack-basicsalready declared the key.Closes #4030.
Not in this PR
No CI job runs
helm lintor a standalonehelm template, which is why none of this was red. A gate is worth proposing separately. Its value is narrow though:_clusteris always populated on a real install, and eight of these ten already had a suite rendering the affected template with_clustersupplied. The two with nothing werekubevirt, whosevm-exportproxy-*templates no test touched, andkubevirt-cdi, which had no tests at all.helm lintstill exits 1 onkeycloakandmonitoringwithchart metadata is missing these dependencies: cozy-lib. Both carry acharts/cozy-libsymlink thatChart.yamlnever declares. That one is not a two-chart item: 82 charts acrosspackages/{system,apps,extra,core}fail lint the same way, which is invisible because no job runshelm lint. Separate defect, untouched here.Fifteen charts outside
packages/systembreak the same way:apps/{bucket,foundationdb,harbor,kubernetes,mongodb,nats,opensearch,postgres,vpn}andextra/{bootbox,etcd,gateway,info,ingress,seaweedfs}.cozy-lib's own helpers already guard every access with| default dict, so routing those reads through the library would close the class instead of patching fifteen more values files.kubevirt's suite only pins that the routes stay absent with nothing injected. Nothing pins that they show up once_clusterselects the service.Screenshots
No UI change: the diff is ten
values.yamlfiles, ten helm-unittest suites, and one packageMakefile.Downstream repositories
Walked the trigger map in
docs/agents/contributing.mdfile by file against this diff. No package is added, renamed or removed underpackages/appsorpackages/extra;packages/core/platform/values.yamlis untouched; no variant, bundle, component, release asset, namespace orApplicationDefinitionsemantic changes; novalues.schema.jsonand no version enum moves, so the provider's hand-written schemas and defaults are unaffected; nothing underhack/moves and no existing make target changes behaviour. The oneMakefileedit adds atest:target topackages/system/kubevirt-cdi, matching the target the other nine already have, somake generateand the ccp skills that drive it see nothing new.Release note
Summary by CodeRabbit
Bug Fixes
Tests