55 "encoding/json"
66 "errors"
77 "fmt"
8+ "k8s.io/client-go/util/retry"
89 "reflect"
910 "sort"
1011 "strings"
@@ -1477,25 +1478,30 @@ func (o *Operator) syncResolvingNamespace(obj interface{}) error {
14771478 o .removeSubsCond (subs , v1alpha1 .SubscriptionResolutionFailed )
14781479
14791480 for _ , updatedSub := range updatedSubs {
1480- newSub := true
1481+ isNewSub := true
14811482 updatedSub .Status .RemoveConditions (v1alpha1 .SubscriptionResolutionFailed )
14821483 for i , sub := range subs {
14831484 if sub .Name == updatedSub .Name && sub .Namespace == updatedSub .Namespace {
14841485 subs [i ] = updatedSub
1485- newSub = false
1486+ isNewSub = false
14861487 break
14871488 }
14881489 }
1489- if newSub {
1490+ if isNewSub {
14901491 subs = append (subs , updatedSub )
1491- continue
14921492 }
14931493 }
14941494
1495+ // *********************************** WARNING *********************************** //
1496+ // if updateSubscriptionStatuses call fails and the IP reference was changed //
1497+ // in this run, we'll be screwed because the IP would have been created but the //
1498+ // subscription won't carry its reference. And, if the CSV gets created by the IP, //
1499+ // it won't be associated with the Subscription -> perma-failure on resolution //
1500+ // ******************************************************************************* //
14951501 // Update subscriptions with all changes so far
14961502 _ , updateErr := o .updateSubscriptionStatuses (subs )
14971503 if updateErr != nil {
1498- logger .WithError (updateErr ).Warn ("failed to update subscription conditions" )
1504+ logger .WithField ( "irreconcilable-resolution" , namespace ). WithError (updateErr ).Warn ("failed to patch subscription conditions" )
14991505 return updateErr
15001506 }
15011507
@@ -1675,7 +1681,7 @@ func (o *Operator) createInstallPlan(namespace string, gen int, subs []*v1alpha1
16751681 return nil , nil
16761682 }
16771683
1678- csvNames := []string {}
1684+ var csvNames []string
16791685 catalogSourceMap := map [string ]struct {}{}
16801686 for _ , s := range steps {
16811687 if s .Resource .Kind == "ClusterServiceVersion" {
@@ -1684,7 +1690,7 @@ func (o *Operator) createInstallPlan(namespace string, gen int, subs []*v1alpha1
16841690 catalogSourceMap [s .Resource .CatalogSource ] = struct {}{}
16851691 }
16861692
1687- catalogSources := []string {}
1693+ var catalogSources []string
16881694 for s := range catalogSourceMap {
16891695 catalogSources = append (catalogSources , s )
16901696 }
@@ -1720,12 +1726,18 @@ func (o *Operator) createInstallPlan(namespace string, gen int, subs []*v1alpha1
17201726 CatalogSources : catalogSources ,
17211727 BundleLookups : bundleLookups ,
17221728 }
1723- res , err = o .client .OperatorsV1alpha1 ().InstallPlans (namespace ).UpdateStatus (context .TODO (), res , metav1.UpdateOptions {})
1729+
1730+ // *************************** WARNING *************************** //
1731+ // If this call fails, the IP will never do anything since it //
1732+ // requires the steps to exist in .status //
1733+ // *************************************************************** //
1734+ newRes , err := o .client .OperatorsV1alpha1 ().InstallPlans (namespace ).UpdateStatus (context .TODO (), res , metav1.UpdateOptions {})
17241735 if err != nil {
1736+ o .logger .WithField ("irreconcilable-ip" , res .GetName ()).WithError (err ).Warn ("error updating installplan status after creation" )
17251737 return nil , err
17261738 }
17271739
1728- return reference .GetReference (res )
1740+ return reference .GetReference (newRes )
17291741}
17301742
17311743// setSubsCond will set the condition to the subscription if it doesn't already
@@ -1749,7 +1761,7 @@ func (o *Operator) setSubsCond(subs []*v1alpha1.Subscription, cond v1alpha1.Subs
17491761 return subList
17501762}
17511763
1752- // removeSubsCond removes the given condition from all of the subscriptions in the input
1764+ // removeSubsCond removes the given condition from all the subscriptions in the input
17531765func (o * Operator ) removeSubsCond (subs []* v1alpha1.Subscription , condType v1alpha1.SubscriptionConditionType ) {
17541766 lastUpdated := o .now ()
17551767 for _ , sub := range subs {
@@ -1775,7 +1787,19 @@ func (o *Operator) updateSubscriptionStatuses(subs []*v1alpha1.Subscription) ([]
17751787 wg .Add (1 )
17761788 go func (sub * v1alpha1.Subscription ) {
17771789 defer wg .Done ()
1778- if _ , err := o .client .OperatorsV1alpha1 ().Subscriptions (sub .Namespace ).UpdateStatus (context .TODO (), sub , updateOpts ); err != nil {
1790+
1791+ update := func () error {
1792+ // Update the status of the latest revision
1793+ latest , err := o .client .OperatorsV1alpha1 ().Subscriptions (sub .GetNamespace ()).Get (context .TODO (), sub .GetName (), getOpts )
1794+ if err != nil {
1795+ return err
1796+ }
1797+ latest .Status = sub .Status
1798+ * sub = * latest
1799+ _ , err = o .client .OperatorsV1alpha1 ().Subscriptions (sub .Namespace ).UpdateStatus (context .TODO (), latest , updateOpts )
1800+ return err
1801+ }
1802+ if err := retry .RetryOnConflict (retry .DefaultRetry , update ); err != nil {
17791803 mu .Lock ()
17801804 defer mu .Unlock ()
17811805 errs = append (errs , err )
0 commit comments