Skip to content

Commit af8de51

Browse files
dinhxuanvuopenshift-cherrypick-robot
authored andcommitted
fix(ip): Recreate pending installplan if deleted before approval
At the moment, OLM will not recreate the pending-approval installplan. The subscription will be stuck in UpgradePending forever as a result. This PR will enable installplan recreation if it is deleted before approval. Signed-off-by: Vu Dinh <[email protected]>
1 parent 33ff880 commit af8de51

File tree

2 files changed

+72
-6
lines changed

2 files changed

+72
-6
lines changed

pkg/controller/operators/catalog/operator.go

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,12 @@ func (o *Operator) syncResolvingNamespace(obj interface{}) error {
831831
return err
832832
}
833833

834+
ips, err := o.listInstallPlansMap(namespace)
835+
if err != nil {
836+
logger.WithError(err).Debug("couldn't list installplan")
837+
return err
838+
}
839+
834840
// TODO: parallel
835841
maxGeneration := 0
836842
subscriptionUpdated := false
@@ -847,7 +853,7 @@ func (o *Operator) syncResolvingNamespace(obj interface{}) error {
847853
}
848854

849855
// ensure the installplan reference is correct
850-
sub, changedIP, err := o.ensureSubscriptionInstallPlanState(logger, sub)
856+
sub, changedIP, err := o.ensureSubscriptionInstallPlanState(logger, sub, ips)
851857
if err != nil {
852858
logger.Debugf("error ensuring installplan state: %v", err)
853859
return err
@@ -952,9 +958,29 @@ func (o *Operator) nothingToUpdate(logger *logrus.Entry, sub *v1alpha1.Subscript
952958
return false
953959
}
954960

955-
func (o *Operator) ensureSubscriptionInstallPlanState(logger *logrus.Entry, sub *v1alpha1.Subscription) (*v1alpha1.Subscription, bool, error) {
956-
if sub.Status.InstallPlanRef != nil {
957-
return sub, false, nil
961+
// checkMissingInstallPlan checks if the installplan is missing or not when
962+
// the subscription is in pending upgrade state
963+
func (o *Operator) checkMissingInstallPlan(sub *v1alpha1.Subscription, ips map[string]struct{}) (*v1alpha1.Subscription, bool, error) {
964+
_, ok := ips[sub.Status.InstallPlanRef.Name]
965+
if !ok && sub.Status.State == v1alpha1.SubscriptionStateUpgradePending {
966+
out := sub.DeepCopy()
967+
out.Status.InstallPlanRef = nil
968+
out.Status.Install = nil
969+
out.Status.CurrentCSV = ""
970+
out.Status.State = v1alpha1.SubscriptionStateNone
971+
out.Status.LastUpdated = o.now()
972+
updated, err := o.client.OperatorsV1alpha1().Subscriptions(sub.GetNamespace()).UpdateStatus(context.TODO(), out, metav1.UpdateOptions{})
973+
if err != nil {
974+
return out, false, nil
975+
}
976+
return updated, true, nil
977+
}
978+
return sub, false, nil
979+
}
980+
981+
func (o *Operator) ensureSubscriptionInstallPlanState(logger *logrus.Entry, sub *v1alpha1.Subscription, ips map[string]struct{}) (*v1alpha1.Subscription, bool, error) {
982+
if sub.Status.InstallPlanRef != nil || sub.Status.Install != nil {
983+
return o.checkMissingInstallPlan(sub, ips)
958984
}
959985

960986
logger.Debug("checking for existing installplan")
@@ -2020,6 +2046,20 @@ func (o *Operator) listInstallPlans(namespace string) (ips []*v1alpha1.InstallPl
20202046
return
20212047
}
20222048

2049+
func (o *Operator) listInstallPlansMap(namespace string) (ips map[string]struct{}, err error) {
2050+
list, err := o.client.OperatorsV1alpha1().InstallPlans(namespace).List(context.TODO(), metav1.ListOptions{})
2051+
if err != nil {
2052+
return
2053+
}
2054+
2055+
ips = make(map[string]struct{})
2056+
for i := range list.Items {
2057+
ips[list.Items[i].GetName()] = struct{}{}
2058+
}
2059+
2060+
return
2061+
}
2062+
20232063
// competingCRDOwnersExist returns true if there exists a CSV that owns at least one of the given CSVs owned CRDs (that's not the given CSV)
20242064
func competingCRDOwnersExist(namespace string, csv *v1alpha1.ClusterServiceVersion, existingOwners map[string][]string) (bool, error) {
20252065
// Attempt to find a pre-existing owner in the namespace for any owned crd

test/e2e/subscription_e2e_test.go

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,8 +217,34 @@ 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+
newInstallPlan.Spec.Approved = true
247+
_, err = crc.OperatorsV1alpha1().InstallPlans(testNamespace).Update(context.Background(), newInstallPlan, metav1.UpdateOptions{})
222248
require.NoError(GinkgoT(), err)
223249

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

0 commit comments

Comments
 (0)