Skip to content

Commit d039748

Browse files
committed
refactor(operatorgroups): bail out after successful namespace update
- OperatorGroup sync bails out after successful namespace update detected - Check CSV status before re-transitioning to failed states due to OperatorGroup issues - Check CSV annotations before setting OperatorGroup annotations - Make OperatorGroup requeuing more aggressive on CSV deletion - Requeue OperatorGroup in OperatorGroup sync if CSV update fails and CSV still exists
1 parent e8b4b69 commit d039748

File tree

3 files changed

+109
-69
lines changed

3 files changed

+109
-69
lines changed

pkg/controller/operators/olm/operator.go

Lines changed: 52 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -346,6 +346,22 @@ func (a *Operator) handleClusterServiceVersionDeletion(obj interface{}) {
346346
defer func(csv v1alpha1.ClusterServiceVersion) {
347347
logger.Debug("removing csv from queue set")
348348
a.csvQueueSet.Remove(csv.GetName(), csv.GetNamespace())
349+
350+
// Requeue all OperatorGroups in the namespace
351+
logger.Debug("requeueing operatorgroups in namespace")
352+
operatorGroups, err := a.lister.OperatorsV1alpha2().OperatorGroupLister().OperatorGroups(csv.GetNamespace()).List(labels.Everything())
353+
if err != nil {
354+
logger.WithError(err).Warnf("an error occurred while listing operatorgroups to requeue after csv deletion")
355+
return
356+
}
357+
358+
for _, operatorGroup := range operatorGroups {
359+
logger := logger.WithField("operatorgroup", operatorGroup.GetName())
360+
logger.Debug("requeueing")
361+
if err := a.ogQueueSet.Requeue(operatorGroup.GetName(), operatorGroup.GetNamespace()); err != nil {
362+
logger.WithError(err).Debug("error requeueing operatorgroup")
363+
}
364+
}
349365
}(*clusterServiceVersion)
350366

351367
targetNamespaces, ok := clusterServiceVersion.Annotations[v1alpha2.OperatorGroupTargetsAnnotationKey]
@@ -360,28 +376,16 @@ func (a *Operator) handleClusterServiceVersionDeletion(obj interface{}) {
360376
return
361377
}
362378

363-
operatorGroupName, ok := clusterServiceVersion.Annotations[v1alpha2.OperatorGroupAnnotationKey]
364-
if !ok {
379+
if _, ok = clusterServiceVersion.Annotations[v1alpha2.OperatorGroupAnnotationKey]; !ok {
365380
logger.Debug("missing operatorgroup name annotation on csv")
366381
return
367382
}
368383

369-
if clusterServiceVersion.Status.Reason == v1alpha1.CSVReasonCopied {
384+
if clusterServiceVersion.IsCopied() {
370385
logger.Debug("deleted csv is copied. skipping additional cleanup steps")
371386
return
372387
}
373388

374-
logger = logger.WithField("operatorgroup", operatorGroupName)
375-
logger.Info("active csv deleted, removing providedAPIs from operatorgroup annotations")
376-
if operatorGroup, _ := a.lister.OperatorsV1alpha2().OperatorGroupLister().OperatorGroups(operatorNamespace).Get(operatorGroupName); operatorGroup != nil {
377-
logger.Debug("requeueing")
378-
if err := a.ogQueueSet.Requeue(operatorGroup.GetName(), operatorGroup.GetNamespace()); err != nil {
379-
logger.WithError(err).Debug("error requeueing")
380-
}
381-
} else {
382-
logger.Debug("operatorgroup not found during csv deletion")
383-
}
384-
385389
logger.Info("gcing children")
386390
namespaces := []string{}
387391
if targetNamespaces == "" {
@@ -524,7 +528,7 @@ func (a *Operator) operatorGroupForActiveCSV(logger *logrus.Entry, csv *v1alpha1
524528

525529
// No OperatorGroup annotation
526530
if !ok {
527-
logger.Info("no operatorgroup annotation")
531+
logger.Info("no olm.operatorGroup annotation")
528532
return nil
529533
}
530534

@@ -537,9 +541,17 @@ func (a *Operator) operatorGroupForActiveCSV(logger *logrus.Entry, csv *v1alpha1
537541
return nil
538542
}
539543

544+
targets, ok := annotations[v1alpha2.OperatorGroupTargetsAnnotationKey]
545+
546+
// No target annotation
547+
if !ok {
548+
logger.Info("no olm.targetNamespaces annotation")
549+
return nil
550+
}
551+
540552
// Target namespaces don't match
541-
if annotations[v1alpha2.OperatorGroupTargetsAnnotationKey] != strings.Join(operatorGroup.Status.Namespaces, ",") {
542-
logger.Info("target namespace annotation doesn't match operatorgroup namespace list")
553+
if targets != strings.Join(operatorGroup.Status.Namespaces, ",") {
554+
logger.Info("olm.targetNamespaces annotation doesn't match operatorgroup status")
543555
return nil
544556
}
545557

@@ -590,46 +602,54 @@ func (a *Operator) transitionCSVState(in v1alpha1.ClusterServiceVersion) (out *v
590602
operatorGroup = operatorGroups[0]
591603
logger = logger.WithField("opgroup", operatorGroup.GetName())
592604

593-
a.addOperatorGroupAnnotations(&out.ObjectMeta, operatorGroup, true)
594-
_, err = a.client.OperatorsV1alpha1().ClusterServiceVersions(out.GetNamespace()).Update(out)
595-
if err != nil {
596-
logger.Error("error adding operatorgroup annotation")
597-
syncError = err
605+
if a.operatorGroupAnnotationsDiffer(&out.ObjectMeta, operatorGroup) {
606+
a.setOperatorGroupAnnotations(&out.ObjectMeta, operatorGroup, true)
607+
if _, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(out.GetNamespace()).Update(out); err != nil {
608+
logger.WithError(err).Warn("error adding operatorgroup annotations")
609+
syncError = err
610+
}
598611
}
612+
599613
return
600614
}
601615
logger.Info("csv in operatorgroup")
602616
default:
603617
syncError = fmt.Errorf("csv created in namespace with multiple operatorgroups, can't pick one automatically")
604-
logger.Warn(syncError.Error())
605-
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonTooManyOperatorGroups, syncError.Error(), now, a.recorder)
618+
logger.WithError(syncError).Warn("csv failed to become an operatorgroup member")
619+
if out.Status.Reason != v1alpha1.CSVReasonTooManyOperatorGroups {
620+
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonTooManyOperatorGroups, syncError.Error(), now, a.recorder)
621+
}
606622
return
607623
}
608624

609625
modeSet, err := v1alpha1.NewInstallModeSet(out.Spec.InstallModes)
610626
if err != nil {
611627
syncError = err
612-
logger.Warn(err.Error())
613-
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidInstallModes, syncError.Error(), now, a.recorder)
628+
logger.WithError(err).Warn("csv has invalid installmodes")
629+
if out.Status.Reason != v1alpha1.CSVReasonInvalidInstallModes {
630+
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonInvalidInstallModes, syncError.Error(), now, a.recorder)
631+
}
614632
return
615633
}
616634

617635
// Check if the CSV supports its operatorgroup's selected namespaces
618636
targets, ok := out.GetAnnotations()[v1alpha2.OperatorGroupTargetsAnnotationKey]
619637
if ok {
620638
namespaces := strings.Split(targets, ",")
621-
err = modeSet.Supports(out.GetNamespace(), namespaces)
622-
if err != nil {
623-
logger.WithField("reason", err.Error()).Infof("InstallModeSet does not support OperatorGroup namespace selection")
639+
640+
if err := modeSet.Supports(out.GetNamespace(), namespaces); err != nil {
641+
logger.WithField("reason", err.Error()).Info("installmodeset does not support operatorgroups namespace selection")
624642
if out.Status.Reason != v1alpha1.CSVReasonUnsupportedOperatorGroup {
625643
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonUnsupportedOperatorGroup, err.Error(), now, a.recorder)
626644
}
627645
return
628646
}
629647
} else {
630-
// This should never be the case
631-
logger.Info("no targets annotation defined for CSV")
632-
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonNoTargetNamespaces, err.Error(), now, a.recorder)
648+
logger.Info("csv missing olm.targetNamespaces annotation")
649+
if out.Status.Reason != v1alpha1.CSVReasonNoTargetNamespaces {
650+
out.SetPhaseWithEvent(v1alpha1.CSVPhaseFailed, v1alpha1.CSVReasonNoTargetNamespaces, "csv missing olm.targetNamespaces annotation", now, a.recorder)
651+
}
652+
return
633653
}
634654

635655
// Check for intersecting provided APIs in intersecting OperatorGroups

pkg/controller/operators/olm/operator_test.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3576,6 +3576,10 @@ func TestSyncOperatorGroups(t *testing.T) {
35763576
}
35773577
}
35783578

