Repository navigation
fix(kubernetes): keep tenant addon CRDs when a release is uninstalled - #3586
Aleksei Sviridkin (lexfrei) merged 4 commits into
Conversation
📝 WalkthroughWalkthroughFour Helm CRD charts now add ChangesCRD retention
Estimated code review effort: 3 (Moderate) | ~25 minutes Possibly related issues
Suggested labels: Suggested reviewers: 🚥 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 |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/system/vertical-pod-autoscaler-crds/Makefile`:
- Around line 12-19: Update the awk transformation in the Makefile’s update
target to guarantee that each CustomResourceDefinition receives the
helm.sh/resource-policy annotation even when metadata.annotations is absent.
Create the annotations block before adding the policy, or fail before replacing
the generated file if it cannot be inserted; do not allow update to finish with
an unannotated CRD.
- Line 16: Update the curl invocation in the Makefile download target to include
the --fail option, ensuring HTTP 4xx and 5xx responses stop the command before
the generated template is modified by the subsequent awk step.
🪄 Autofix
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 3d02055f-18c6-495e-90e3-c128aad23a94
📒 Files selected for processing (14)
packages/system/gateway-api-crds/Makefilepackages/system/gateway-api-crds/templates/crds-experimental.yamlpackages/system/gateway-api-crds/tests/resource_policy_test.yamlpackages/system/prometheus-operator-crds/Makefilepackages/system/prometheus-operator-crds/tests/resource_policy_test.yamlpackages/system/prometheus-operator-crds/values.yamlpackages/system/vertical-pod-autoscaler-crds/Makefilepackages/system/vertical-pod-autoscaler-crds/templates/vpa-v1-crd-gen.yamlpackages/system/vertical-pod-autoscaler-crds/tests/resource_policy_test.yamlpackages/system/vsnap-crd/Makefilepackages/system/vsnap-crd/templates/volumesnapshotclasses.yamlpackages/system/vsnap-crd/templates/volumesnapshotcontents.yamlpackages/system/vsnap-crd/templates/volumesnapshots.yamlpackages/system/vsnap-crd/tests/resource_policy_test.yaml
| # The stamp goes into the CRD's existing metadata.annotations block; a CRD that | ||
| # arrives without one is skipped, and the chart's helm-unittest suite is what | ||
| # catches that. | ||
| update: | ||
| curl -o ./templates/vpa-v1-crd-gen.yaml https://raw.githubusercontent.com/kubernetes/autoscaler/refs/heads/master/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml | ||
| @set -e; f=./templates/vpa-v1-crd-gen.yaml; tmp=$$(mktemp); \ | ||
| awk '/^ helm.sh\/resource-policy: keep$$/{next} /^kind: /{kind=$$2} /^ annotations:$$/ && kind=="CustomResourceDefinition"{print; print " helm.sh/resource-policy: keep"; next} {print}' "$$f" > "$$tmp"; \ | ||
| cat "$$tmp" > "$$f"; rm -f "$$tmp" |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Handle CRDs that have no metadata.annotations block.
The awk rule adds the policy only when it finds ^ annotations:$. If upstream removes that block, make update completes with an unannotated CRD. Create the annotations block when absent, or fail the update before replacing the generated file. The separate test target does not run from update.
🧰 Tools
🪛 checkmake (0.3.2)
[warning] 15-15: Required target "all" is missing from the Makefile.
(minphony)
[warning] 15-15: Required target "clean" is missing from the Makefile.
(minphony)
[warning] 15-15: Required target "test" must be declared PHONY.
(minphony)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/system/vertical-pod-autoscaler-crds/Makefile` around lines 12 - 19,
Update the awk transformation in the Makefile’s update target to guarantee that
each CustomResourceDefinition receives the helm.sh/resource-policy annotation
even when metadata.annotations is absent. Create the annotations block before
adding the policy, or fail before replacing the generated file if it cannot be
inserted; do not allow update to finish with an unannotated CRD.
| # arrives without one is skipped, and the chart's helm-unittest suite is what | ||
| # catches that. | ||
| update: | ||
| curl -o ./templates/vpa-v1-crd-gen.yaml https://raw.githubusercontent.com/kubernetes/autoscaler/refs/heads/master/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Fail on an HTTP error before changing the generated template.
curl accepts HTTP 4xx and 5xx responses without --fail. The following awk command can then replace vpa-v1-crd-gen.yaml with an error page. Add --fail to prevent a failed download from corrupting the tracked template.
Proposed fix
- curl -o ./templates/vpa-v1-crd-gen.yaml https://raw.githubusercontent.com/kubernetes/autoscaler/refs/heads/master/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml
+ curl --fail -o ./templates/vpa-v1-crd-gen.yaml https://raw.githubusercontent.com/kubernetes/autoscaler/refs/heads/master/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| curl -o ./templates/vpa-v1-crd-gen.yaml https://raw.githubusercontent.com/kubernetes/autoscaler/refs/heads/master/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml | |
| curl --fail -o ./templates/vpa-v1-crd-gen.yaml https://raw.githubusercontent.com/kubernetes/autoscaler/refs/heads/master/vertical-pod-autoscaler/deploy/vpa-v1-crd-gen.yaml |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/system/vertical-pod-autoscaler-crds/Makefile` at line 16, Update the
curl invocation in the Makefile download target to include the --fail option,
ensuring HTTP 4xx and 5xx responses stop the command before the generated
template is modified by the subsequent awk step.
|
Reopening to pick up the multus fix on main. |
Andrei Kvapil (kvaps)
left a comment
There was a problem hiding this comment.
Verified the mechanics end to end and they hold. Rendering all four charts, every
CRD carries helm.sh/resource-policy: keep (12 / 2 / 10 / 3) and nothing else
does — the Gateway API ValidatingAdmissionPolicy pair is correctly left out. I
re-ran the stamping awk over the five committed files and it is a no-op, and I ran
the real update: fetch for gateway-api-crds (kubectl kustomize ... ?ref=v1.5.1)
and vsnap-crd: both come back byte-identical to what is committed here.
The tests are not self-asserting. Dropping the annotation from one vsnap CRD turns
two cases red; appending an unannotated CRD to the Gateway API file turns the
wildcard case and the document-count pin red. hack/helm-unit-tests.sh is green
across the whole repo.
On the trade-off: reinstall after a keep-uninstall is safe. Helm excludes kept
resources from the delete set without touching their metadata, so
meta.helm.sh/release-name and -namespace survive; release name and
storageNamespace are fixed in these HelmReleases, so the retry install passes the
ownership check and adopts the CRDs rather than failing on "exists and cannot be
imported". Existing clusters need no migration either — the platform upgrade runs
helm upgrade on these releases and patches the annotation onto the CRDs already in
place. Coverage looks complete for the stated scope: every tenant addon that renders
CRDs from templates/ is now annotated, and the ones that ship CRDs under crds/
(velero, gpu-operator) were never at risk since Helm does not delete those.
Two things worth resolving, both about consistency inside this block of PRs rather
than correctness here.
The stamping step is copy-pasted three times, and #3595 is hardening the fourth
copy in the opposite direction. The same awk one-liner appears verbatim in
gateway-api-crds/Makefile:22, vertical-pod-autoscaler-crds/Makefile:18 and
vsnap-crd/Makefile:23, alongside a fourth, differently-shaped and non-idempotent
variant already in etcd-operator-crds/Makefile:20. #3595 gives that fourth one a
count guard — one annotation per CRD or the update fails — and defers writing
templates/ until after the check. The three added here have neither. A CRD that
arrives without a metadata.annotations block, or with annotations: {} in flow
style, is skipped silently, the step exits 0, and since rm -rf templates has
already run there is nothing to fall back to. The suite in this PR does catch it in
CI, which the description says, but #3595 has decided the guard belongs at the point
of failure. A shared hack/stamp-crd-keep.sh — the kind-aware idempotent matcher
from this PR plus the count guard from #3595 — would leave one implementation
instead of four.
The suites are much heavier than the equivalent in #3590. 387 of the 456 added
lines are tests, and most of that is repetition:
gateway-api-crds/tests/resource_policy_test.yaml:35-141 is twelve near-identical
cases that each re-check what the matchMany case at :18 already covers, and
prometheus-operator-crds/tests/resource_policy_test.yaml:24-142 is ten more. #3590
gets the same guarantee for cert-manager-crds in a single wildcard case. Worth
converging on one shape across the block.
Smaller points:
- The description says a CRD from a later upstream bump is "covered without editing
the test", buthasDocuments: count: 14at :32 (andcount: 2in the VPA suite)
is exactly what will need editing on such a bump. Both properties are worth having;
the sentence just reads as if the pin were not there. - Three of the four suites scope to no template and assert
kind == CustomResourceDefinitionon every document. That is stricter than
intended: a non-CRD resource appearing upstream would fail them for the wrong
reason. The Gateway API suite gets this right withdocumentSelector+matchMany.
Conversely it is the only one with a suite-leveltemplates:(:15), so a second
file undertemplates/would go untested — moot today, sinceupdate:writes
exactly one. renders twelve CRDs and the admission policy pair(:30) bakes the count into the
case name as well as the assertion; the name will go stale first.vsnap-crd/Makefile:22createstmpoutside the loop, so a mid-loop awk failure
leaves it behind.
Out of scope, but the same class exists on the management cluster: kamaji-crds
(tenantcontrolplanes), piraeus-operator-crds, kubevirt-operator,
kubevirt-cdi-operator, metallb, objectstorage-controller,
mariadb-operator-crds, kubeovn and external-secrets all render CRDs from
templates/ without the annotation. Not urgent — those HelmReleases set no
install.remediation, and the default there is to perform no action — but the same
protection would cost the same.
CI is red on "Unit & controller tests" for an unrelated reason: the EXIT-trap freeze
guard in hack/cozyreport.bats:2553 does not list
hack/run-kubernetes-talos-diagnostics_test.bats, which landed on main with #3548.
This PR touches no .bats file.
Approving — none of the above blocks the fix.
The tenant addon HelmRelease remediates a failed install by uninstalling the release, and an uninstall deletes whatever the chart rendered. Deleting a CRD makes the API server garbage-collect every custom resource of that kind, so a failed reinstall takes every Gateway, HTTPRoute and ReferenceGrant in the tenant cluster with it. Stamp helm.sh/resource-policy: keep on each CustomResourceDefinition and teach `make update` to reapply it, since that target rebuilds templates/ from upstream and would otherwise drop the annotation silently. The ValidatingAdmissionPolicy pair the experimental kustomization also emits holds no user data and stays unannotated. Removing the release on purpose now leaves the definitions behind to be deleted by hand. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The tenant addon HelmRelease remediates a failed install by uninstalling the release, and an uninstall deletes whatever the chart rendered. Deleting a CRD makes the API server garbage-collect every custom resource of that kind, so a failed reinstall takes every VerticalPodAutoscaler in the tenant cluster with it, along with the recommendation history held in the checkpoints. Stamp helm.sh/resource-policy: keep on each CustomResourceDefinition and teach `make update` to reapply it, since that target refetches the manifest from upstream and would otherwise drop the annotation silently. Removing the release on purpose now leaves the definitions behind to be deleted by hand. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The tenant addon HelmRelease remediates a failed install by uninstalling the release, and an uninstall deletes whatever the chart rendered. Deleting a CRD makes the API server garbage-collect every custom resource of that kind, so a failed reinstall takes every VolumeSnapshot and VolumeSnapshotContent in the tenant cluster with it — the objects that carry the only reference to a snapshot on the storage backend. Stamp helm.sh/resource-policy: keep on each CustomResourceDefinition and teach `make update` to reapply it, since that target rebuilds templates/ from upstream and would otherwise drop the annotation silently. Removing the release on purpose now leaves the definitions behind to be deleted by hand. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
The tenant addon HelmRelease remediates a failed install by uninstalling the release, and an uninstall deletes whatever the chart rendered. Deleting a CRD makes the API server garbage-collect every custom resource of that kind, so a failed reinstall takes every ServiceMonitor, PodMonitor, PrometheusRule and ScrapeConfig in the tenant cluster with it. The CRDs ship inside a vendored subchart that `make update` re-pulls, so the annotation is set through the chart values the subchart already renders rather than by editing templates that would be overwritten. Removing the release on purpose now leaves the definitions behind to be deleted by hand. Assisted-By: Claude <[email protected]> Signed-off-by: Aleksei Sviridkin <[email protected]>
5f646c8 to
d90a6a5
Compare
## What this PR does `make update` in `packages/system/etcd-operator-crds` vendors three CRDs and stamps `helm.sh/resource-policy: keep` onto each with an awk step anchored on the `controller-gen.kubebuilder.io/version:` line. That line is upstream's to emit. If a future controller-gen stops writing it, the awk matches nothing, writes the CRD out unstamped and exits zero, so the regeneration reports success and the CRDs land without the annotation that keeps a chart uninstall from deleting them, and with them every EtcdCluster, EtcdMember and EtcdSnapshot in the cluster. The step now counts what it produced and requires exactly one annotation per CRD. Zero means the anchor is gone; more than one means it matched somewhere unintended. Every CRD is staged in a temporary directory and `templates/` is replaced only after all of them have been counted, so a failure on any one leaves the vendored files exactly as they were rather than wiping the directory and refilling part of the set. I checked it by substituting the upstream response, so what ran was the recipe that ships rather than a copy of its logic: a CRD with no controller-gen line fails with `stamped 0 keep annotations, expected 1`, a CRD carrying that line twice fails with 2, a failure on the second of the three leaves all three committed files untouched, and the real upstream still vendors byte-identical output, with `make update` leaving `git status` showing nothing but this Makefile. On `main` today this is the only thing guarding those three CRDs. A helm-unittest suite that fails when one of them renders without the annotation is in #3590, which is open and not merged. Once that lands the two catch the same loss at different moments: the suite on a test run, this step in front of whoever ran the regeneration. The same stamping shape exists in three more packages, but only on the branch of #3586, which adds it to `gateway-api-crds`, `vsnap-crd` and `vertical-pod-autoscaler-crds`. There is nothing to guard there on `main` yet, so they are deliberately out of this change and need the same step once #3586 merges. ### Screenshots Not a UI change. ### Downstream repositories - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: I walked the trigger map in `docs/agents/contributing.md` against the file list of this diff, which is one package Makefile and nothing else. `hack/package.mk` is untouched, so the `ccp` and `external-apps-example` triggers that key on it do not fire, and the website's "developer tooling (the package Makefiles)" line is the only near miss: `content/en/docs/next/development.md` describes `make update` in general terms and does not go stale from a package validating its own output. ### Release note ```release-note NONE ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **Bug Fixes** * Improved CRD update validation to ensure generated definitions include the required preservation annotation. * Prevented incomplete or invalid updates from replacing existing CRD templates. * Added automatic cleanup of temporary update files. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
|
Successfully created backport PR for |
…trics operator is gone first (#5152) <!-- Thank you for making a contribution! Here are some tips for you: - Use Conventional Commits for the PR title: `type(scope): description` - Add the label `kind/backport` if it's a bugfix that needs to be backported to a previous version. --> ## What this PR does Disabling the Monitoring Agents addon of a tenant Kubernetes cluster leaves `<cluster>-monitoring-agents` (release `cozy-monitoring-agents`, installed into the tenant cluster) in `UninstallFailed` for good. Seen in production on 1.6.5 and still reproducible from `main`. `monitoring-agents`, `victoria-metrics-operator` and `vertical-pod-autoscaler-crds` in `packages/apps/kubernetes/templates/helmreleases/` are all gated on `addons.monitoringAgents.enabled`, so they disappear together and Flux uninstalls them in parallel: `dependsOn` is not honoured on deletion. Two things then break the uninstall of `monitoring-agents`: 1. The VictoriaMetrics operator is often gone first. The operator's `apps.victoriametrics.com/finalizer` stays on the `VMAgent`, nobody removes it, and the deletion hangs. The manual workaround was to strip the finalizer, after which GC removes the VMAgent's Deployment, Service, Secrets and ServiceAccount through their owner references. 2. The VPA CRD was deleted with its own release while the stored manifest still contains `VerticalPodAutoscaler vpa-vmagent`, so Helm cannot build the manifest to uninstall. That root cause is fixed by #3586 (`helm.sh/resource-policy: keep` on the tenant addon CRDs), which this PR does not redo. This PR: - adds a `pre-delete` hook (`templates/vm-cleanup-hook.yaml`) that deletes every VictoriaMetrics object the release owns, waits up to 60s for a live operator to finalize them properly, and clears their finalizers by hand when it has not. Objects are selected through Helm's `meta.helm.sh/release-name` / `release-namespace` annotations rather than by name, so the 34 `VMRule`s rendered from `alerts/` and the `VMServiceScrape` in `cozy-victoria-metrics-operator` are covered along with the VMAgent. The kinds handled are every VictoriaMetrics kind the chart renders: `VMAgent`, `VMRule`, `VMServiceScrape`, `VMPodScrape`, `VMNodeScrape`. Operator v0.68.4 only finalizes the VMAgent; the other kinds are covered in case another operator version finalizes them, and for them the patch is a no-op. A kind whose CRD is already gone is skipped, and the script always exits 0, since a failing pre-delete hook would itself block the uninstall. The Job is bounded by `activeDeadlineSeconds: 180` and `backoffLimit: 0`; its kubectl calls carry no `--request-timeout`, which would make kubectl skip the in-cluster credentials (`hack/check-hook-request-timeout.bats`) and reuses the digest-pinned `docker.io/clastix/kubectl:v1.32` image the etcd-operator hook uses, via a new `kubectlImage` value. The shape follows `packages/system/forklift/templates/forklift-cr-cleanup-hook.yaml`. - guards `templates/vpa.yaml` on `.Capabilities.APIVersions.Has "autoscaling.k8s.io/v1/VerticalPodAutoscaler"`, so a cluster that does not serve the CRD never records a VPA in the release manifest. Cheap defence in depth next to #3586. Points for review: - The hook's RBAC is a ClusterRole/ClusterRoleBinding, limited to `get, list, delete, patch` on the five `operator.victoriametrics.com` resources, rather than Roles. The objects span two namespaces, and a Role in `cozy-victoria-metrics-operator` could not be created if that namespace were already gone or terminating, which would fail the hook and the uninstall with it. All hook objects carry `hook-succeeded,hook-failed,before-hook-creation` except the Job, which keeps a failed pod for its logs (`ttlSecondsAfterFinished: 600`), as in the forklift hook. - When the operator is already gone, clearing the finalizer skips whatever the operator does on finalize, notably the cluster-scoped RBAC it creates for the VMAgent, which has no owner reference. That residue is the same the manual workaround left, and it is no worse than today's stuck release; removing it would mean hard-coding the operator's naming scheme for those objects, which I preferred not to do. - When the operator is alive, the hook only brings forward deletions Helm was about to make, so the operator's normal finalization still runs. Tests: `tests/uninstall_test.yaml` asserts that the hook is a `pre-delete` Job in the release namespace with a bounded runtime, that its RBAC is hook-scoped and grants exactly the verbs needed on every VictoriaMetrics kind the chart renders, that the binding targets the hook's ServiceAccount, that the script selects by release ownership, deletes, clears finalizers and exits 0, and that the VPA renders only when the capability is present (using `capabilities.apiVersions`). With the hook removed and `vpa.yaml` reverted, 6 of the 7 tests fail; with the fix, `helm unittest packages/system/monitoring-agents` passes 26/26. `hack/monitoring-agents-vm-cleanup-hook.bats` runs the rendered script against a fake `kubectl` that keeps the objects in a state file, with fake `date` and `sleep`. It checks that only objects annotated for this release are deleted and patched, that with the operator gone the hook polls through the grace period and then clears the finalizers, that a live operator's objects are never patched, that a missing CRD still exits 0 and cleans the other kinds, and that a release with nothing left exits 0 without deleting anything. Removing the ownership condition, making the patch a no-op, or inverting the polling condition each turns this file red. The hook has not yet been run on a live tenant cluster. Backport: labelled `kind/backport` (release-1.7). The release-1.6 backport is done by hand in #5158. The commit cherry-picks onto `release-1.6` with a single trivial conflict in `values.yaml` (context only: 1.6 lacks the `prometheus-node-exporter` resources block the new `kubectlImage` block sits after on `main`). Resolved locally, the chart's tests pass on 1.6 (9/9); 1.6's chart renders the same VictoriaMetrics kinds. Note that `release-1.6`'s monitoring-agents `Makefile` has no `test:` target, so CI does not run this chart's unit tests on that branch. ### Screenshots Not a UI change. ### Downstream repositories I walked the trigger map against the diff (a system chart's templates, `values.yaml` and tests): no package added or renamed, no platform values, no app schema, no CRD, no tooling or convention change. I also searched cozystack/website for a documented VMAgent finalizer workaround that this would make obsolete and found none. - [x] No downstream repository is affected by this change - [ ] [cozystack/website](https://github.com/cozystack/website) - follow-up: - [ ] [cozystack/terraform-provider-cozystack](https://github.com/cozystack/terraform-provider-cozystack) - follow-up: - [ ] [cozystack/ansible-cozystack](https://github.com/cozystack/ansible-cozystack) - follow-up: - [ ] [cozystack/ccp](https://github.com/cozystack/ccp) - follow-up: - [ ] [cozystack/talm](https://github.com/cozystack/talm) - follow-up: - [ ] [cozystack/cozyhr](https://github.com/cozystack/cozyhr) - follow-up: - [ ] [cozystack/cozy-proxy](https://github.com/cozystack/cozy-proxy) - follow-up: - [ ] [cozystack/cozystack-telemetry-server](https://github.com/cozystack/cozystack-telemetry-server) - follow-up: - [ ] [cozystack/external-apps-example](https://github.com/cozystack/external-apps-example) - follow-up: - [ ] [cozystack/examples](https://github.com/cozystack/examples) - follow-up: - [ ] [cozystack/community](https://github.com/cozystack/community) - follow-up: ### Release note ```release-note fix(monitoring-agents): disabling the Monitoring Agents addon of a tenant Kubernetes cluster no longer leaves the monitoring-agents release stuck in UninstallFailed when the VictoriaMetrics operator is removed first; a pre-delete hook now releases the VictoriaMetrics objects' finalizers, and the VPA is only rendered when its CRD is served. ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> <!-- coderabbit-ai-generated:v1 --> ## Summary by CodeRabbit * **Bug Fixes** * VictoriaMetrics resources belonging to a release are cleaned up during uninstall, including resources that remain because of finalizers. Cleanup is limited to resources owned by that release. * Vertical Pod Autoscaler resources are rendered only when the cluster supports the required API. * **Configuration** * Added an image setting for the uninstall cleanup job, including a pinned image version and pull policy. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
What this PR does
Four tenant addon HelmReleases render their CRDs from a chart's
templates/directory and remediate a failed install by uninstalling the release. An uninstall deletes what the chart rendered, and deleting a CRD makes the API server garbage-collect every custom resource of that kind, so a failed reinstall takes every Gateway, VerticalPodAutoscaler, ServiceMonitor or VolumeSnapshot in the tenant cluster with it. This annotates the CRDs of the four packages behind them,gateway-api-crds,vertical-pod-autoscaler-crds,prometheus-operator-crdsandvsnap-crd(that last one is declared byhelmreleases/volumesnapshot-crd.yaml), withhelm.sh/resource-policy: keep, which is whatcert-manager-crdsandetcd-operator-crdsalready carry in this tree.Three of the four regenerate
templates/from upstream onmake update: two delete the directory outright and the third overwrites its file. So the annotation is written into the vendored files and reapplied by a step in eachupdate:target. Without that second half the next regeneration drops it silently, with nothing reporting the loss. I ranmake updatefor real to check the pair holds:gateway-api-crdsandvsnap-crdcome back byte-identical to what is committed here, andvertical-pod-autoscaler-crdsreproduces the annotation on both of its CRDs. The rest of the VPA diff is upstream drift, because that package'supdate:tracks a branch rather than a pinned ref; the bump itself is not in this PR. The step is idempotent, so running it twice does not stack a second annotation into the same mapping.prometheus-operator-crdsships its CRDs in a vendored subchart thatmake updatere-pulls, so nothing undercharts/is edited. The upstream template already renders.Values.annotationsonto every CRD it emits, and the annotation is set through the package'svalues.yaml.The Gateway API kustomization also emits a
ValidatingAdmissionPolicyand its binding. Those hold no user data, so the stamping step selects onkind: CustomResourceDefinitionand leaves them alone.Each package gains a helm-unittest suite and the
test:target thathack/helm-unit-tests.shrequires before it will run a suite at all. Every suite asserts the annotation across all CRDs its chart renders, not only the ones listed by name, so a CRD arriving in a later upstream bump is covered without editing the test.The annotation has a cost worth stating plainly: uninstalling one of these releases on purpose now leaves the CRDs behind, to be removed by hand. That is the same trade-off
cert-manager-crdsalready carries.This covers the first of the two directions in #3555. The second one, setting
install.strategy.name: RetryOnFailureon these releases, is a separate decision with a different blast radius and is not part of this PR.Screenshots
Not a UI change.
Downstream repositories
I walked the trigger map in
docs/agents/contributing.mdagainst the file list of this diff. It touches four packages underpackages/system/and nothing else: nohack/package.mk, no appvalues.schema.json, no platform values, noApplicationDefinition, no release asset names. The one line that looked close is the website's "developer tooling (the package Makefiles)" trigger, so I readcontent/en/docs/next/development.mdin the website repo: it documentsmake updateandmake testin general terms, and neither goes stale from this change.Release note
Summary by CodeRabbit