@@ -39,6 +39,11 @@ const (
3939 maxHelmReleaseHistory = 10
4040)
4141
42+ var (
43+ errPendingRelease = errors .New ("release is in a pending state" )
44+ errBundleToHelmChartConverterNil = errors .New ("BundleToHelmChartConverter is nil" )
45+ )
46+
4247// Preflight is a check that should be run before making any changes to the cluster
4348type Preflight interface {
4449 // Install runs checks that should be successful prior
@@ -144,6 +149,23 @@ func (h *Helm) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1.ClusterExte
144149 }
145150
146151 rel , desiredRel , state , err := h .getReleaseState (ctx , ac , ext , chrt , values , post )
152+ // if a release is pending, that means that a helm action
153+ // (installation/upgrade) we were attempting was likely interrupted in-flight.
154+ // Pending release would leave us in reconciliation error loop because helm
155+ // wouldn't be able to progress automatically from it.
156+ //
157+ // one of the workarounds is to try and remove helm metadata relating to
158+ // that pending release which should 'reset' its state communicated to helm
159+ // and the next reconciliation should be able to successfully pick up from here
160+ // for context see: https://github.com/helm/helm/issues/5595 and https://github.com/helm/helm/issues/7476
161+ // and the discussion in https://github.com/operator-framework/operator-controller/pull/1776
162+ if errors .Is (err , errPendingRelease ) {
163+ if _ , err := ac .Config ().Releases .Delete (rel .Name , rel .Version ); err != nil {
164+ return nil , "" , fmt .Errorf ("failed removing pending release %q version %d metadata: %w" , rel .Name , rel .Version , err )
165+ }
166+ // return an error to try to detect proper state (installation/upgrade) at next reconciliation
167+ return nil , "" , fmt .Errorf ("removed pending release %q version %d metadata" , rel .Name , rel .Version )
168+ }
147169 if err != nil {
148170 return nil , "" , fmt .Errorf ("failed to get release state using server-side dry-run: %w" , err )
149171 }
@@ -203,7 +225,7 @@ func (h *Helm) Apply(ctx context.Context, contentFS fs.FS, ext *ocv1.ClusterExte
203225
204226func (h * Helm ) buildHelmChart (bundleFS fs.FS , ext * ocv1.ClusterExtension ) (* chart.Chart , error ) {
205227 if h .BundleToHelmChartConverter == nil {
206- return nil , errors . New ( "BundleToHelmChartConverter is nil" )
228+ return nil , errBundleToHelmChartConverterNil
207229 }
208230 watchNamespace , err := GetWatchNamespace (ext )
209231 if err != nil {
@@ -244,24 +266,6 @@ func (h *Helm) getReleaseState(ctx context.Context, cl helmclient.ActionInterfac
244266 logger := log .FromContext (ctx )
245267 currentRelease , err := cl .Get (ext .GetName ())
246268
247- // if a release is pending at this point, that means that a helm action
248- // (installation/upgrade) we were attempting was likely interrupted in-flight.
249- // Pending release would leave us in reconciliation error loop because helm
250- // wouldn't be able to progress automatically from it.
251- //
252- // one of the workarounds is to try and remove helm metadata relating to
253- // that pending release which should 'reset' its state communicated to helm
254- // and the next reconciliation should be able to successfully pick up from here
255- // for context see: https://github.com/helm/helm/issues/5595 and https://github.com/helm/helm/issues/7476
256- // and the discussion in https://github.com/operator-framework/operator-controller/pull/1776
257- if err == nil && currentRelease .Info .Status .IsPending () {
258- if _ , err = cl .Config ().Releases .Delete (currentRelease .Name , currentRelease .Version ); err != nil {
259- return nil , nil , StateError , fmt .Errorf ("failed removing interrupted release %q version %d metadata: %w" , currentRelease .Name , currentRelease .Version , err )
260- }
261- // return error to try to detect proper state (installation/upgrade) at next reconciliation
262- return nil , nil , StateError , fmt .Errorf ("removed interrupted release %q version %d metadata" , currentRelease .Name , currentRelease .Version )
263- }
264-
265269 if errors .Is (err , driver .ErrReleaseNotFound ) {
266270 logger .V (4 ).Info ("ClusterExtension dry-run install" , "extension" , ext .GetName ())
267271 desiredRelease , err := cl .Install (ext .GetName (), ext .Spec .Namespace , chrt , values , func (i * action.Install ) error {
@@ -277,6 +281,9 @@ func (h *Helm) getReleaseState(ctx context.Context, cl helmclient.ActionInterfac
277281 if err != nil {
278282 return nil , nil , StateError , err
279283 }
284+ if currentRelease .Info .Status .IsPending () {
285+ return currentRelease , nil , StateError , errPendingRelease
286+ }
280287
281288 desiredRelease , err := cl .Upgrade (ext .GetName (), ext .Spec .Namespace , chrt , values , func (upgrade * action.Upgrade ) error {
282289 logger .V (4 ).Info ("ClusterExtension dry-run upgrade" , "extension" , ext .GetName ())
0 commit comments