Skip to content

Commit 127d7ed

Browse files
committed
Fix finalizer processing
There are two reconcilers for the CSV, one is controller-runtime based, the other is based on queueinformer. A finalizer was added to the CSV and it's handled by the controller-runtime reconciler. However, the queueinformer-based reconciler may take a while to do its processing such that the CSV may be deleted and the finalizer run via the controller-runtime reconciler. (This still takes <1s.) This causes problems when CSV being synced is deleted. The queueinformer attempts to sync RBAC to the stale CSV. The proper (BIG/risky) fix is to consolidate the two reconcilers. A less risky fix is to query the lister cache to see if the CSV has been deleted (or has a DeletionTimestamp), and not do the RBAC updates if that's the case. Signed-off-by: Todd Short <todd.short@me.com>
1 parent 9f42a6f commit 127d7ed

File tree

3 files changed

+112
-120
lines changed

3 files changed

+112
-120
lines changed

pkg/controller/operators/olm/operator.go

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ import (
3636
apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
3737
kagg "k8s.io/kube-aggregator/pkg/client/informers/externalversions"
3838
utilclock "k8s.io/utils/clock"
39+
"sigs.k8s.io/controller-runtime/pkg/client"
40+
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
3941

4042
operatorsv1 "github.com/operator-framework/api/pkg/operators/v1"
4143
"github.com/operator-framework/api/pkg/operators/v1alpha1"
@@ -1093,6 +1095,9 @@ func (a *Operator) handleClusterServiceVersionDeletion(obj interface{}) {
10931095
"phase": clusterServiceVersion.Status.Phase,
10941096
})
10951097

1098+
logger.Debug("start deleting CSV")
1099+
defer logger.Debug("end deleting CSV")
1100+
10961101
metrics.DeleteCSVMetric(clusterServiceVersion)
10971102

10981103
if clusterServiceVersion.IsCopied() {
@@ -1277,6 +1282,96 @@ func (a *Operator) deleteChild(csv *metav1.PartialObjectMetadata, logger *logrus
12771282
return a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).Delete(context.TODO(), csv.GetName(), metav1.DeleteOptions{})
12781283
}
12791284

