Skip to content

Commit f0d6d61

Browse files
authored
Merge pull request #4275 from shraddhabang/gwrulescrdfins
[feat: gw api] Add finalizers for Rules CRD
2 parents 7963004 + 0575c1c commit f0d6d61

File tree

8 files changed

+414
-261
lines changed

8 files changed

+414
-261
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package gateway
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"github.com/go-logr/logr"
7+
"k8s.io/client-go/tools/record"
8+
elbv2gw "sigs.k8s.io/aws-load-balancer-controller/apis/gateway/v1beta1"
9+
"sigs.k8s.io/aws-load-balancer-controller/pkg/config"
10+
"sigs.k8s.io/aws-load-balancer-controller/pkg/gateway/constants"
11+
"sigs.k8s.io/aws-load-balancer-controller/pkg/gateway/routeutils"
12+
"sigs.k8s.io/aws-load-balancer-controller/pkg/k8s"
13+
"sigs.k8s.io/aws-load-balancer-controller/pkg/runtime"
14+
"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
15+
ctrl "sigs.k8s.io/controller-runtime"
16+
"sigs.k8s.io/controller-runtime/pkg/client"
17+
"sigs.k8s.io/controller-runtime/pkg/controller"
18+
"sigs.k8s.io/controller-runtime/pkg/handler"
19+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
20+
"sigs.k8s.io/controller-runtime/pkg/source"
21+
)
22+
23+
// NewListenerRuleConfigurationReconciler constructs a reconciler that responds to listener rule configuration changes
24+
func NewListenerRuleConfigurationReconciler(k8sClient client.Client, eventRecorder record.EventRecorder, controllerConfig config.ControllerConfig, finalizerManager k8s.FinalizerManager, logger logr.Logger) Reconciler {
25+
26+
return &listenerRuleConfigurationReconciler{
27+
k8sClient: k8sClient,
28+
eventRecorder: eventRecorder,
29+
logger: logger,
30+
finalizerManager: finalizerManager,
31+
workers: controllerConfig.GatewayClassMaxConcurrentReconciles,
32+
}
33+
}
34+
35+
// listenerRuleConfigurationReconciler reconciles listener rule configurations
36+
type listenerRuleConfigurationReconciler struct {
37+
k8sClient client.Client
38+
logger logr.Logger
39+
eventRecorder record.EventRecorder
40+
finalizerManager k8s.FinalizerManager
41+
workers int
42+
}
43+
44+
func (r *listenerRuleConfigurationReconciler) SetupWatches(_ context.Context, ctrl controller.Controller, mgr ctrl.Manager) error {
45+
46+
if err := ctrl.Watch(source.Kind(mgr.GetCache(), &elbv2gw.ListenerRuleConfiguration{}, &handler.TypedEnqueueRequestForObject[*elbv2gw.ListenerRuleConfiguration]{})); err != nil {
47+
return err
48+
}
49+
50+
return nil
51+
}
52+
53+
func (r *listenerRuleConfigurationReconciler) Reconcile(ctx context.Context, req reconcile.Request) (ctrl.Result, error) {
54+
return runtime.HandleReconcileError(r.reconcile(ctx, req), r.logger)
55+
}
56+
57+
func (r *listenerRuleConfigurationReconciler) reconcile(ctx context.Context, req reconcile.Request) error {
58+
listenerRuleConf := &elbv2gw.ListenerRuleConfiguration{}
59+
if err := r.k8sClient.Get(ctx, req.NamespacedName, listenerRuleConf); err != nil {
60+
return client.IgnoreNotFound(err)
61+
}
62+
63+
r.logger.V(1).Info("Reconcile request for listener rule configuration", "cfg", listenerRuleConf)
64+
65+
if listenerRuleConf.DeletionTimestamp == nil || listenerRuleConf.DeletionTimestamp.IsZero() {
66+
return r.handleUpdate(listenerRuleConf)
67+
}
68+
69+
return r.handleDelete(listenerRuleConf)
70+
}
71+
72+
func (r *listenerRuleConfigurationReconciler) handleUpdate(listenerRuleConf *elbv2gw.ListenerRuleConfiguration) error {
73+
if k8s.HasFinalizer(listenerRuleConf, shared_constants.ListenerRuleConfigurationFinalizer) {
74+
return nil
75+
}
76+
return r.finalizerManager.AddFinalizers(context.Background(), listenerRuleConf, shared_constants.ListenerRuleConfigurationFinalizer)
77+
}
78+
79+
func (r *listenerRuleConfigurationReconciler) handleDelete(listenerRuleConf *elbv2gw.ListenerRuleConfiguration) error {
80+
if !k8s.HasFinalizer(listenerRuleConf, shared_constants.ListenerRuleConfigurationFinalizer) {
81+
return nil
82+
}
83+
84+
inUse, err := routeutils.IsListenerRuleConfigInUse(context.Background(), listenerRuleConf, r.k8sClient)
85+
86+
if err != nil {
87+
return fmt.Errorf("skipping finalizer removal due failure to verify if listener rule configuration [%+v] is in use. Error : %w ", k8s.NamespacedName(listenerRuleConf), err)
88+
}
89+
// if the listener rule configuration is still in use, we should not delete it
90+
if inUse {
91+
return fmt.Errorf("failed to remove finalizers as listener rule configuration [%+v] is still in use", k8s.NamespacedName(listenerRuleConf))
92+
}
93+
return r.finalizerManager.RemoveFinalizers(context.Background(), listenerRuleConf, shared_constants.ListenerRuleConfigurationFinalizer)
94+
}
95+
96+
func (r *listenerRuleConfigurationReconciler) SetupWithManager(_ context.Context, mgr ctrl.Manager) (controller.Controller, error) {
97+
return controller.New(constants.ListenerRuleConfigurationController, mgr, controller.Options{
98+
MaxConcurrentReconciles: r.workers,
99+
Reconciler: r,
100+
})
101+
102+
}

