Skip to content

Commit e3df1ff

Browse files
committed
fix(grpcserver): preserve projected gateway listeners
1 parent 90d2d21 commit e3df1ff

2 files changed

Lines changed: 46 additions & 1 deletion

File tree

internal/grpcserver/snapshot_projection.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func projectListeners(listeners []ir.Listener, snapshot *ir.Snapshot) []ir.Liste
157157
attachedRoutes = append(attachedRoutes, routeKey)
158158
}
159159
}
160-
if len(attachedRoutes) == 0 {
160+
if len(attachedRoutes) == 0 && !isGatewayProjectedListener(listener) {
161161
continue
162162
}
163163
listener.AttachedRoutes = attachedRoutes
@@ -166,6 +166,13 @@ func projectListeners(listeners []ir.Listener, snapshot *ir.Snapshot) []ir.Liste
166166
return out
167167
}
168168

169+
func isGatewayProjectedListener(listener ir.Listener) bool {
170+
if listener.Metadata == nil {
171+
return false
172+
}
173+
return listener.Metadata["gateway"] != "" && listener.Metadata["namespace"] != ""
174+
}
175+
169176
func filterBackendRefs(routeNamespace string, refs []ir.BackendRef, survivingBackends map[string]struct{}) []ir.BackendRef {
170177
out := make([]ir.BackendRef, 0, len(refs))
171178
for _, ref := range refs {

internal/grpcserver/snapshot_projection_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,44 @@ func TestProjectedSnapshotFullProfilePreservesAIServiceTokenPolicyWasmAndLabels(
135135
}
136136
}
137137

138+
func TestProjectedSnapshotPreservesListenerWhenAllAttachedRoutesArePruned(t *testing.T) {
139+
t.Parallel()
140+
141+
projected := buildProjectedProtoSnapshot(
142+
&ir.Snapshot{
143+
Listeners: []ir.Listener{{
144+
Name: "listener-empty-after-projection",
145+
Address: "0.0.0.0",
146+
Port: 80,
147+
Protocol: "HTTP",
148+
AttachedRoutes: []string{"default/http-missing"},
149+
Metadata: map[string]string{
150+
"gateway": "edge",
151+
"namespace": "default",
152+
},
153+
}},
154+
HTTPRoutes: []ir.HTTPRoute{{
155+
Name: "http-missing",
156+
Namespace: "default",
157+
Rules: []ir.HTTPRule{{
158+
BackendRefs: []ir.BackendRef{{
159+
Name: "missing-backend",
160+
Namespace: "default",
161+
Port: 8080,
162+
}},
163+
}},
164+
}},
165+
},
166+
effectiveProjectionProfile([]string{featureCoreV1}),
167+
slog.New(slog.NewTextHandler(io.Discard, nil)),
168+
)
169+
170+
listener := findProjectedListener(t, projected, "listener-empty-after-projection")
171+
if got := listener.GetAttachedRoutes(); len(got) != 0 {
172+
t.Fatalf("attached routes = %#v, want empty list", got)
173+
}
174+
}
175+
138176
func projectionTestSnapshot() *ir.Snapshot {
139177
return &ir.Snapshot{
140178
ID: "projection-snapshot",

0 commit comments

Comments
 (0)