1285+
// Return values, err, ok; ok == true: continue Reconcile, ok == false: exit Reconcile
1286+
func (a *Operator) processFinalizer(csv *v1alpha1.ClusterServiceVersion, log *logrus.Entry) (error, bool) {
1287+
myFinalizerName := "operators.coreos.com/csv-cleanup"
1288+
1289+
if csv.ObjectMeta.DeletionTimestamp.IsZero() {
1290+
// CSV is not being deleted, add finalizer if not present
1291+
if !controllerutil.ContainsFinalizer(csv, myFinalizerName) {
1292+
controllerutil.AddFinalizer(csv, myFinalizerName)
1293+
_, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).Update(a.ctx, csv, metav1.UpdateOptions{})
1294+
if err != nil {
1295+
log.WithError(err).Error("Adding finalizer")
1296+
return err, false
1297+
}
1298+
}
1299+
return nil, true
1300+
}
1301+
1302+
if !controllerutil.ContainsFinalizer(csv, myFinalizerName) {
1303+
// Finalizer has been removed; stop reconciliation as the CSV is being deleted
1304+
return nil, false
1305+
}
1306+
1307+
log.Info("started finalizer")
1308+
defer log.Info("completed finalizer")
1309+
1310+
// CSV is being deleted and the finalizer still present; do any clean up
1311+
ownerSelector := ownerutil.CSVOwnerSelector(csv)
1312+
listOptions := metav1.ListOptions{
1313+
LabelSelector: ownerSelector.String(),
1314+
}
1315+
deleteOptions := metav1.DeleteOptions{}
1316+
// Look for resources owned by this CSV, and delete them.
1317+
log.WithFields(logrus.Fields{"selector": ownerSelector}).Info("Cleaning up resources after CSV deletion")
1318+
var errs []error
1319+
1320+
err := a.opClient.KubernetesInterface().RbacV1().ClusterRoleBindings().DeleteCollection(a.ctx, deleteOptions, listOptions)
1321+
if client.IgnoreNotFound(err) != nil {
1322+
log.WithError(err).Error("Deleting ClusterRoleBindings on CSV delete")
1323+
errs = append(errs, err)
1324+
}
1325+
1326+
err = a.opClient.KubernetesInterface().RbacV1().ClusterRoles().DeleteCollection(a.ctx, deleteOptions, listOptions)
1327+
if client.IgnoreNotFound(err) != nil {
1328+
log.WithError(err).Error("Deleting ClusterRoles on CSV delete")
1329+
errs = append(errs, err)
1330+
}
1331+
err = a.opClient.KubernetesInterface().AdmissionregistrationV1().MutatingWebhookConfigurations().DeleteCollection(a.ctx, deleteOptions, listOptions)
1332+
if client.IgnoreNotFound(err) != nil {
1333+
log.WithError(err).Error("Deleting MutatingWebhookConfigurations on CSV delete")
1334+
errs = append(errs, err)
1335+
}
1336+
1337+
err = a.opClient.KubernetesInterface().AdmissionregistrationV1().ValidatingWebhookConfigurations().DeleteCollection(a.ctx, deleteOptions, listOptions)
1338+
if client.IgnoreNotFound(err) != nil {
1339+
log.WithError(err).Error("Deleting ValidatingWebhookConfigurations on CSV delete")
1340+
errs = append(errs, err)
1341+
}
1342+
1343+
// Make sure things are deleted
1344+
crbList, err := a.lister.RbacV1().ClusterRoleBindingLister().List(ownerSelector)
1345+
if err != nil {
1346+
errs = append(errs, err)
1347+
} else if len(crbList) != 0 {
1348+
errs = append(errs, fmt.Errorf("waiting for ClusterRoleBindings to delete"))
1349+
}
1350+
1351+
crList, err := a.lister.RbacV1().ClusterRoleLister().List(ownerSelector)
1352+
if err != nil {
1353+
errs = append(errs, err)
1354+
} else if len(crList) != 0 {
1355+
errs = append(errs, fmt.Errorf("waiting for ClusterRoles to delete"))
1356+
}
1357+
1358+
// Return any errors
1359+
if err := utilerrors.NewAggregate(errs); err != nil {
1360+
return err, false
1361+
}
1362+
1363+
// If no errors, remove our finalizer from the CSV and update
1364+
controllerutil.RemoveFinalizer(csv, myFinalizerName)
1365+
_, err = a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).Update(a.ctx, csv, metav1.UpdateOptions{})
1366+
if err != nil {
1367+
log.WithError(err).Error("Removing finalizer")
1368+
return err, false
1369+
}
1370+
1371+
// Stop reconciliation as the csv is being deleted
1372+
return nil, false
1373+
}
1374+
12801375
// syncClusterServiceVersion is the method that gets called when we see a CSV event in the cluster
12811376
func (a *Operator) syncClusterServiceVersion(obj interface{}) (syncError error) {
12821377
clusterServiceVersion, ok := obj.(*v1alpha1.ClusterServiceVersion)
@@ -1291,7 +1386,22 @@ func (a *Operator) syncClusterServiceVersion(obj interface{}) (syncError error)
12911386
"namespace": clusterServiceVersion.GetNamespace(),
12921387
"phase": clusterServiceVersion.Status.Phase,
12931388
})
1294-
logger.Debug("syncing CSV")
1389+
logger.Debug("start syncing CSV")
1390+
defer logger.Debug("end syncing CSV")
1391+
1392+
// get an up-to-date clusterServiceVersion from the cache
1393+
clusterServiceVersion, err := a.lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(clusterServiceVersion.GetNamespace()).Get(clusterServiceVersion.GetName())
1394+
if apierrors.IsNotFound(err) {
1395+
logger.Info("CSV has beeen deleted")
1396+
return nil
1397+
} else if err != nil {
1398+
logger.Info("Error getting latest version of CSV")
1399+
return err
1400+
}
1401+
1402+
if err, ok := a.processFinalizer(clusterServiceVersion, logger); !ok {
1403+
return err
1404+
}
12951405

