55 "encoding/json"
66 "errors"
77 "fmt"
8+ "k8s.io/apimachinery/pkg/types"
89 "reflect"
910 "sort"
1011 "strings"
@@ -1492,10 +1493,16 @@ func (o *Operator) syncResolvingNamespace(obj interface{}) error {
14921493 }
14931494 }
14941495
1496+ // ************************************************ WARNING ************************************************* //
1497+ // if updateSubscriptionStatuses call fails and the IP reference was changed in this run, //
1498+ // we'll be screwed because the IP would have been created but the subscription won't carry its reference. //
1499+ // And if the CSV gets created by the IP, it won't be associated with the Subscription //
1500+ // -> perma-failure on resolution //
1501+ // ********************************************************************************************************** //
14951502 // Update subscriptions with all changes so far
1496- _ , updateErr := o .updateSubscriptionStatuses (subs )
1503+ _ , updateErr := o .patchSubscriptionStatuses (subs )
14971504 if updateErr != nil {
1498- logger .WithError (updateErr ).Warn ("failed to update subscription conditions" )
1505+ logger .WithError (updateErr ).Warn ("failed to patch subscription conditions" )
14991506 return updateErr
15001507 }
15011508
@@ -1667,15 +1674,23 @@ func (o *Operator) ensureInstallPlan(logger *logrus.Entry, namespace string, gen
16671674 }
16681675 logger .Warn ("no installplan found with matching generation, creating new one" )
16691676
1670- return o .createInstallPlan (namespace , gen , subs , installPlanApproval , steps , bundleLookups )
1677+ // **************************** WARNING **************************** //
1678+ // If this call fails, after the IP is created, the IP will never
1679+ // do anything since it requires the steps to exist in .status
1680+ // ***************************************************************** //
1681+ ip , err := o .createInstallPlan (namespace , gen , subs , installPlanApproval , steps , bundleLookups )
1682+ if err != nil {
1683+ return nil , err
1684+ }
1685+ return reference .GetReference (ip )
16711686}
16721687
16731688func (o * Operator ) createInstallPlan (namespace string , gen int , subs []* v1alpha1.Subscription , installPlanApproval v1alpha1.Approval , steps []* v1alpha1.Step , bundleLookups []v1alpha1.BundleLookup ) (* corev1.ObjectReference , error ) {
16741689 if len (steps ) == 0 && len (bundleLookups ) == 0 {
16751690 return nil , nil
16761691 }
16771692
1678- csvNames := []string {}
1693+ var csvNames []string
16791694 catalogSourceMap := map [string ]struct {}{}
16801695 for _ , s := range steps {
16811696 if s .Resource .Kind == "ClusterServiceVersion" {
@@ -1684,7 +1699,7 @@ func (o *Operator) createInstallPlan(namespace string, gen int, subs []*v1alpha1
16841699 catalogSourceMap [s .Resource .CatalogSource ] = struct {}{}
16851700 }
16861701
1687- catalogSources := []string {}
1702+ var catalogSources []string
16881703 for s := range catalogSourceMap {
16891704 catalogSources = append (catalogSources , s )
16901705 }
@@ -1720,6 +1735,7 @@ func (o *Operator) createInstallPlan(namespace string, gen int, subs []*v1alpha1
17201735 CatalogSources : catalogSources ,
17211736 BundleLookups : bundleLookups ,
17221737 }
1738+
17231739 res , err = o .client .OperatorsV1alpha1 ().InstallPlans (namespace ).UpdateStatus (context .TODO (), res , metav1.UpdateOptions {})
17241740 if err != nil {
17251741 return nil , err
@@ -1763,6 +1779,56 @@ func (o *Operator) removeSubsCond(subs []*v1alpha1.Subscription, condType v1alph
17631779 }
17641780}
17651781
1782+ func (o * Operator ) patchSubscriptionStatuses (subs []* v1alpha1.Subscription ) ([]* v1alpha1.Subscription , error ) {
1783+ var (
1784+ errs []error
1785+ mu sync.Mutex
1786+ wg sync.WaitGroup
1787+ patchOpts = metav1.PatchOptions {}
1788+ )
1789+
1790+ lastUpdated := o .now ()
1791+
1792+ for _ , sub := range subs {
1793+ wg .Add (1 )
1794+ go func (sub * v1alpha1.Subscription ) {
1795+ defer wg .Done ()
1796+
1797+ patch := map [string ]interface {}{
1798+ "status" : map [string ]interface {}{
1799+ "conditions" : sub .Status .Conditions ,
1800+ "currentCSV" : sub .Status .CurrentCSV ,
1801+ "installPlanRef" : sub .Status .InstallPlanRef ,
1802+ "installPlan" : sub .Status .Install ,
1803+ "installPlanGeneration" : sub .Status .InstallPlanGeneration ,
1804+ "lastUpdated" : lastUpdated ,
1805+ },
1806+ }
1807+
1808+ patchBytes , err := json .Marshal (patch )
1809+ if err != nil {
1810+ errs = append (errs , err )
1811+ return
1812+ }
1813+
1814+ if _ , err := o .client .OperatorsV1alpha1 ().Subscriptions (sub .Namespace ).Patch (
1815+ context .TODO (),
1816+ sub .GetName (),
1817+ types .MergePatchType ,
1818+ patchBytes ,
1819+ patchOpts ,
1820+ "status" ,
1821+ ); err != nil {
1822+ mu .Lock ()
1823+ defer mu .Unlock ()
1824+ errs = append (errs , err )
1825+ }
1826+ }(sub )
1827+ }
1828+ wg .Wait ()
1829+ return subs , utilerrors .NewAggregate (errs )
1830+ }
1831+
17661832func (o * Operator ) updateSubscriptionStatuses (subs []* v1alpha1.Subscription ) ([]* v1alpha1.Subscription , error ) {
17671833 var (
17681834 errs []error
0 commit comments