Skip to content

Commit 10928c5

Browse files
committed
(feat) Add FailureMessage to helmReleaseSummaries
Previously, when a profile managed multiple Helm charts, deployment failures were only captured at the aggregate `featureSummary` level. The individual `helmReleaseSummaries` would list the charts but offer no specific visibility into which release failed. This PR introduces a `FailureMessage` field to the HelmSummary struct. This allows the controller to surface granular error messages directly from the Helm engine for each specific release. ```yaml // +optional // FailureMessage provides the specific error from the Helm engine for this release FailureMessage *string `json:"failureMessage,omitempty"` ``` In the example below, the specific "name in use" error is now correctly attributed to the specific release summary, rather than just the top-level feature: ```yaml status: dependencies: no dependencies featureSummaries: - consecutiveFailures: 12 failureMessage: 'release name check failed: cannot reuse a name that is still in use' featureID: Helm hash: wFhMn1Ap3BaXYgWatgZCIwurH58IgDRbfgr3wd9TO7s= lastAppliedTime: "2026-03-24T10:01:05Z" status: Failed helmReleaseSummaries: - failureMessage: 'release name check failed: cannot reuse a name that is still in use' releaseName: kyverno-latest releaseNamespace: kyverno status: Managing valuesHash: jLsMQyyUoho8Lt2VvihRy3KiiKWLWuSkupgNiEdY1DI= ```
1 parent c165067 commit 10928c5

7 files changed

Lines changed: 85 additions & 32 deletions

File tree

api/v1beta1/clustersummary_types.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ type HelmChartSummary struct {
114114
// chart or there is a conflict
115115
// +optional
116116
ConflictMessage string `json:"conflictMessage,omitempty"`
117+
118+
// +optional
119+
// FailureMessage provides the specific error from the Helm engine for this release
120+
FailureMessage *string `json:"failureMessage,omitempty"`
117121
}
118122

119123
// ClusterSummarySpec defines the desired state of ClusterSummary

api/v1beta1/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/config.projectsveltos.io_clustersummaries.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,6 +1650,10 @@ spec:
16501650
Status indicates whether ClusterSummary can manage the helm
16511651
chart or there is a conflict
16521652
type: string
1653+
failureMessage:
1654+
description: FailureMessage provides the specific error from
1655+
the Helm engine for this release
1656+
type: string
16531657
releaseName:
16541658
description: ReleaseName is the chart release
16551659
minLength: 1