12961406
if a.csvNotification != nil {
12971407
a.csvNotification.OnAddOrUpdate(clusterServiceVersion)

pkg/controller/operators/operatorconditiongenerator_controller.go

Lines changed: 0 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,15 @@ package operators
22

33
import (
44
"context"
5-
"fmt"
65
"reflect"
76

87
"github.com/go-logr/logr"
9-
admissionregistrationv1 "k8s.io/api/admissionregistration/v1"
10-
rbacv1 "k8s.io/api/rbac/v1"
118
apierrors "k8s.io/apimachinery/pkg/api/errors"
129
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1310
"k8s.io/apimachinery/pkg/runtime"
14-
utilerrors "k8s.io/apimachinery/pkg/util/errors"
1511
ctrl "sigs.k8s.io/controller-runtime"
1612
"sigs.k8s.io/controller-runtime/pkg/builder"
1713
"sigs.k8s.io/controller-runtime/pkg/client"
18-
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
1914
"sigs.k8s.io/controller-runtime/pkg/event"
2015
"sigs.k8s.io/controller-runtime/pkg/handler"
2116
"sigs.k8s.io/controller-runtime/pkg/predicate"
@@ -100,10 +95,6 @@ func (r *OperatorConditionGeneratorReconciler) Reconcile(ctx context.Context, re
10095
return ctrl.Result{}, client.IgnoreNotFound(err)
10196
}
10297

103-
if err, ok := r.processFinalizer(ctx, in); !ok {
104-
return ctrl.Result{}, err
105-
}
106-
10798
operatorCondition := &operatorsv2.OperatorCondition{
10899
ObjectMeta: metav1.ObjectMeta{
109100
// For now, only generate an OperatorCondition with the same name as the csv.
@@ -179,112 +170,3 @@ func (r *OperatorConditionGeneratorReconciler) ensureOperatorCondition(operatorC
179170
existingOperatorCondition.Spec.ServiceAccounts = operatorCondition.Spec.ServiceAccounts
180171
return r.Client.Update(context.TODO(), existingOperatorCondition)
181172
}
182-
183-
// Return values, err, ok; ok == true: continue Reconcile, ok == false: exit Reconcile
184-
func (r *OperatorConditionGeneratorReconciler) processFinalizer(ctx context.Context, csv *operatorsv1alpha1.ClusterServiceVersion) (error, bool) {
185-
myFinalizerName := "operators.coreos.com/csv-cleanup"
186-
log := r.log.WithValues("name", csv.GetName()).WithValues("namespace", csv.GetNamespace())
187-
188-
if csv.ObjectMeta.DeletionTimestamp.IsZero() {
189-
// CSV is not being deleted, add finalizer if not present
190-
if !controllerutil.ContainsFinalizer(csv, myFinalizerName) {
191-
patch := csv.DeepCopy()
192-
controllerutil.AddFinalizer(patch, myFinalizerName)
193-
if err := r.Client.Patch(ctx, patch, client.MergeFrom(csv)); err != nil {
194-
log.Error(err, "Adding finalizer")
195-
return err, false
196-
}
197-
}
198-
return nil, true
199-
}
200-
201-
if !controllerutil.ContainsFinalizer(csv, myFinalizerName) {
202-
// Finalizer has been removed; stop reconciliation as the CSV is being deleted
203-
return nil, false
204-
}
205-
206-
// CSV is being deleted and the finalizer still present; do any clean up
207-
ownerSelector := ownerutil.CSVOwnerSelector(csv)
208-
listOptions := client.ListOptions{
209-
LabelSelector: ownerSelector,
210-
}
211-
deleteOptions := client.DeleteAllOfOptions{
212-
ListOptions: listOptions,
213-
}
214-
// Look for resources owned by this CSV, and delete them.
215-
log.WithValues("selector", ownerSelector).Info("Cleaning up resources after CSV deletion")
216-
var errs []error
217-
218-
err := r.Client.DeleteAllOf(ctx, &rbacv1.ClusterRoleBinding{}, &deleteOptions)
219-
if client.IgnoreNotFound(err) != nil {
220-
log.Error(err, "Deleting ClusterRoleBindings on CSV delete")
221-
errs = append(errs, err)
222-
}
223-
224-
err = r.Client.DeleteAllOf(ctx, &rbacv1.ClusterRole{}, &deleteOptions)
225-
if client.IgnoreNotFound(err) != nil {
226-
log.Error(err, "Deleting ClusterRoles on CSV delete")
227-
errs = append(errs, err)
228-
}
229-
230-
err = r.Client.DeleteAllOf(ctx, &admissionregistrationv1.MutatingWebhookConfiguration{}, &deleteOptions)
231-
if client.IgnoreNotFound(err) != nil {
232-
log.Error(err, "Deleting MutatingWebhookConfigurations on CSV delete")
233-
errs = append(errs, err)
234-
}
235-
236-
err = r.Client.DeleteAllOf(ctx, &admissionregistrationv1.ValidatingWebhookConfiguration{}, &deleteOptions)
237-
if client.IgnoreNotFound(err) != nil {
238-
log.Error(err, "Deleting ValidatingWebhookConfigurations on CSV delete")
239-
errs = append(errs, err)
240-
}
241-
242-
// Make sure things are deleted
243-
crbList := &rbacv1.ClusterRoleBindingList{}
244-
err = r.Client.List(ctx, crbList, &listOptions)
245-
if err != nil {
246-
errs = append(errs, err)
247-
} else if len(crbList.Items) != 0 {
248-
errs = append(errs, fmt.Errorf("waiting for ClusterRoleBindings to delete"))
249-
}
250-
251-
crList := &rbacv1.ClusterRoleList{}
252-
err = r.Client.List(ctx, crList, &listOptions)
253-
if err != nil {
254-
errs = append(errs, err)
255-
} else if len(crList.Items) != 0 {
256-
errs = append(errs, fmt.Errorf("waiting for ClusterRoles to delete"))
257-
}
258-
259-
mwcList := &admissionregistrationv1.MutatingWebhookConfigurationList{}
260-
err = r.Client.List(ctx, mwcList, &listOptions)
261-
if err != nil {
262-
errs = append(errs, err)
263-
} else if len(mwcList.Items) != 0 {
264-
errs = append(errs, fmt.Errorf("waiting for MutatingWebhookConfigurations to delete"))
265-
}
266-
267-
vwcList := &admissionregistrationv1.ValidatingWebhookConfigurationList{}
268-
err = r.Client.List(ctx, vwcList, &listOptions)
269-
if err != nil {
270-
errs = append(errs, err)
271-
} else if len(vwcList.Items) != 0 {
272-
errs = append(errs, fmt.Errorf("waiting for ValidatingWebhookConfigurations to delete"))
273-
}
274-
275-
// Return any errors
276-
if err := utilerrors.NewAggregate(errs); err != nil {
277-
return err, false
278-
}
279-
280-
// If no errors, remove our finalizer from the CSV and update
281-
patch := csv.DeepCopy()
282-
controllerutil.RemoveFinalizer(patch, myFinalizerName)
283-
if err := r.Client.Patch(ctx, patch, client.MergeFrom(csv)); err != nil {
284-
log.Error(err, "Removing finalizer")
285-
return err, false
286-
}
287-
288-
// Stop reconciliation as the csv is being deleted
289-
return nil, false
290-
}

test/e2e/installplan_e2e_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2925,7 +2925,7 @@ var _ = Describe("Install Plan", func() {
29252925
}
29262926

29272927
return true
2928-
}, pollDuration*2, pollInterval).Should(BeTrue())
2928+
}, pollDuration, pollInterval).Should(BeTrue())
29292929
By("Cleaning up the test")
29302930
})
29312931

0 commit comments

Comments
 (0)