Skip to content

Commit 74afb99

Browse files
Merge pull request #1874 from openshift-cherrypick-robot/cherry-pick-1843-to-release-4.6
[release-4.6] Bug 1899747: Recreate pending installplan if deleted before approval
2 parents f754da6 + f8b564e commit 74afb99

File tree

4 files changed

+107
-9
lines changed

4 files changed

+107
-9
lines changed

pkg/controller/operators/catalog/operator.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -953,7 +953,7 @@ func (o *Operator) nothingToUpdate(logger *logrus.Entry, sub *v1alpha1.Subscript
953953
}
954954

955955
func (o *Operator) ensureSubscriptionInstallPlanState(logger *logrus.Entry, sub *v1alpha1.Subscription) (*v1alpha1.Subscription, bool, error) {
956-
if sub.Status.InstallPlanRef != nil {
956+
if sub.Status.InstallPlanRef != nil || sub.Status.Install != nil {
957957
return sub, false, nil
958958
}
959959

pkg/controller/operators/catalog/subscription/reconciler_test.go

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,63 @@ func TestInstallPlanReconcile(t *testing.T) {
11711171
}),
11721172
},
11731173
},
1174+
{
1175+
description: "SubscriptionExistsToInstallPlanNotFound/SubscriptionStateUpgradePending/Changes",
1176+
fields: fields{
1177+
config: &fakeReconcilerConfig{
1178+
now: nowFunc,
1179+
existingObjs: existingObjs{
1180+
clientObjs: []runtime.Object{
1181+
&v1alpha1.Subscription{
1182+
ObjectMeta: metav1.ObjectMeta{
1183+
Name: "sub",
1184+
Namespace: "ns",
1185+
},
1186+
Status: v1alpha1.SubscriptionStatus{
1187+
InstallPlanRef: &corev1.ObjectReference{
1188+
Namespace: "ns",
1189+
Name: "ip",
1190+
},
1191+
LastUpdated: earlier,
1192+
State: v1alpha1.SubscriptionStateUpgradePending,
1193+
},
1194+
},
1195+
},
1196+
},
1197+
},
1198+
},
1199+
args: args{
1200+
in: newSubscriptionExistsState(&v1alpha1.Subscription{
1201+
ObjectMeta: metav1.ObjectMeta{
1202+
Name: "sub",
1203+
Namespace: "ns",
1204+
},
1205+
Status: v1alpha1.SubscriptionStatus{
1206+
InstallPlanRef: &corev1.ObjectReference{
1207+
Namespace: "ns",
1208+
Name: "ip",
1209+
},
1210+
LastUpdated: earlier,
1211+
Conditions: []v1alpha1.SubscriptionCondition{
1212+
planPendingCondition(corev1.ConditionTrue, string(v1alpha1.InstallPlanPhaseInstalling), "", &earlier),
1213+
},
1214+
State: v1alpha1.SubscriptionStateUpgradePending,
1215+
},
1216+
}),
1217+
},
1218+
want: want{
1219+
out: newInstallPlanMissingState(&v1alpha1.Subscription{
1220+
ObjectMeta: metav1.ObjectMeta{
1221+
Name: "sub",
1222+
Namespace: "ns",
1223+
},
1224+
Status: v1alpha1.SubscriptionStatus{
1225+
LastUpdated: now,
1226+
State: v1alpha1.SubscriptionStateNone,
1227+
},
1228+
}),
1229+
},
1230+
},
11741231
{
11751232
description: "SubscriptionExistsToInstallPlanPending/Installing/Conditions/NoChanges",
11761233
fields: fields{

pkg/controller/operators/catalog/subscription/state.go

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -385,12 +385,22 @@ func (i *installPlanReferencedState) InstallPlanNotFound(now *metav1.Time, clien
385385
// Remove pending and failed conditions
386386
out.Status.RemoveConditions(v1alpha1.SubscriptionInstallPlanPending, v1alpha1.SubscriptionInstallPlanFailed)
387387

388-
// Set missing condition to true
389-
missingCond := out.Status.GetCondition(v1alpha1.SubscriptionInstallPlanMissing)
390-
missingCond.Status = corev1.ConditionTrue
391-
missingCond.Reason = v1alpha1.ReferencedInstallPlanNotFound
392-
missingCond.LastTransitionTime = now
393-
out.Status.SetCondition(missingCond)
388+
// If the installplan is missing when subscription is in pending upgrade,
389+
// clear the installplan ref so the resolution can happen again
390+
if in.Status.State == v1alpha1.SubscriptionStateUpgradePending {
391+
out.Status.InstallPlanRef = nil
392+
out.Status.Install = nil
393+
out.Status.CurrentCSV = ""
394+
out.Status.State = v1alpha1.SubscriptionStateNone
395+
out.Status.LastUpdated = *now
396+
} else {
397+
// Set missing condition to true
398+
cond := out.Status.GetCondition(v1alpha1.SubscriptionInstallPlanMissing)
399+
cond.Status = corev1.ConditionTrue
400+
cond.Reason = v1alpha1.ReferencedInstallPlanNotFound
401+
cond.LastTransitionTime = now
402+
out.Status.SetCondition(cond)
403+
}
394404

395405
// Build missing state
396406
missingState := &installPlanMissingState{

test/e2e/subscription_e2e_test.go

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,39 @@ var _ = Describe("Subscription", func() {
217217
require.Equal(GinkgoT(), v1alpha1.ApprovalManual, installPlan.Spec.Approval)
218218
require.Equal(GinkgoT(), v1alpha1.InstallPlanPhaseRequiresApproval, installPlan.Status.Phase)
219219

220-
installPlan.Spec.Approved = true
221-
_, err = crc.OperatorsV1alpha1().InstallPlans(testNamespace).Update(context.Background(), installPlan, metav1.UpdateOptions{})
220+
// Delete the current installplan
221+
err = crc.OperatorsV1alpha1().InstallPlans(testNamespace).Delete(context.Background(), installPlan.Name, metav1.DeleteOptions{})
222+
require.NoError(GinkgoT(), err)
223+
224+
var ipName string
225+
Eventually(func() bool {
226+
fetched, err := crc.OperatorsV1alpha1().Subscriptions(testNamespace).Get(context.TODO(), "manual-subscription", metav1.GetOptions{})
227+
if err != nil {
228+
return false
229+
}
230+
if fetched.Status.Install != nil {
231+
ipName = fetched.Status.Install.Name
232+
return fetched.Status.Install.Name != installPlan.Name
233+
}
234+
return false
235+
}, 5*time.Minute, 10*time.Second).Should(BeTrue())
236+
237+
// Fetch new installplan
238+
newInstallPlan, err := fetchInstallPlan(GinkgoT(), crc, ipName, buildInstallPlanPhaseCheckFunc(v1alpha1.InstallPlanPhaseRequiresApproval))
239+
require.NoError(GinkgoT(), err)
240+
require.NotNil(GinkgoT(), newInstallPlan)
241+
242+
require.NotEqual(GinkgoT(), installPlan.Name, newInstallPlan.Name, "expected new installplan recreated")
243+
require.Equal(GinkgoT(), v1alpha1.ApprovalManual, newInstallPlan.Spec.Approval)
244+
require.Equal(GinkgoT(), v1alpha1.InstallPlanPhaseRequiresApproval, newInstallPlan.Status.Phase)
245+
246+
// Set the InstallPlan's approved to True
247+
Eventually(Apply(newInstallPlan, func(p *v1alpha1.InstallPlan) error {
248+
p.Spec.Approved = true
249+
return nil
250+
})).Should(Succeed())
251+
252+
_, err = crc.OperatorsV1alpha1().InstallPlans(testNamespace).Update(context.Background(), newInstallPlan, metav1.UpdateOptions{})
222253
require.NoError(GinkgoT(), err)
223254

224255
subscription, err = fetchSubscription(crc, testNamespace, "manual-subscription", subscriptionStateAtLatestChecker)

0 commit comments

Comments
 (0)