@@ -36,6 +36,11 @@ const (
3636 maxHelmReleaseHistory = 10
3737)
3838
39+ var (
40+ errPendingRelease = errors .New ("release is in a pending state" )
41+ errBuildHelmChartFuncNil = errors .New ("BundleToHelmChartFn is nil" )
42+ )
43+
3944// Preflight is a check that should be run before making any changes to the cluster
4045type Preflight interface {
4146 // Install runs checks that should be successful prior
@@ -96,6 +101,23 @@ func (h *Helm) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1.ClusterExte
96101 }
97102
98103 rel , desiredRel , state , err := h .getReleaseState (ctx , ac , ext , chrt , values , post )
104+ // if a release is pending, that means that a helm action
105+ // (installation/upgrade) we were attempting was likely interrupted in-flight.
106+ // Pending release would leave us in reconciliation error loop because helm
107+ // wouldn't be able to progress automatically from it.
108+ //
109+ // one of the workarounds is to try and remove helm metadata relating to
110+ // that pending release which should 'reset' its state communicated to helm
111+ // and the next reconciliation should be able to successfully pick up from here
112+ // for context see: https://github.com/helm/helm/issues/5595 and https://github.com/helm/helm/issues/7476
113+ // and the discussion in https://github.com/operator-framework/operator-controller/pull/1776
114+ if errors .Is (err , errPendingRelease ) {
115+ if _ , err := ac .Config ().Releases .Delete (rel .Name , rel .Version ); err != nil {
116+ return nil , "" , fmt .Errorf ("failed removing pending release %q version %d metadata: %w" , rel .Name , rel .Version , err )
117+ }
118+ // return an error to try to detect proper state (installation/upgrade) at next reconciliation
119+ return nil , "" , fmt .Errorf ("removed pending release %q version %d metadata" , rel .Name , rel .Version )
120+ }
99121 if err != nil {
100122 return nil , "" , err
101123 }
@@ -155,7 +177,7 @@ func (h *Helm) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1.ClusterExte
155177
156178func (h * Helm ) buildHelmChart (bundleFS fs.FS , ext * ocv1.ClusterExtension ) (* chart.Chart , error ) {
157179 if h .BundleToHelmChartFn == nil {
158- return nil , errors . New ( "BundleToHelmChartFn is nil" )
180+ return nil , errBuildHelmChartFuncNil
159181 }
160182 watchNamespace , err := GetWatchNamespace (ext )
161183 if err != nil {
@@ -168,24 +190,6 @@ func (h *Helm) getReleaseState(ctx context.Context, cl helmclient.ActionInterfac
168190 logger := log .FromContext (ctx )
169191 currentRelease , err := cl .Get (ext .GetName ())
170192
171- // if a release is pending at this point, that means that a helm action
172- // (installation/upgrade) we were attempting was likely interrupted in-flight.
173- // Pending release would leave us in reconciliation error loop because helm
174- // wouldn't be able to progress automatically from it.
175- //
176- // one of the workarounds is to try and remove helm metadata relating to
177- // that pending release which should 'reset' its state communicated to helm
178- // and the next reconciliation should be able to successfully pick up from here
179- // for context see: https://github.com/helm/helm/issues/5595 and https://github.com/helm/helm/issues/7476
180- // and the discussion in https://github.com/operator-framework/operator-controller/pull/1776
181- if err == nil && currentRelease .Info .Status .IsPending () {
182- if _ , err = cl .Config ().Releases .Delete (currentRelease .Name , currentRelease .Version ); err != nil {
183- return nil , nil , StateError , fmt .Errorf ("failed removing interrupted release %q version %d metadata: %w" , currentRelease .Name , currentRelease .Version , err )
184- }
185- // return error to try to detect proper state (installation/upgrade) at next reconciliation
186- return nil , nil , StateError , fmt .Errorf ("removed interrupted release %q version %d metadata" , currentRelease .Name , currentRelease .Version )
187- }
188-
189193 if errors .Is (err , driver .ErrReleaseNotFound ) {
190194 logger .V (4 ).Info ("ClusterExtension dry-run install" , "extension" , ext .GetName ())
191195 desiredRelease , err := cl .Install (ext .GetName (), ext .Spec .Namespace , chrt , values , func (i * action.Install ) error {
@@ -205,6 +209,9 @@ func (h *Helm) getReleaseState(ctx context.Context, cl helmclient.ActionInterfac
205209 if err != nil {
206210 return nil , nil , StateError , err
207211 }
212+ if currentRelease .Info .Status .IsPending () {
213+ return currentRelease , nil , StateError , errPendingRelease
214+ }
208215
209216 desiredRelease , err := cl .Upgrade (ext .GetName (), ext .Spec .Namespace , chrt , values , func (upgrade * action.Upgrade ) error {
210217 logger .V (4 ).Info ("ClusterExtension dry-run upgrade" , "extension" , ext .GetName ())
0 commit comments