main.go

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ func main() {
319319

320320
targetGroupConfigurationReconciler := gateway.NewTargetGroupConfigurationReconciler(
321321
mgr.GetClient(),
322-
mgr.GetEventRecorderFor(gateway_constants.LoadBalancerConfigurationController),
322+
mgr.GetEventRecorderFor(gateway_constants.TargetGroupConfigurationController),
323323
controllerCFG,
324324
serviceReferenceCounter,
325325
finalizerManager,
@@ -338,6 +338,26 @@ func main() {
338338
os.Exit(1)
339339
}
340340

341+
listenerRuleConfigurationReconciler := gateway.NewListenerRuleConfigurationReconciler(
342+
mgr.GetClient(),
343+
mgr.GetEventRecorderFor(gateway_constants.ListenerRuleConfigurationController),
344+
controllerCFG,
345+
finalizerManager,
346+
mgr.GetLogger().WithName("listenerruleconfiguration-controller"),
347+
)
348+
349+
listenerRuleCfgController, err := listenerRuleConfigurationReconciler.SetupWithManager(ctx, mgr)
350+
if err != nil {
351+
setupLog.Error(err, "Unable to set up ListenerRuleConfiguration Manager")
352+
os.Exit(1)
353+
}
354+
355+
err = listenerRuleConfigurationReconciler.SetupWatches(ctx, listenerRuleCfgController, mgr)
356+
if err != nil {
357+
setupLog.Error(err, "Unable to set up ListenerRuleConfiguration Watches")
358+
os.Exit(1)
359+
}
360+
341361
go func() {
342362
setupLog.Info("starting gateway route reconciler")
343363
routeReconciler.Run()

pkg/gateway/constants/controller_constants.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,4 +63,7 @@ const (
6363

6464
//TargetGroupConfigurationController the controller that reconciles TargetGroupConfiguration changes
6565
TargetGroupConfigurationController = "aws-lbc-targetgroupconfiguration-controller"
66+
67+
//ListenerRuleConfigurationController the controller that reconciles ListenerRuleConfiguration changes
68+
ListenerRuleConfigurationController = "aws-lbc-listenerruleconfiguration-controller"
6669
)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package routeutils
2+
3+
import (
4+
"context"
5+
"k8s.io/apimachinery/pkg/types"
6+
elbv2gw "sigs.k8s.io/aws-load-balancer-controller/apis/gateway/v1beta1"
7+
"sigs.k8s.io/aws-load-balancer-controller/pkg/k8s"
8+
"sigs.k8s.io/controller-runtime/pkg/client"
9+
)
10+
11+
func IsListenerRuleConfigInUse(ctx context.Context, listenerRuleConfig *elbv2gw.ListenerRuleConfiguration, k8sClient client.Client) (bool, error) {
12+
l7Routes, err := ListL7Routes(ctx, k8sClient)
13+
if err != nil {
14+
return false, err
15+
}
16+
filteredRoutesByListenerRuleCfg := FilterRoutesByListenerRuleCfg(l7Routes, listenerRuleConfig)
17+
18+
return len(filteredRoutesByListenerRuleCfg) > 0, nil
19+
}
20+
21+
// FilterRoutesByListenerRuleCfg filters a slice of routes based on ListenerRuleConfiguration reference.
22+
// Returns a new slice containing only routes that reference the specified ListenerRuleConfiguration.
23+
func FilterRoutesByListenerRuleCfg(routes []preLoadRouteDescriptor, ruleConfig *elbv2gw.ListenerRuleConfiguration) []preLoadRouteDescriptor {
24+
if ruleConfig == nil || len(routes) == 0 {
25+
return []preLoadRouteDescriptor{}
26+
}
27+
filteredRoutes := make([]preLoadRouteDescriptor, 0, len(routes))
28+
for _, route := range routes {
29+
if isListenerRuleConfigReferredByRoute(route, k8s.NamespacedName(ruleConfig)) {
30+
filteredRoutes = append(filteredRoutes, route)
31+
}
32+
}
33+
return filteredRoutes
34+
}
35+
36+
// isListenerRuleConfigReferredByRoute checks if a route references a specific ruleConfig.
37+
func isListenerRuleConfigReferredByRoute(route preLoadRouteDescriptor, ruleConfig types.NamespacedName) bool {
38+
for _, config := range route.GetListenerRuleConfigs() {
39+
namespace := route.GetRouteNamespacedName().Namespace
40+
if string(config.Name) == ruleConfig.Name && namespace == ruleConfig.Namespace {
41+
return true
42+
}
43+
}
44+
return false
45+
}

0 commit comments

Comments
 (0)