Skip to content

Commit b2d1cd2

Browse files
Merge pull request #838 from ecordell/fix-dependent-subs
fix(resolver): fixes a bug where resolved dependent subscriptions don't
2 parents 0772e80 + 221819e commit b2d1cd2

17 files changed

+714
-166
lines changed

pkg/controller/operators/catalog/operator.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ func (o *Operator) nothingToUpdate(logger *logrus.Entry, sub *v1alpha1.Subscript
736736
}
737737

738738
func (o *Operator) ensureSubscriptionInstallPlanState(logger *logrus.Entry, sub *v1alpha1.Subscription) (*v1alpha1.Subscription, bool, error) {
739-
if sub.Status.Install != nil {
739+
if sub.Status.InstallPlanRef != nil {
740740
return sub, false, nil
741741
}
742742

@@ -765,6 +765,8 @@ func (o *Operator) ensureSubscriptionInstallPlanState(logger *logrus.Entry, sub
765765
out.Status.InstallPlanRef = ref
766766
out.Status.Install = v1alpha1.NewInstallPlanReference(ref)
767767
out.Status.State = v1alpha1.SubscriptionStateUpgradePending
768+
out.Status.CurrentCSV = out.Spec.StartingCSV
769+
out.Status.LastUpdated = timeNow()
768770

769771
updated, err := o.client.OperatorsV1alpha1().Subscriptions(sub.GetNamespace()).UpdateStatus(out)
770772
if err != nil {

pkg/controller/operators/catalog/operator_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -142,23 +142,23 @@ func TestExecutePlan(t *testing.T) {
142142
Resource: v1alpha1.StepResource{
143143
CatalogSource: "catalog",
144144
CatalogSourceNamespace: namespace,
145-
Group: "",
146-
Version: "v1",
147-
Kind: "Service",
148-
Name: "service",
149-
Manifest: toManifest(service("service", namespace)),
145+
Group: "",
146+
Version: "v1",
147+
Kind: "Service",
148+
Name: "service",
149+
Manifest: toManifest(service("service", namespace)),
150150
},
151151
Status: v1alpha1.StepStatusUnknown,
152152
},
153153
&v1alpha1.Step{
154154
Resource: v1alpha1.StepResource{
155155
CatalogSource: "catalog",
156156
CatalogSourceNamespace: namespace,
157-
Group: "operators.coreos.com",
158-
Version: "v1alpha1",
159-
Kind: "ClusterServiceVersion",
160-
Name: "csv",
161-
Manifest: toManifest(csv("csv", namespace, nil, nil)),
157+
Group: "operators.coreos.com",
158+
Version: "v1alpha1",
159+
Kind: "ClusterServiceVersion",
160+
Name: "csv",
161+
Manifest: toManifest(csv("csv", namespace, nil, nil)),
162162
},
163163
Status: v1alpha1.StepStatusUnknown,
164164
},

pkg/controller/operators/olm/operator.go

Lines changed: 94 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
12521327
func (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

Comments
 (0)