diff --git a/internal/provider/kubernetes/predicates.go b/internal/provider/kubernetes/predicates.go index 7b16dce317..e87dcb7815 100644 --- a/internal/provider/kubernetes/predicates.go +++ b/internal/provider/kubernetes/predicates.go @@ -726,7 +726,8 @@ func (r *gatewayAPIReconciler) envoyServiceForGateway(ctx context.Context, gatew return &services.Items[0], nil } -// findOwningGateway attempts finds a Gateway using "labels". +// findOwningGateway finds a Gateway using the provided labels. +// Returns the Gateway only if it belongs to this controller, or nil otherwise. func (r *gatewayAPIReconciler) findOwningGateway(ctx context.Context, labels map[string]string) *gwapiv1.Gateway { gwName, ok := labels[gatewayapi.OwningGatewayNameLabel] if !ok { @@ -745,6 +746,10 @@ func (r *gatewayAPIReconciler) findOwningGateway(ctx context.Context, labels map return nil } + if !r.validateGatewayForReconcile(gtw) { + return nil + } + return gtw } diff --git a/internal/provider/kubernetes/predicates_test.go b/internal/provider/kubernetes/predicates_test.go index 38208eeead..8157614d21 100644 --- a/internal/provider/kubernetes/predicates_test.go +++ b/internal/provider/kubernetes/predicates_test.go @@ -6,6 +6,7 @@ package kubernetes import ( + "context" "fmt" "os" "testing" @@ -177,6 +178,90 @@ func TestValidateGatewayForReconcile(t *testing.T) { } } +func TestFindOwningGateway(t *testing.T) { + controllerName := gwapiv1.GatewayController("example.com/foo") + otherControllerName := gwapiv1.GatewayController("example.com/bar") + + testCases := []struct { + name string + configs []client.Object + labels map[string]string + expect *gwapiv1.Gateway + }{ + { + name: "returns Gateway when it belongs to this controller", + configs: []client.Object{ + test.GetGatewayClass("test-gc", controllerName, nil), + test.GetGateway(types.NamespacedName{Namespace: "default", Name: "test-gw"}, "test-gc", 8080), + }, + labels: map[string]string{ + gatewayapi.OwningGatewayNameLabel: "test-gw", + gatewayapi.OwningGatewayNamespaceLabel: "default", + }, + expect: test.GetGateway(types.NamespacedName{Namespace: "default", Name: "test-gw"}, "test-gc", 8080), + }, + { + name: "returns nil when Gateway belongs to different controller", + configs: []client.Object{ + test.GetGatewayClass("test-gc", otherControllerName, nil), + test.GetGateway(types.NamespacedName{Namespace: "default", Name: "test-gw"}, "test-gc", 8080), + }, + labels: map[string]string{ + gatewayapi.OwningGatewayNameLabel: "test-gw", + gatewayapi.OwningGatewayNamespaceLabel: "default", + }, + expect: nil, + }, + { + name: "returns nil when Gateway name label is missing", + configs: []client.Object{}, + labels: map[string]string{ + gatewayapi.OwningGatewayNamespaceLabel: "default", + }, + expect: nil, + }, + { + name: "returns nil when Gateway namespace label is missing", + configs: []client.Object{}, + labels: map[string]string{ + gatewayapi.OwningGatewayNameLabel: "test-gw", + }, + expect: nil, + }, + { + name: "returns nil when Gateway does not exist", + configs: []client.Object{}, + labels: map[string]string{ + gatewayapi.OwningGatewayNameLabel: "non-existent", + gatewayapi.OwningGatewayNamespaceLabel: "default", + }, + expect: nil, + }, + } + + logger := logging.DefaultLogger(os.Stdout, egv1a1.LogLevelInfo) + + r := gatewayAPIReconciler{ + classController: controllerName, + log: logger, + } + + for _, tc := range testCases { + r.client = fakeclient.NewClientBuilder().WithScheme(envoygateway.GetScheme()).WithObjects(tc.configs...).Build() + t.Run(tc.name, func(t *testing.T) { + ctx := context.Background() + res := r.findOwningGateway(ctx, tc.labels) + if tc.expect == nil { + require.Nil(t, res) + } else { + require.NotNil(t, res) + require.Equal(t, tc.expect.Name, res.Name) + require.Equal(t, tc.expect.Namespace, res.Namespace) + } + }) + } +} + // TestValidateConfigMapForReconcile tests the validateConfigMapForReconcile // predicate function. func TestValidateConfigMapForReconcile(t *testing.T) {