controllers/handlers_helm.go

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1007,8 +1007,9 @@ func walkChartsAndDeploy(ctx context.Context, c client.Client, clusterSummary *c
10071007

10081008
var report *configv1beta1.ReleaseReport
10091009
var currentRelease *releaseInfo
1010-
currentRelease, report, err = handleChart(ctx, clusterSummary, mgmtResources, instantiatedChart, kubeconfig,
1011-
isPullMode, logger)
1010+
currentRelease, report, err = handleChart(ctx, clusterSummary, mgmtResources, instantiatedChart,
1011+
kubeconfig, isPullMode, logger)
1012+
setHelmFailureMessageOnHelmChartSummary(clusterSummary, currentChart, err)
10121013
if err != nil {
10131014
if clusterSummary.Spec.ClusterProfileSpec.ContinueOnError {
10141015
errorMsg += fmt.Sprintf("chart: %s, release: %s, %v\n",
@@ -1018,7 +1019,8 @@ func walkChartsAndDeploy(ctx context.Context, c client.Client, clusterSummary *c
10181019
return releaseReports, chartDeployed, err
10191020
}
10201021

1021-
valueHash, err := updateValueHashOnHelmChartSummary(ctx, instantiatedChart, clusterSummary, mgmtResources, logger)
1022+
valueHash, err := updateValueHashOnHelmChartSummary(ctx, instantiatedChart, clusterSummary, mgmtResources,
1023+
logger)
10221024
if err != nil {
10231025
return releaseReports, chartDeployed, err
10241026
}
@@ -1032,10 +1034,12 @@ func walkChartsAndDeploy(ctx context.Context, c client.Client, clusterSummary *c
10321034
valueHash, currentRelease.Status))
10331035
} else {
10341036
logger.V(logs.LogInfo).Info(fmt.Sprintf("release %s/%s (version %s) status: %s",
1035-
currentRelease.ReleaseNamespace, currentRelease.ReleaseName, currentRelease.ChartVersion, currentRelease.Status))
1037+
currentRelease.ReleaseNamespace, currentRelease.ReleaseName, currentRelease.ChartVersion,
1038+
currentRelease.Status))
10361039
}
10371040
if currentRelease.Status == releasecommon.StatusDeployed.String() {
1038-
// Deployed chart is used for updating ClusterConfiguration. There is no ClusterConfiguration for mgmt cluster
1041+
// Deployed chart is used for updating ClusterConfiguration. There is no ClusterConfiguration
1042+
// for mgmt cluster
10391043
chartDeployed = append(chartDeployed, configv1beta1.Chart{
10401044
RepoURL: instantiatedChart.RepositoryURL,
10411045
Namespace: currentRelease.ReleaseNamespace,
@@ -1065,6 +1069,59 @@ func walkChartsAndDeploy(ctx context.Context, c client.Client, clusterSummary *c
10651069
return releaseReports, chartDeployed, nil
10661070
}
10671071

1072+
func setHelmFailureMessageOnHelmChartSummary(clusterSummary *configv1beta1.ClusterSummary,
1073+
instantiatedChart *configv1beta1.HelmChart, err error) {
1074+
1075+
for i := range clusterSummary.Status.HelmReleaseSummaries {
1076+
hr := &clusterSummary.Status.HelmReleaseSummaries[i]
1077+
if hr.ReleaseNamespace == instantiatedChart.ReleaseNamespace &&
1078+
hr.ReleaseName == instantiatedChart.ReleaseName {
1079+
1080+
if err == nil {
1081+
clusterSummary.Status.HelmReleaseSummaries[i].FailureMessage = nil
1082+
} else {
1083+
failureMessage := err.Error()
1084+
clusterSummary.Status.HelmReleaseSummaries[i].FailureMessage = &failureMessage
1085+
}
1086+
return
1087+
}
1088+
}
1089+
}
1090+
1091+
// getFailureMessageFromHelmChartSummary returns the failureMessage stored for this chart
1092+
// in the ClusterSummary
1093+
func getFailureMessageFromHelmChartSummary(requestedChart *configv1beta1.HelmChart,
1094+
clusterSummary *configv1beta1.ClusterSummary) *string {
1095+
1096+
for i := range clusterSummary.Status.HelmReleaseSummaries {
1097+
rs := &clusterSummary.Status.HelmReleaseSummaries[i]
1098+
if rs.ReleaseName == requestedChart.ReleaseName &&
1099+
rs.ReleaseNamespace == requestedChart.ReleaseNamespace {
1100+
1101+
return rs.FailureMessage
1102+
}
1103+
}
1104+
1105+
return nil
1106+
}
1107+
1108+
// getValueHashFromHelmChartSummary returns the valueHash stored for this chart
1109+
// in the ClusterSummary
1110+
func getValueHashFromHelmChartSummary(requestedChart *configv1beta1.HelmChart,
1111+
clusterSummary *configv1beta1.ClusterSummary) []byte {
1112+
1113+
for i := range clusterSummary.Status.HelmReleaseSummaries {
1114+
rs := &clusterSummary.Status.HelmReleaseSummaries[i]
1115+
if rs.ReleaseName == requestedChart.ReleaseName &&
1116+
rs.ReleaseNamespace == requestedChart.ReleaseNamespace {
1117+
1118+
return rs.ValuesHash
1119+
}
1120+
}
1121+
1122+
return nil
1123+
}
1124+
10681125
func generateConflictForHelmChart(ctx context.Context, clusterSummary *configv1beta1.ClusterSummary,
10691126
instantiatedChart *configv1beta1.HelmChart) string {
10701127

@@ -1553,10 +1610,10 @@ func installRelease(ctx context.Context, clusterSummary *configv1beta1.ClusterSu
15531610
// This condition should never occur. A previous check ensures that only one
15541611
// ClusterProfile/Profile can manage a Helm Chart with a given name in a
15551612
// specific namespace within a managed cluster. If this code is reached,
1556-
// that check has already passed. Therefore, the "cannot re-use a name that
1613+
// that check has already passed. Therefore, the "cannot reuse a name that
15571614
// is still in use" error should be impossible.
15581615
// There is no constant defined in the helm library but this is an error seen more than once.
1559-
if err.Error() == "cannot re-use a name that is still in use" {
1616+
if strings.Contains(err.Error(), "cannot reuse a name that is still in use") {
15601617
_, err = upgradeRelease(ctx, clusterSummary, settings, requestedChart, kubeconfig, registryOptions,
15611618
values, mgmtResources, logger)
15621619
return nil, err
@@ -2529,6 +2586,7 @@ func updateStatusForReferencedHelmReleases(ctx context.Context, c client.Client,
25292586
ReleaseName: instantiatedChart.ReleaseName,
25302587
ReleaseNamespace: instantiatedChart.ReleaseNamespace,
25312588
Status: configv1beta1.HelmChartStatusManaging,
2589+
FailureMessage: getFailureMessageFromHelmChartSummary(instantiatedChart, clusterSummary),
25322590
ValuesHash: getValueHashFromHelmChartSummary(instantiatedChart, clusterSummary), // if a value is currently stored, keep it.
25332591
// after chart is deployed such value will be updated
25342592
}
@@ -2604,11 +2662,6 @@ func updateStatusForNonReferencedHelmReleases(ctx context.Context, c client.Clie
26042662
}
26052663
}
26062664

2607-
if len(helmReleaseSummaries) == len(clusterSummary.Status.HelmReleaseSummaries) {
2608-
// Nothing has changed
2609-
return clusterSummary, nil
2610-
}
2611-
26122665
currentClusterSummary := &configv1beta1.ClusterSummary{}
26132666
err := c.Get(ctx,
26142667
types.NamespacedName{Namespace: clusterSummary.Namespace, Name: clusterSummary.Name}, currentClusterSummary)
@@ -3813,23 +3866,6 @@ func updateValueHashOnHelmChartSummary(ctx context.Context, requestedChart *conf
38133866
return helmChartValuesHash, err
38143867
}
38153868

3816-
// getValueHashFromHelmChartSummary returns the valueHash stored for this chart
3817-
// in the ClusterSummary
3818-
func getValueHashFromHelmChartSummary(requestedChart *configv1beta1.HelmChart,
3819-
clusterSummary *configv1beta1.ClusterSummary) []byte {
3820-
3821-
for i := range clusterSummary.Status.HelmReleaseSummaries {
3822-
rs := &clusterSummary.Status.HelmReleaseSummaries[i]
3823-
if rs.ReleaseName == requestedChart.ReleaseName &&
3824-
rs.ReleaseNamespace == requestedChart.ReleaseNamespace {
3825-
3826-
return rs.ValuesHash
3827-
}
3828-
}
3829-
3830-
return nil
3831-
}
3832-
38333869
func getCredentialsAndCAFiles(ctx context.Context, c client.Client, clusterSummary *configv1beta1.ClusterSummary,
38343870
requestedChart *configv1beta1.HelmChart) (credentialsPath, caPath string, err error) {
38353871

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ require (
1818
github.com/onsi/ginkgo/v2 v2.28.1
1919
github.com/onsi/gomega v1.39.1
2020
github.com/pkg/errors v0.9.1
21-
github.com/projectsveltos/libsveltos v1.6.1
21+
github.com/projectsveltos/libsveltos v1.6.2-0.20260323171327-a0d7029ca880
2222
github.com/prometheus/client_golang v1.23.2
2323
github.com/robfig/cron v1.2.0
2424
github.com/spf13/pflag v1.0.10

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -278,8 +278,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI
278278
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
279279
github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY=
280280
github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg=
281-
github.com/projectsveltos/libsveltos v1.6.1 h1:+NRYGDWONyUfjX0/LKFtPwvK/eQhO/jz1yvcPBj2lVA=
282-
github.com/projectsveltos/libsveltos v1.6.1/go.mod h1:Wi/ICx8bv1SGBuzIu6ZFEJAosauY3jA/wbIe1SCvnEs=
281+
github.com/projectsveltos/libsveltos v1.6.2-0.20260323171327-a0d7029ca880 h1:PrrZB3Fw9WT7fQ2G7VmZKzd70gjBSLzWKeIHQnSssFM=
282+
github.com/projectsveltos/libsveltos v1.6.2-0.20260323171327-a0d7029ca880/go.mod h1:j3RWlB9jVFbZasy89M2xkp7wqyy6p46oea++VbP3E3Y=
283283
github.com/projectsveltos/lua-utils/glua-json v0.0.0-20251212200258-2b3cdcb7c0f5 h1:khnc+994UszxZYu69J+R5FKiLA/Nk1JQj0EYAkwTWz0=
284284
github.com/projectsveltos/lua-utils/glua-json v0.0.0-20251212200258-2b3cdcb7c0f5/go.mod h1:yVL8KQFa9tmcxgwl9nwIMtKgtmIVC1zaFRSCfOwYvPY=
285285
github.com/projectsveltos/lua-utils/glua-runes v0.0.0-20251212200258-2b3cdcb7c0f5 h1:YbsebwRwTRhV8QacvEAdFqxcxHdeu7JTVtsBovbkgos=

manifest/manifest.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5783,6 +5783,10 @@ spec:
57835783
Status indicates whether ClusterSummary can manage the helm
57845784
chart or there is a conflict
57855785
type: string
5786+
failureMessage:
5787+
description: FailureMessage provides the specific error from
5788+
the Helm engine for this release
5789+
type: string
57865790
releaseName:
57875791
description: ReleaseName is the chart release
57885792
minLength: 1

0 commit comments

Comments
 (0)