fix: clear stale Helm Conflict entry when ownership is won mid-deploy… - #1980
Merged
gianlucam76 merged 1 commit intoSep 17, 2026
Merged
Conversation
…projectsveltos#1975) buildReferencedHelmReleaseSummaries is the only code that computes the Status and ConflictMessage fields of Status.HelmReleaseSummaries. It runs once per pass, from updateStatusForReferencedHelmReleases at the start of handleCharts. walkChartsAndDeploy then checks ownership again, per chart, in deploySingleChart. The two checks can disagree. If the ClusterSummary that holds a release unregisters between them, this ClusterSummary can win the chart and deploy it, while the entry written moments earlier still says Conflict and names a ClusterSummary that is already gone. Nothing later in the pass corrected that entry. updateValueHashOnHelmChartSummary wrote ValuesHash, PatchesHash and NeedsRedeploy, but not Status. updateStatusForNonReferencedHelmReleases re-reads the ClusterSummary and copies each referenced entry verbatim, overriding only FailureMessage. The pass ends with no error, so the feature goes to Provisioned. The state is then permanent: shouldRedeploy returns false for a deployed feature whose hash has not changed, so proceedDeployingFeature is never reached and the Helm handler never runs again to recompute the entry. The profile reports a Conflict against a ClusterSummary that no longer exists, until an operator clears the feature summary by hand. This is the sibling case of the race fixed in projectsveltos#1741. There the deploy fails with a NonRetriableError and helmConflictResolved recovers it. Here the deploy succeeds, so proceedDeployingFeature returns on the Provisioned branch, before reaching the deployerError != nil block that guards helmConflictResolved. updateValueHashOnHelmChartSummary is the one status write reached per chart after deploySingleChart confirmed ownership, so it now resets the entry to Managing and clears ConflictMessage. A fresh chartManager.CanManageChart check guards the write, so the correction cannot apply to a release this ClusterSummary does not own even if the function gains another caller. DryRun is excluded: it can pass the ownership check without ever registering, and it no-ops the two functions that otherwise maintain these entries. The correction relies on updateStatusForNonReferencedHelmReleases, which runs afterwards and does its own Status().Update, to carry the value forward. It does, because it re-reads from the API server rather than using the in-memory copy.
gianlucam76
merged commit Sep 17, 2026
7fd9a29
into
projectsveltos:release-1.15
19 of 20 checks passed
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.
… (#1975)
buildReferencedHelmReleaseSummaries is the only code that computes the Status and ConflictMessage fields of Status.HelmReleaseSummaries. It runs once per pass, from updateStatusForReferencedHelmReleases at the start of handleCharts. walkChartsAndDeploy then checks ownership again, per chart, in deploySingleChart.
The two checks can disagree. If the ClusterSummary that holds a release unregisters between them, this ClusterSummary can win the chart and deploy it, while the entry written moments earlier still says Conflict and names a ClusterSummary that is already gone.
Nothing later in the pass corrected that entry. updateValueHashOnHelmChartSummary wrote ValuesHash, PatchesHash and NeedsRedeploy, but not Status. updateStatusForNonReferencedHelmReleases re-reads the ClusterSummary and copies each referenced entry verbatim, overriding only FailureMessage.
The pass ends with no error, so the feature goes to Provisioned. The state is then permanent: shouldRedeploy returns false for a deployed feature whose hash has not changed, so proceedDeployingFeature is never reached and the Helm handler never runs again to recompute the entry. The profile reports a Conflict against a ClusterSummary that no longer exists, until an operator clears the feature summary by hand.
This is the sibling case of the race fixed in #1741. There the deploy fails with a NonRetriableError and helmConflictResolved recovers it. Here the deploy succeeds, so proceedDeployingFeature returns on the Provisioned branch, before reaching the deployerError != nil block that guards helmConflictResolved.
updateValueHashOnHelmChartSummary is the one status write reached per chart after deploySingleChart confirmed ownership, so it now resets the entry to Managing and clears ConflictMessage. A fresh chartManager.CanManageChart check guards the write, so the correction cannot apply to a release this ClusterSummary does not own even if the function gains another caller. DryRun is excluded: it can pass the ownership check without ever registering, and it no-ops the two functions that otherwise maintain these entries.
The correction relies on updateStatusForNonReferencedHelmReleases, which runs afterwards and does its own Status().Update, to carry the value forward. It does, because it re-reads from the API server rather than using the in-memory copy.