Skip to content

Commit aaed167

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 move the finalizer to the queueinformer reconciler and query the lister cache to see if the CSV has been deleted, and not do the RBAC updates if that's the case. Signed-off-by: Todd Short <todd.short@me.com>
1 parent 9f42a6f commit aaed167

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)