3579+
// Sync again to catch provided API changes
3580+
err = op.syncOperatorGroups(tt.initial.operatorGroup)
3581+
require.NoError(t, err)
3582+
35793583
operatorGroup, err := op.GetClient().OperatorsV1alpha2().OperatorGroups(tt.initial.operatorGroup.GetNamespace()).Get(tt.initial.operatorGroup.GetName(), metav1.GetOptions{})
35803584
require.NoError(t, err)
35813585
assert.Equal(t, tt.expectedStatus, operatorGroup.Status)

pkg/controller/operators/olm/operatorgroup.go

Lines changed: 53 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -51,39 +51,55 @@ func (a *Operator) syncOperatorGroups(obj interface{}) error {
5151
"namespace": op.GetNamespace(),
5252
})
5353

54-
targetNamespaces, err := a.updateNamespaceList(op)
54+
targetNamespaces, err := a.getOperatorGroupTargets(op)
5555
if err != nil {
56-
logger.WithError(err).Warn("updateNamespaceList error")
56+
logger.WithError(err).Warn("issue getting operatorgroup target namespaces")
5757
return err
5858
}
59-
logger.WithField("targetNamespaces", targetNamespaces).Debug("updated target namespaces")
59+
60+
if namespacesChanged(targetNamespaces, op.Status.Namespaces) {
61+
// Update operatorgroup target namespace selection
62+
logger.WithField("targets", targetNamespaces).Debug("namespace change detected")
63+
op.Status = v1alpha2.OperatorGroupStatus{
64+
Namespaces: targetNamespaces,
65+
LastUpdated: timeNow(),
66+
}
67+
68+
if _, err = a.client.OperatorsV1alpha2().OperatorGroups(op.GetNamespace()).UpdateStatus(op); err != nil && !k8serrors.IsNotFound(err) {
69+
logger.WithError(err).Warn("operatorgroup update failed")
70+
return err
71+
}
72+
73+
// CSV requeue is handled by the succeeding sync
74+
return nil
75+
}
6076

