Skip to content

Commit 8a89b44

Browse files
tmshortci-robot
authored andcommitted
Fix finalizer processing (#3180)
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 <[email protected]> Upstream-repository: operator-lifecycle-manager Upstream-commit: fc3c18363f6710da41cd003b9c4b41e826c4e244
1 parent b3bfaa4 commit 8a89b44

File tree

6 files changed

+228
-239
lines changed

6 files changed

+228
-239
lines changed

staging/operator-lifecycle-manager/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)

staging/operator-lifecycle-manager/pkg/controller/operators/olm/operator_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5832,6 +5832,9 @@ func RequireObjectsInCache(t *testing.T, lister operatorlister.OperatorLister, n
58325832
fetched, err = lister.RbacV1().RoleBindingLister().RoleBindings(namespace).Get(o.GetName())
58335833
case *v1alpha1.ClusterServiceVersion:
58345834
fetched, err = lister.OperatorsV1alpha1().ClusterServiceVersionLister().ClusterServiceVersions(namespace).Get(o.GetName())
5835+
// We don't care about finalizers
5836+
object.(*v1alpha1.ClusterServiceVersion).Finalizers = nil
5837+
fetched.(*v1alpha1.ClusterServiceVersion).Finalizers = nil
58355838
case *operatorsv1.OperatorGroup:
58365839
fetched, err = lister.OperatorsV1().OperatorGroupLister().OperatorGroups(namespace).Get(o.GetName())
58375840
default:
@@ -5885,6 +5888,8 @@ func CheckObjectsInNamespace(t *testing.T, opClient operatorclient.ClientInterfa
58855888
// and this will still check that the final state is correct
58865889
object.(*v1alpha1.ClusterServiceVersion).Status.Conditions = nil
58875890
fetched.(*v1alpha1.ClusterServiceVersion).Status.Conditions = nil
5891+
object.(*v1alpha1.ClusterServiceVersion).Finalizers = nil
5892+
fetched.(*v1alpha1.ClusterServiceVersion).Finalizers = nil
58885893
case *operatorsv1.OperatorGroup:
58895894
name = o.GetName()
58905895
fetched, err = client.OperatorsV1().OperatorGroups(namespace).Get(context.TODO(), o.GetName(), metav1.GetOptions{})

staging/operator-lifecycle-manager/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-
}

staging/operator-lifecycle-manager/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)