Repository navigation
[Backport release-1.6] fix(api): let the garbage collector finalize Applications - #4683
Merged
myasnikovdaniil merged 1 commit intoOct 14, 2026
Conversation
Contributor
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
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 |
europrinter (yankawai)
marked this pull request as ready for review
October 2, 2026 10:32
europrinter (yankawai)
force-pushed
the
fix/application-garbage-collection-1.6
branch
from
October 4, 2026 09:05
1ff0580 to
55b5767
Compare
An Application and its HelmRelease share one UID, so the garbage collector keeps a single graph node for both and may finalize it through the Application endpoint. The API never returned finalizers on an Application, and every update restored the HelmRelease finalizers from the live object. When the collector came to drop foregroundDeletion or orphan through the Application, removeFinalizer found no such finalizer and returned as if it were already gone. The HelmRelease then kept foregroundDeletion after Helm had uninstalled the release, and the deletion never completed. The Application now carries the two garbage collection finalizers, and an update that adds or removes one of them applies the same change to the HelmRelease. Controller finalizers such as finalizers.fluxcd.io stay owned by the live object, so helm uninstall still runs before the release goes away. The deletion timestamp and grace period are copied from the live object, which keeps an update of a terminating release valid. Backport of 46b5a54 to release-1.6. Update on this branch has no applyLiveMetadata, so the finalizer merge and the deletion metadata copy are done inline, in Update and in its conflict retry. The tests are the same as on main. Assisted-by: LLM Signed-off-by: Yan Bondarenko <[email protected]>
europrinter (yankawai)
force-pushed
the
fix/application-garbage-collection-1.6
branch
from
October 6, 2026 21:56
55b5767 to
e63439b
Compare
myasnikovdaniil
merged commit Oct 14, 2026
f50f4a8
into
cozystack:release-1.6
12 of 44 checks passed
1 of 11 tasks
myasnikovdaniil
added a commit
that referenced
this pull request
Oct 14, 2026
…a and repair empty required fields (#4919) ## What this PR does Backport of #2914 and #3956 to `release-1.6`. It sits on top of #4683, which is merged here now. #2914: `Update` on an Application rebuilds the HelmRelease and sends a full-replace PUT, so metadata owned by other controllers was dropped, helm-controller's `finalizers.fluxcd.io` among it. A delete landing before helm-controller added the finalizer back removed the HelmRelease without `helm uninstall` and orphaned every resource of the release. Now `Update` carries over finalizers, ownerReferences and labels/annotations outside the `apps.cozystack.io-` prefix from the live object, `mergeMaps` no longer returns the shared config map that requests wrote into, and a conflict retry rebuilds the carried metadata from the object it just read instead of writing the stale copy back. #3956: a required spec field written with nothing under it (`replicas:`) reached Helm as null, Helm coalescing deletes it together with the chart default before schema validation, and the whole release failed with "missing property" for a property the spec does contain. Such a null is removed on Create and Update now so the chart default applies, and the client gets a warning with the field name. Optional fields, free-form subtrees, user-keyed map entries and array elements keep their nulls. Admission validates the normalized copy, the caller's object is not mutated anymore. On this branch #4683 inlined the garbage collection finalizer merge and the deletion metadata copy, because `applyLiveMetadata` didn't exist yet. They move into `applyLiveMetadata` here, so `Update` and its helpers match main. Suspend preservation (#4411) is not on this branch and not part of this backport. The example field in #3956, `talos.registryMirrors`, doesn't exist in the kubernetes chart on this branch, so the tests use required fields that do (`talos.installerRepository`, `talos.version`, `controlPlane.replicas`). The node group null is its own case, because `nodeGroups` is still a typed map here and its entries require `instanceType`. Three test helpers main has from #3315 are copied into a test-only file. Production code needed one import beyond the cherry-picks. ### Validation - `go build ./...` and `go vet ./pkg/registry/...` are clean and `go test ./pkg/registry/...` passes on the head, rebased onto release-1.6 after #4683 merged. - The Helm coalescing test renders this branch's own chart values and schemas, Helm rejects the empty required fields before the repair and accepts them after it. - Reverting `applyLiveMetadata` to the plain live finalizer list, skipping the retry rebuild, or validating the un-normalized object each turns the related tests red. ### Downstream repositories The change touches the Application REST handler and its tests only: no chart, values, schema, CRD, version enum or `hack/` file, so none of the trigger map entries match. - [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: ### Release note ```release-note fix(api): updating an Application no longer strips finalizers, ownerReferences and foreign labels/annotations from its HelmRelease, which could make a following delete skip helm uninstall and orphan the release's resources. A required field written with no value in an application spec is treated as unset so the chart default applies, instead of failing the whole release. ```
Merged
1 of 11 tasks
myasnikovdaniil
added a commit
that referenced
this pull request
Oct 14, 2026
…ed across an app update (#4928) ## What this PR does Backport of #4411 to `release-1.6`. `REST.Update` rebuilds the HelmRelease from the Application and writes it back whole, and Application has no suspension, so every edit through the API resumes a release that an operator or a controller suspended. The CNPG restore driver depends on it: it suspends the target release, patches the Postgres app through this API, purges the Cluster and resumes only after the purge, so the next render lands `bootstrap.recovery` on an empty namespace. When the patch resumes the release, helm-controller upgrades right away, the Cluster gets rendered while the purge still runs, the driver deletes it, and nothing renders it again because the values don't change anymore. RestoreJob stays `Running` until its deadline. Why it is needed on this line now. The race was hidden by timing: Update dropped `finalizers.fluxcd.io`, helm-controller spent its first pass putting it back and requeued, and that delay usually let the purge finish first. #4683 and #4919 keep the finalizer across the write, so the delay is gone. After they landed, `postgres-2-backup-roundtrip` failed on v1.6.5-rc.1 (https://github.com/cozystack/cozystack/actions/runs/38583543706) and in two earlier PR runs, each time stuck at `TargetPurged: Cluster ... deleted; awaiting chart-rendered re-bootstrap`. In the snapshot of the rc run the HelmRelease of the restore target upgraded to v2 at 16:16:13Z, the Cluster was deleted at 16:16:22Z, and no Cluster of the target exists afterwards. The cherry-pick conflicted only in comments of `REST.Update`, where this branch already has the metadata carry-over. The two `Spec.Suspend` assignments merged unchanged and the comments read as they do on main. ### Validation - `go build ./...` is clean, `go vet ./pkg/registry/...` is clean, `go test ./pkg/registry/... ./internal/backupcontroller/...` passes. - Removing either `Spec.Suspend` assignment turns its test red: `TestUpdate_PreservesSuspend` for the first write, `TestUpdate_RefreshesSuspendOnConflictRetry` for the conflict retry. - Not run here: the restore round trip on a live cluster, the E2E of this PR covers it. ### Downstream repositories It changes how the aggregated API writes the HelmRelease back, no downstream repository restates that. - [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: ### Release note ```release-note fix(api): app edit through cozystack API no longer resumes a suspended HelmRelease, so postgres restore waits for its purge before the cluster is rendered again. ```
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this PR does
Backport of #4610 to
release-1.6.Updateon this branch has noapplyLiveMetadata, so the finalizer merge and the copy of the deletion metadata are done inline, inUpdateand in its conflict retry. The tests are the same as on main.An Application and its HelmRelease share one UID, so the garbage collector keeps one graph node for both and may finalize it through the Application endpoint. The API never returned finalizers on an Application, so when the collector dropped
foregroundDeletionororphanthrough it, the HelmRelease keptforegroundDeletionafter Helm had uninstalled the release and the deletion never completed. The Application now carries the two garbage collection finalizers, and an update that adds or removes one of them applies the same change to the HelmRelease. Controller finalizers such asfinalizers.fluxcd.iostay owned by the live object.Validation
go test ./pkg/registry/apps/application/...passes on this branch.Screenshots
Not a UI change.
Downstream repositories
Walked the trigger map against the diff. It changes the Application REST handler and its test, with no chart, values, schema, CRD or
hack/file, so no companion repository needs an update.Release note