6177
if err := a.ensureOpGroupClusterRoles(op); err != nil {
62-
a.Log.Errorf("ensureOpGroupClusterRoles error: %v", err)
78+
logger.WithError(err).Warn("failed to ensure operatorgroup clusterroles")
6379
return err
6480
}
65-
a.Log.Debug("cluster roles completed")
81+
logger.Debug("operatorgroup clusterroles ensured")
6682

6783
set := a.csvSet(op.Namespace, v1alpha1.CSVPhaseAny)
6884
providedAPIs := make(resolver.APISet)
6985
for _, csv := range set {
7086
logger := logger.WithField("csv", csv.GetName())
71-
origCSVannotations := csv.GetAnnotations()
72-
a.addOperatorGroupAnnotations(&csv.ObjectMeta, op, !csv.IsCopied())
73-
if !reflect.DeepEqual(origCSVannotations, csv.GetAnnotations()) {
74-
// CRDs don't support strategic merge patching, but in the future if they do this should be updated to patch
75-
if _, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).Update(csv); err != nil {
76-
// TODO: return an error and requeue the OperatorGroup here? Can this cause an update to never happen if there's resource contention?
77-
logger.WithError(err).Warnf("update to existing csv failed")
78-
continue
79-
}
80-
}
8187

82-
// Don't union providedAPIs if the CSV is copied (member of another OperatorGroup)
88+
// Don't stomp on copied CSVs
8389
if csv.IsCopied() {
84-
logger.Debug("csv is copied. not including in operatorgroup's provided api set")
90+
logger.Debug("csv is copied. not updating annotations or including in operatorgroup's provided api set")
8591
continue
8692
}
93+
94+
if a.operatorGroupAnnotationsDiffer(&csv.ObjectMeta, op) {
95+
a.setOperatorGroupAnnotations(&csv.ObjectMeta, op, true)
96+
// CRDs don't support strategic merge patching, but in the future if they do this should be updated to patch
97+
if _, err := a.client.OperatorsV1alpha1().ClusterServiceVersions(csv.GetNamespace()).Update(csv); err != nil && !k8serrors.IsNotFound(err) {
98+
// TODO: return an error and requeue the OperatorGroup here? Can this cause an update to never happen if there's resource contention?
99+
logger.WithError(err).Warnf("error adding operatorgroup annotations")
100+
return err
101+
}
102+
}
87103

