Skip to content

Commit 029e16f

Browse files
sudiptob2jukie
authored andcommitted
findOwningGateway should return controller based on linked GatewayClass (envoyproxy#7611)
* fix: filter Gateway by controller in findOwningGateway Prevent cross-controller Gateway mutations by validating GatewayClass Signed-off-by: Sudipto Baral <[email protected]>
1 parent 5d1b92b commit 029e16f

File tree

2 files changed

+91
-1
lines changed

2 files changed

+91
-1
lines changed

internal/provider/kubernetes/predicates.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -738,7 +738,8 @@ func (r *gatewayAPIReconciler) envoyServiceForGateway(ctx context.Context, gatew
738738
return &services.Items[0], nil
739739
}
740740

741-
// findOwningGateway attempts finds a Gateway using "labels".
741+
// findOwningGateway finds a Gateway using the provided labels.
742+
// Returns the Gateway only if it belongs to this controller, or nil otherwise.
742743
func (r *gatewayAPIReconciler) findOwningGateway(ctx context.Context, labels map[string]string) *gwapiv1.Gateway {
743744
gwName, ok := labels[gatewayapi.OwningGatewayNameLabel]
744745
if !ok {
@@ -757,6 +758,10 @@ func (r *gatewayAPIReconciler) findOwningGateway(ctx context.Context, labels map
757758
return nil
758759
}
759760

761+
if !r.validateGatewayForReconcile(gtw) {
762+
return nil
763+
}
764+
760765
return gtw
761766
}
762767

internal/provider/kubernetes/predicates_test.go

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
package kubernetes
77

88
import (
9+
"context"
910
"fmt"
1011
"os"
1112
"testing"
@@ -177,6 +178,90 @@ func TestValidateGatewayForReconcile(t *testing.T) {
177178
}
178179
}
179180

181+
func TestFindOwningGateway(t *testing.T) {
182+
controllerName := gwapiv1.GatewayController("example.com/foo")
183+
otherControllerName := gwapiv1.GatewayController("example.com/bar")
184+
185+
testCases := []struct {
186+
name string
187+
configs []client.Object
188+
labels map[string]string
189+
expect *gwapiv1.Gateway
190+
}{
191+
{
192+
name: "returns Gateway when it belongs to this controller",
193+
configs: []client.Object{
194+
test.GetGatewayClass("test-gc", controllerName, nil),
195+
test.GetGateway(types.NamespacedName{Namespace: "default", Name: "test-gw"}, "test-gc", 8080),
196+
},
197+
labels: map[string]string{
198+
gatewayapi.OwningGatewayNameLabel: "test-gw",
199+
gatewayapi.OwningGatewayNamespaceLabel: "default",
200+
},
201+
expect: test.GetGateway(types.NamespacedName{Namespace: "default", Name: "test-gw"}, "test-gc", 8080),
202+
},
203+
{
204+
name: "returns nil when Gateway belongs to different controller",
205+
configs: []client.Object{
206+
test.GetGatewayClass("test-gc", otherControllerName, nil),
207+
test.GetGateway(types.NamespacedName{Namespace: "default", Name: "test-gw"}, "test-gc", 8080),
208+
},
209+
labels: map[string]string{
210+
gatewayapi.OwningGatewayNameLabel: "test-gw",
211+
gatewayapi.OwningGatewayNamespaceLabel: "default",
212+
},
213+
expect: nil,
214+
},
215+
{
216+
name: "returns nil when Gateway name label is missing",
217+
configs: []client.Object{},
218+
labels: map[string]string{
219+
gatewayapi.OwningGatewayNamespaceLabel: "default",
220+
},
221+
expect: nil,
222+
},
223+
{
224+
name: "returns nil when Gateway namespace label is missing",
225+
configs: []client.Object{},
226+
labels: map[string]string{
227+
gatewayapi.OwningGatewayNameLabel: "test-gw",
228+
},
229+
expect: nil,
230+
},
231+
{
232+
name: "returns nil when Gateway does not exist",
233+
configs: []client.Object{},
234+
labels: map[string]string{
235+
gatewayapi.OwningGatewayNameLabel: "non-existent",
236+
gatewayapi.OwningGatewayNamespaceLabel: "default",
237+
},
238+
expect: nil,
239+
},
240+
}
241+
242+
logger := logging.DefaultLogger(os.Stdout, egv1a1.LogLevelInfo)
243+
244+
r := gatewayAPIReconciler{
245+
classController: controllerName,
246+
log: logger,
247+
}
248+
249+
for _, tc := range testCases {
250+
r.client = fakeclient.NewClientBuilder().WithScheme(envoygateway.GetScheme()).WithObjects(tc.configs...).Build()
251+
t.Run(tc.name, func(t *testing.T) {
252+
ctx := context.Background()
253+
res := r.findOwningGateway(ctx, tc.labels)
254+
if tc.expect == nil {
255+
require.Nil(t, res)
256+
} else {
257+
require.NotNil(t, res)
258+
require.Equal(t, tc.expect.Name, res.Name)
259+
require.Equal(t, tc.expect.Namespace, res.Namespace)
260+
}
261+
})
262+
}
263+
}
264+
180265
// TestValidateConfigMapForReconcile tests the validateConfigMapForReconcile
181266
// predicate function.
182267
func TestValidateConfigMapForReconcile(t *testing.T) {

0 commit comments

Comments
 (0)