Skip to content

Commit 61bfb2e

Browse files
authored
operator recovery logic (#782)
* operator recovery logic * update several logic * add warning msg
1 parent 6c6b9d7 commit 61bfb2e

File tree

2 files changed

+90
-32
lines changed

2 files changed

+90
-32
lines changed

controllers/constant/constant.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,7 @@ const (
7575

7676
//DefaultSubDeleteTimeout is the default timeout for deleting a subscription
7777
DefaultSubDeleteTimeout = 10 * time.Minute
78+
79+
//DefaultCSVWaitPeriod is the default period for wait CSV ready
80+
DefaultCSVWaitPeriod = 1 * time.Minute
7881
)

controllers/operatorchecker/operatorchecker_controller.go

Lines changed: 87 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -19,9 +19,9 @@ package operatorchecker
1919
import (
2020
"context"
2121
"strings"
22+
"time"
2223

2324
olmv1alpha1 "github.com/operator-framework/api/pkg/operators/v1alpha1"
24-
"k8s.io/apimachinery/pkg/types"
2525
"k8s.io/klog"
2626
ctrl "sigs.k8s.io/controller-runtime"
2727
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -37,54 +37,109 @@ type Reconciler struct {
3737

3838
// Reconcile watchs on the Subscription of the target namespace and apply the recovery to fixing the Subscription failed error
3939
func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (_ ctrl.Result, reconcileErr error) {
40-
// Fetch the subscription instance
41-
subscriptionInstance := &olmv1alpha1.Subscription{}
42-
if err := r.Client.Get(ctx, req.NamespacedName, subscriptionInstance); err != nil {
40+
subscriptionInstance, err := r.getSubscription(ctx, req)
41+
if err != nil {
4342
return ctrl.Result{}, client.IgnoreNotFound(err)
4443
}
4544

4645
klog.V(2).Info("Operator Checker is monitoring Subscription...")
4746

4847
if _, ok := subscriptionInstance.Labels[constant.OpreqLabel]; !ok {
49-
return
48+
return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil
5049
}
51-
if subscriptionInstance.Status.State != "" {
52-
return
53-
}
54-
for _, condition := range subscriptionInstance.Status.Conditions {
55-
if condition.Type == "ResolutionFailed" && condition.Reason == "ConstraintsNotSatisfiable" {
56-
csvList := &olmv1alpha1.ClusterServiceVersionList{}
57-
opts := []client.ListOption{
58-
client.InNamespace(subscriptionInstance.Namespace),
59-
}
60-
if err := r.Client.List(ctx, csvList, opts...); err != nil {
50+
51+
if subscriptionInstance.Status.CurrentCSV == "" && subscriptionInstance.Status.State == "" {
52+
// cover fresh install case
53+
csvList, err := r.getCSVBySubscription(ctx, subscriptionInstance)
54+
if err != nil {
55+
klog.Error(err)
56+
return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil
57+
}
58+
if len(csvList) != 1 {
59+
klog.Warning("Not found matched CSV, CSVList length: ", len(csvList))
60+
return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil
61+
}
62+
csv := csvList[0]
63+
64+
time.Sleep(constant.DefaultCSVWaitPeriod)
65+
subscriptionInstance, err := r.getSubscription(ctx, req)
66+
if err != nil {
67+
return ctrl.Result{}, client.IgnoreNotFound(err)
68+
}
69+
if subscriptionInstance.Status.CurrentCSV == "" && subscriptionInstance.Status.State == "" {
70+
if err = r.deleteCSV(ctx, csv.Name, csv.Namespace); err != nil {
6171
return ctrl.Result{}, client.IgnoreNotFound(err)
6272
}
73+
}
74+
}
75+
76+
if subscriptionInstance.Status.CurrentCSV != "" && subscriptionInstance.Status.State == "UpgradePending" {
77+
// cover upgrade case
78+
csvList, err := r.getCSVBySubscription(ctx, subscriptionInstance)
79+
if err != nil {
80+
klog.Error(err)
81+
return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil
82+
}
83+
if len(csvList) != 1 {
84+
klog.Warning("Not found matched CSV, CSVList length: ", len(csvList))
85+
return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil
86+
}
87+
csv := csvList[0]
6388

64-
for _, csv := range csvList.Items {
65-
if strings.Contains(csv.Name, subscriptionInstance.Name) {
66-
if csv.Status.Phase == "Succeeded" {
67-
csvInstance := &olmv1alpha1.ClusterServiceVersion{}
68-
csvKey := types.NamespacedName{
69-
Name: csv.Name,
70-
Namespace: csv.Namespace,
71-
}
72-
if err := r.Client.Get(ctx, csvKey, csvInstance); err != nil {
73-
return ctrl.Result{}, client.IgnoreNotFound(err)
74-
}
75-
if err := r.Client.Delete(ctx, csvInstance); err != nil {
76-
return ctrl.Result{}, client.IgnoreNotFound(err)
77-
}
78-
}
79-
break
89+
if subscriptionInstance.Status.CurrentCSV != csv.Spec.Version.String() {
90+
time.Sleep(constant.DefaultCSVWaitPeriod)
91+
subscriptionInstance, err := r.getSubscription(ctx, req)
92+
if err != nil {
93+
return ctrl.Result{}, client.IgnoreNotFound(err)
94+
}
95+
if subscriptionInstance.Status.CurrentCSV != "" && subscriptionInstance.Status.State == "UpgradePending" {
96+
if err = r.deleteCSV(ctx, csv.Name, csv.Namespace); err != nil {
97+
return ctrl.Result{}, client.IgnoreNotFound(err)
8098
}
8199
}
82-
break
83100
}
84101
}
102+
85103
return ctrl.Result{RequeueAfter: constant.DefaultRequeueDuration}, nil
86104
}
87105

106+
func (r *Reconciler) getCSVBySubscription(ctx context.Context, subscriptionInstance *olmv1alpha1.Subscription) ([]olmv1alpha1.ClusterServiceVersion, error) {
107+
csvList := &olmv1alpha1.ClusterServiceVersionList{}
108+
opts := []client.ListOption{
109+
client.InNamespace(subscriptionInstance.Namespace),
110+
}
111+
if err := r.Client.List(ctx, csvList, opts...); err != nil {
112+
return nil, client.IgnoreNotFound(err)
113+
}
114+
115+
var matchCSVList = []olmv1alpha1.ClusterServiceVersion{}
116+
for _, csv := range csvList.Items {
117+
if strings.Contains(csv.Name, subscriptionInstance.Name) {
118+
matchCSVList = append(matchCSVList, csv)
119+
}
120+
}
121+
return matchCSVList, nil
122+
}
123+
124+
func (r *Reconciler) getSubscription(ctx context.Context, req ctrl.Request) (*olmv1alpha1.Subscription, error) {
125+
// Fetch the subscription instance
126+
subscriptionInstance := &olmv1alpha1.Subscription{}
127+
if err := r.Client.Get(ctx, req.NamespacedName, subscriptionInstance); err != nil {
128+
return nil, err
129+
}
130+
return subscriptionInstance, nil
131+
}
132+
133+
func (r *Reconciler) deleteCSV(ctx context.Context, name, namespace string) error {
134+
csvInstance := &olmv1alpha1.ClusterServiceVersion{}
135+
csvInstance.Name = name
136+
csvInstance.Namespace = namespace
137+
if err := r.Client.Delete(ctx, csvInstance); err != nil {
138+
return client.IgnoreNotFound(err)
139+
}
140+
return nil
141+
}
142+
88143
// SetupWithManager adds subscription to watch to the manager.
89144
func (r *Reconciler) SetupWithManager(mgr ctrl.Manager) error {
90145
return ctrl.NewControllerManagedBy(mgr).

0 commit comments

Comments
 (0)