Skip to content

Commit 82d119f

Browse files
committed
gatewayclass: Reconcile the oldest gatewayclass
When reconciling gatewayclasses in order to ensure the Istio CR, make sure to use the oldest gatewayclass that has our controller name. Before this commit, the controller behaved inconsistently: - The controller's watch on gatewayclasses reconciled the specific gatewayclass that triggered the watch. - The controller's watches on subscriptions, installplans, and istios reconciled the "openshift-default" gatewayclass. This inconsistency caused several problems: - If a gatewayclass existed with our controller name but none existed with the name "openshift-default", the controller logged spurious reconcile requests for, and failures to get, the "openshift-default" gatewayclass. - If multiple gatewayclasses existed with our controller name, the controller tried to update the owner reference on the Istio CR every time the controller reconciled a gatewayclass other than the one in the owner reference. Using the oldest gatewayclass solves these problems. * pkg/operator/controller/gatewayclass/controller.go (enqueueRequestForDefaultGatewayClassController): Rename... (enqueueRequestForSomeGatewayClass): ...to this. Delete the unused namespace parameter. Look up the oldest gatewayclass with our controller name, and return a reconcile request for that gatewayclass. (NewUnmanaged, Reconcile): Use enqueueRequestForSomeGatewayClass for all watches.
1 parent c8edf73 commit 82d119f

File tree

1 file changed

+43
-11
lines changed

1 file changed

+43
-11
lines changed

pkg/operator/controller/gatewayclass/controller.go

Lines changed: 43 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515

1616
gatewayapiv1 "sigs.k8s.io/gateway-api/apis/v1"
1717

18+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1819
"k8s.io/apimachinery/pkg/types"
1920
utilerrors "k8s.io/apimachinery/pkg/util/errors"
2021

@@ -57,15 +58,15 @@ func NewUnmanaged(mgr manager.Manager, config Config) (controller.Controller, er
5758
notIstioGatewayClass := predicate.NewPredicateFuncs(func(o client.Object) bool {
5859
return o.GetName() != "istio"
5960
})
60-
if err := c.Watch(source.Kind[client.Object](operatorCache, &gatewayapiv1.GatewayClass{}, &handler.EnqueueRequestForObject{}, isOurGatewayClass, notIstioGatewayClass)); err != nil {
61+
if err := c.Watch(source.Kind[client.Object](operatorCache, &gatewayapiv1.GatewayClass{}, reconciler.enqueueRequestForSomeGatewayClass(), isOurGatewayClass, notIstioGatewayClass)); err != nil {
6162
return nil, err
6263
}
6364

6465
isServiceMeshSubscription := predicate.NewPredicateFuncs(func(o client.Object) bool {
6566
return o.GetName() == operatorcontroller.ServiceMeshOperatorSubscriptionName().Name
6667
})
6768
if err = c.Watch(source.Kind[client.Object](operatorCache, &operatorsv1alpha1.Subscription{},
68-
enqueueRequestForDefaultGatewayClassController(config.OperandNamespace), isServiceMeshSubscription)); err != nil {
69+
reconciler.enqueueRequestForSomeGatewayClass(), isServiceMeshSubscription)); err != nil {
6970
return nil, err
7071
}
7172

@@ -86,7 +87,7 @@ func NewUnmanaged(mgr manager.Manager, config Config) (controller.Controller, er
8687
installPlan := o.(*operatorsv1alpha1.InstallPlan)
8788
return installPlan.Spec.Approved
8889
})
89-
if err := c.Watch(source.Kind[client.Object](operatorCache, &operatorsv1alpha1.InstallPlan{}, enqueueRequestForDefaultGatewayClassController(config.OperatorNamespace), isOurInstallPlan, predicate.Not(isInstallPlanApproved))); err != nil {
90+
if err := c.Watch(source.Kind[client.Object](operatorCache, &operatorsv1alpha1.InstallPlan{}, reconciler.enqueueRequestForSomeGatewayClass(), isOurInstallPlan, predicate.Not(isInstallPlanApproved))); err != nil {
9091
return nil, err
9192
}
9293

@@ -119,17 +120,48 @@ type reconciler struct {
119120
startIstioWatch sync.Once
120121
}
121122

122-
func enqueueRequestForDefaultGatewayClassController(namespace string) handler.EventHandler {
123+
// enqueueRequestForSomeGatewayClass enqueues a reconciliation request for the
124+
// gatewayclass that has the earliest creation timestamp and that specifies our
125+
// controller name.
126+
func (r *reconciler) enqueueRequestForSomeGatewayClass() handler.EventHandler {
123127
return handler.EnqueueRequestsFromMapFunc(
124-
func(ctx context.Context, a client.Object) []reconcile.Request {
125-
return []reconcile.Request{
126-
{
128+
func(ctx context.Context, _ client.Object) []reconcile.Request {
129+
requests := []reconcile.Request{}
130+
131+
var gatewayClasses gatewayapiv1.GatewayClassList
132+
if err := r.cache.List(context.Background(), &gatewayClasses); err != nil {
133+
log.Error(err, "Failed to list gatewayclasses")
134+
135+
return requests
136+
}
137+
138+
var (
139+
found bool
140+
oldest metav1.Time
141+
name string
142+
)
143+
for i := range gatewayClasses.Items {
144+
if gatewayClasses.Items[i].Spec.ControllerName != operatorcontroller.OpenShiftGatewayClassControllerName {
145+
continue
146+
}
147+
148+
ctime := gatewayClasses.Items[i].CreationTimestamp
149+
if !found || ctime.Before(&oldest) {
150+
found, oldest, name = true, ctime, gatewayClasses.Items[i].Name
151+
}
152+
}
153+
154+
if found {
155+
request := reconcile.Request{
127156
NamespacedName: types.NamespacedName{
128-
Namespace: namespace,
129-
Name: operatorcontroller.OpenShiftDefaultGatewayClassName,
157+
Namespace: "", // GatewayClass is cluster-scoped.
158+
Name: name,
130159
},
131-
},
160+
}
161+
requests = append(requests, request)
132162
}
163+
164+
return requests
133165
},
134166
)
135167
}
@@ -162,7 +194,7 @@ func (r *reconciler) Reconcile(ctx context.Context, request reconcile.Request) (
162194
isOurIstio := predicate.NewPredicateFuncs(func(o client.Object) bool {
163195
return o.GetName() == operatorcontroller.IstioName(r.config.OperandNamespace).Name
164196
})
165-
if err = gatewayClassController.Watch(source.Kind[client.Object](r.cache, &sailv1.Istio{}, enqueueRequestForDefaultGatewayClassController(r.config.OperandNamespace), isOurIstio)); err != nil {
197+
if err = gatewayClassController.Watch(source.Kind[client.Object](r.cache, &sailv1.Istio{}, r.enqueueRequestForSomeGatewayClass(), isOurIstio)); err != nil {
166198
log.Error(err, "failed to watch istios.sailoperator.io", "request", request)
167199
errs = append(errs, err)
168200
}

0 commit comments

Comments
 (0)