@@ -607,11 +607,6 @@ func (a *Operator) syncCopyCSV(obj interface{}) (syncError error) {
607607 return
608608 }
609609
610- if len (operatorGroup .Status .Namespaces ) == 1 && operatorGroup .Status .Namespaces [0 ] == operatorGroup .GetNamespace () {
611- logger .Debug ("skipping copy for OwnNamespace operatorgroup" )
612- return
613- }
614-
615610 logger .WithFields (logrus.Fields {
616611 "targetNamespaces" : strings .Join (operatorGroup .Status .Namespaces , "," ),
617612 }).Debug ("copying csv to targets" )
@@ -773,12 +768,6 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
773768 * out = * updated
774769 }
775770
776- // Check if the current CSV is being replaced, return with replacing status if so
777- if err := a .checkReplacementsAndUpdateStatus (out ); err != nil {
778- logger .WithError (err ).Info ("replacement check" )
779- return
780- }
781-
782771 // Verify CSV operatorgroup (and update annotations if needed)
783772 operatorGroup , err := a .operatorGroupForCSV (out , logger )
784773 if operatorGroup == nil {
@@ -889,6 +878,15 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
889878 }
890879 out .SetRequirementStatus (statuses )
891880
881+ // Check if we need to requeue the previous
882+ if prev := a .isReplacing (out ); prev != nil {
883+ if prev .Status .Phase == v1alpha1 .CSVPhaseSucceeded {
884+ if err := a .csvQueueSet .Requeue (prev .GetName (), prev .GetNamespace ()); err != nil {
885+ a .Log .WithError (err ).Warn ("error requeueing previous" )
886+ }
887+ }
888+ }
889+
892890 if ! met {
893891 logger .Info ("requirements were not met" )
894892 out .SetPhaseWithEventIfChanged (v1alpha1 .CSVPhasePending , v1alpha1 .CSVReasonRequirementsNotMet , "one or more requirements couldn't be found" , now , a .recorder )
@@ -912,6 +910,13 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
912910 return
913911 }
914912
913+ // Check if we're not ready to install part of the replacement chain yet
914+ if prev := a .isReplacing (out ); prev != nil {
915+ if prev .Status .Phase != v1alpha1 .CSVPhaseReplacing {
916+ return
917+ }
918+ }
919+
915920 logger .Info ("scheduling ClusterServiceVersion for install" )
916921 out .SetPhaseWithEvent (v1alpha1 .CSVPhaseInstallReady , v1alpha1 .CSVReasonRequirementsMet , "all requirements found, attempting install" , now , a .recorder )
917922 case v1alpha1 .CSVPhaseInstallReady :
@@ -955,6 +960,12 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
955960 }
956961
957962 case v1alpha1 .CSVPhaseSucceeded :
963+ // Check if the current CSV is being replaced, return with replacing status if so
964+ if err := a .checkReplacementsAndUpdateStatus (out ); err != nil {
965+ logger .WithError (err ).Info ("replacement check" )
966+ return
967+ }
968+
958969 installer , strategy , _ := a .parseStrategiesAndUpdateStatus (out )
959970 if strategy == nil {
960971 return
@@ -1073,6 +1084,14 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
10731084 return
10741085 }
10751086
1087+ // If we are a leaf, we should requeue the replacement for processing
1088+ if next := a .isBeingReplaced (out , a .csvSet (out .GetNamespace (), v1alpha1 .CSVPhaseAny )); next != nil {
1089+ err := a .csvQueueSet .Requeue (next .GetName (), next .GetNamespace ())
1090+ if err != nil {
1091+ a .Log .WithError (err ).Warn ("error requeuing replacement" )
1092+ }
1093+ }
1094+
10761095 // If we can find a newer version that's successfully installed, we're safe to mark all intermediates
10771096 for _ , csv := range a .findIntermediatesForDeletion (out ) {
10781097 // we only mark them in this step, in case some get deleted but others fail and break the replacement chain
@@ -1093,6 +1112,10 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
10931112 }
10941113 case v1alpha1 .CSVPhaseDeleting :
10951114 var immediate int64 = 0
1115+
1116+ if err := a .csvQueueSet .Remove (out .GetNamespace (), out .GetName ()); err != nil {
1117+ logger .WithError (err ).Debug ("error removing from queue" )
1118+ }
10961119 syncError = a .client .OperatorsV1alpha1 ().ClusterServiceVersions (out .GetNamespace ()).Delete (out .GetName (), & metav1.DeleteOptions {GracePeriodSeconds : & immediate })
10971120 if syncError != nil {
10981121 logger .Debugf ("unable to get delete csv marked for deletion: %s" , syncError .Error ())
@@ -1158,7 +1181,7 @@ func (a *Operator) checkReplacementsAndUpdateStatus(csv *v1alpha1.ClusterService
11581181 }
11591182 if replacement := a .isBeingReplaced (csv , a .csvSet (csv .GetNamespace (), v1alpha1 .CSVPhaseAny )); replacement != nil {
11601183 a .Log .Infof ("newer ClusterServiceVersion replacing %s, no-op" , csv .SelfLink )
1161- msg := fmt .Sprintf ("being replaced by csv: %s" , replacement .SelfLink )
1184+ msg := fmt .Sprintf ("being replaced by csv: %s" , replacement .GetName () )
11621185 csv .SetPhaseWithEvent (v1alpha1 .CSVPhaseReplacing , v1alpha1 .CSVReasonBeingReplaced , msg , timeNow (), a .recorder )
11631186 metrics .CSVUpgradeCount .Inc ()
11641187
@@ -1237,10 +1260,15 @@ func (a *Operator) parseStrategiesAndUpdateStatus(csv *v1alpha1.ClusterServiceVe
12371260 return installer , strategy , previousStrategy
12381261}
12391262
1240- func (a * Operator ) crdOwnerConflicts (in * v1alpha1.ClusterServiceVersion , csvs map [string ]* v1alpha1.ClusterServiceVersion ) error {
1241- for _ , crd := range in .Spec .CustomResourceDefinitions .Owned {
1242- for name , csv := range csvs {
1243- if name != in .GetName () && in .Spec .Replaces != name && csv .OwnsCRD (crd .Name ) {
1263+ func (a * Operator ) crdOwnerConflicts (in * v1alpha1.ClusterServiceVersion , csvsInNamespace map [string ]* v1alpha1.ClusterServiceVersion ) error {
1264+ csvsInChain := a .getReplacementChain (in , csvsInNamespace )
1265+ // find csvs in the namespace that are not part of the replacement chain
1266+ for name , csv := range csvsInNamespace {
1267+ if _ , ok := csvsInChain [name ]; ok {
1268+ continue
1269+ }
1270+ for _ , crd := range in .Spec .CustomResourceDefinitions .Owned {
1271+ if name != in .GetName () && csv .OwnsCRD (crd .Name ) {
12441272 return ErrCRDOwnerConflict
12451273 }
12461274 }
@@ -1249,6 +1277,53 @@ func (a *Operator) crdOwnerConflicts(in *v1alpha1.ClusterServiceVersion, csvs ma
12491277 return nil
12501278}
12511279
1280+ func (a * Operator ) getReplacementChain (in * v1alpha1.ClusterServiceVersion , csvsInNamespace map [string ]* v1alpha1.ClusterServiceVersion ) map [string ]struct {} {
1281+ current := in .GetName ()
1282+ csvsInChain := map [string ]struct {}{
1283+ current : {},
1284+ }
1285+
1286+ replacement := func (csvName string ) * string {
1287+ for _ , csv := range csvsInNamespace {
1288+ if csv .Spec .Replaces == csvName {
1289+ name := csv .GetName ()
1290+ return & name
1291+ }
1292+ }
1293+ return nil
1294+ }
1295+
1296+ replaces := func (replaces string ) * string {
1297+ for _ , csv := range csvsInNamespace {
1298+ name := csv .GetName ()
1299+ if name == replaces {
1300+ rep := csv .Spec .Replaces
1301+ return & rep
1302+ }
1303+ }
1304+ return nil
1305+ }
1306+
1307+ next := replacement (current )
1308+ for next != nil {
1309+ csvsInChain [* next ] = struct {}{}
1310+ current = * next
1311+ next = replacement (current )
1312+ }
1313+
1314+ current = in .Spec .Replaces
1315+ prev := replaces (current )
1316+ if prev != nil {
1317+ csvsInChain [current ] = struct {}{}
1318+ }
1319+ for prev != nil && * prev != "" {
1320+ current = * prev
1321+ csvsInChain [current ] = struct {}{}
1322+ prev = replaces (current )
1323+ }
1324+ return csvsInChain
1325+ }
1326+
12521327func (a * Operator ) apiServiceOwnerConflicts (csv * v1alpha1.ClusterServiceVersion ) error {
12531328 // Get replacing CSV if exists
12541329 replacing , err := a .lister .OperatorsV1alpha1 ().ClusterServiceVersionLister ().ClusterServiceVersions (csv .GetNamespace ()).Get (csv .Spec .Replaces )
@@ -1297,7 +1372,9 @@ func (a *Operator) isReplacing(in *v1alpha1.ClusterServiceVersion) *v1alpha1.Clu
12971372 if in .Spec .Replaces == "" {
12981373 return nil
12991374 }
1300- previous , err := a .lister .OperatorsV1alpha1 ().ClusterServiceVersionLister ().ClusterServiceVersions (in .GetNamespace ()).Get (in .Spec .Replaces )
1375+
1376+ // using the client instead of a lister; missing an object because of a cache sync can cause upgrades to fail
1377+ previous , err := a .client .OperatorsV1alpha1 ().ClusterServiceVersions (in .GetNamespace ()).Get (in .Spec .Replaces , metav1.GetOptions {})
13011378 if err != nil {
13021379 a .Log .WithField ("replacing" , in .Spec .Replaces ).WithError (err ).Debugf ("unable to get previous csv" )
13031380 return nil
0 commit comments