88104
// TODO: Throw out CSVs that aren't members of the group due to group related failures?
89105

@@ -122,7 +138,7 @@ func (a *Operator) syncOperatorGroups(obj interface{}) error {
122138
logger.Debug("removing provided apis from annotation to match cluster state")
123139
if _, err := a.client.OperatorsV1alpha2().OperatorGroups(op.GetNamespace()).Update(op); err != nil && !k8serrors.IsNotFound(err) {
124140
logger.WithError(err).Warn("could not update provided api annotations")
125-
return nil
141+
return err
126142
}
127143
}
128144

@@ -502,14 +518,30 @@ func (a *Operator) copyCsvToTargetNamespace(csv *v1alpha1.ClusterServiceVersion,
502518
return nil
503519
}
504520

505-
func (a *Operator) addOperatorGroupAnnotations(obj *metav1.ObjectMeta, op *v1alpha2.OperatorGroup, addTargets bool) {
521+
func (a *Operator) setOperatorGroupAnnotations(obj *metav1.ObjectMeta, op *v1alpha2.OperatorGroup, addTargets bool) {
506522
metav1.SetMetaDataAnnotation(obj, v1alpha2.OperatorGroupNamespaceAnnotationKey, op.GetNamespace())
507523
metav1.SetMetaDataAnnotation(obj, v1alpha2.OperatorGroupAnnotationKey, op.GetName())
508-
if addTargets {
524+
525+
if addTargets && op.Status.Namespaces != nil {
509526
metav1.SetMetaDataAnnotation(obj, v1alpha2.OperatorGroupTargetsAnnotationKey, strings.Join(op.Status.Namespaces, ","))
510527
}
511528
}
512529

530+
func (a *Operator) operatorGroupAnnotationsDiffer(obj *metav1.ObjectMeta, op *v1alpha2.OperatorGroup) bool {
531+
annotations := obj.GetAnnotations()
532+
if operatorGroupNamespace, ok := annotations[v1alpha2.OperatorGroupNamespaceAnnotationKey]; !ok || operatorGroupNamespace != op.GetNamespace() {
533+
return true
534+
}
535+
if operatorGroup, ok := annotations[v1alpha2.OperatorGroupAnnotationKey]; !ok || operatorGroup != op.GetName() {
536+
return true
537+
}
538+
if targets, ok := annotations[v1alpha2.OperatorGroupTargetsAnnotationKey]; !ok || targets != strings.Join(op.Status.Namespaces, ",") {
539+
return true
540+
}
541+
542+
return false
543+
}
544+
513545
func namespacesChanged(clusterNamespaces []string, statusNamespaces []string) bool {
514546
if len(clusterNamespaces) != len(statusNamespaces) {
515547
return true
@@ -527,7 +559,7 @@ func namespacesChanged(clusterNamespaces []string, statusNamespaces []string) bo
527559
return false
528560
}
529561

530-
func (a *Operator) updateNamespaceList(op *v1alpha2.OperatorGroup) ([]string, error) {
562+
func (a *Operator) getOperatorGroupTargets(op *v1alpha2.OperatorGroup) ([]string, error) {
531563
selector, err := metav1.LabelSelectorAsSelector(&op.Spec.Selector)
532564
if err != nil {
533565
return nil, err
@@ -560,22 +592,6 @@ func (a *Operator) updateNamespaceList(op *v1alpha2.OperatorGroup) ([]string, er
560592
}
561593
sort.StringSlice(namespaceList).Sort()
562594

563-
if !namespacesChanged(namespaceList, op.Status.Namespaces) {
564-
// status is current with correct namespaces, so no further updates required
565-
return namespaceList, nil
566-
}
567-
568-
a.Log.Debugf("Namespace change detected, found: %v", namespaceList)
569-
op.Status = v1alpha2.OperatorGroupStatus{
570-
Namespaces: namespaceList,
571-
LastUpdated: timeNow(),
572-
}
573-
574-
_, err = a.client.OperatorsV1alpha2().OperatorGroups(op.GetNamespace()).UpdateStatus(op)
575-
if err != nil {
576-
return namespaceList, err
577-
}
578-
579595
return namespaceList, nil
580596
}
581597

0 commit comments

Comments
 (0)