Skip to content

Commit 8ad1aa2

Browse files
authored
Merge pull request #95 from kgateway-dev/issue_59_14
agentgateway: target backend-protocol policy to service-upstream backends
2 parents 6295976 + c617f94 commit 8ad1aa2

5 files changed

Lines changed: 53 additions & 33 deletions

File tree

pkg/i2gw/emitters/agentgateway/README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,7 @@ The agentgateway emitter supports projecting upstream **connection timeout** beh
345345

346346
- `nginx.ingress.kubernetes.io/proxy-connect-timeout`
347347

348-
This is projected into a **Service-targeted** `AgentgatewayPolicy` by setting:
348+
This is projected into a backend-scoped `AgentgatewayPolicy` by setting:
349349

350350
- `AgentgatewayPolicy.spec.backend.tcp.connectTimeout`
351351

@@ -389,8 +389,12 @@ This is projected into a **Service-targeted** `AgentgatewayPolicy` by setting:
389389

390390
**Notes:**
391391

392-
- This feature is emitted as a **per-Service** `AgentgatewayPolicy` because backend HTTP protocol selection is
392+
- This feature is emitted as a **per-backend** `AgentgatewayPolicy` because backend HTTP protocol selection is
393393
backend-scoped.
394+
- Targeting behavior:
395+
- For normal Service backendRefs, the policy targets `group: ""`, `kind: Service`.
396+
- If `service-upstream` rewrites a backendRef to `group: agentgateway.dev`, `kind: AgentgatewayBackend`, the
397+
policy targets that `AgentgatewayBackend` instead.
394398
- This annotation does **not** cause ingress2gateway to emit a `GRPCRoute`. The generated route remains an
395399
`HTTPRoute`; the emitter uses `AgentgatewayPolicy.spec.backend.http.version: HTTP2` to express how agentgateway
396400
should communicate with the upstream backend.
@@ -439,8 +443,8 @@ Mappings:
439443

440444
- Rewrites only apply to core Service backendRefs (empty group and kind `Service` / unset kind).
441445
- If the provider could not determine an explicit backendRef port, that backendRef is skipped.
442-
- `backend-protocol` remains a Service-targeted `AgentgatewayPolicy` and continues to control upstream HTTP version
443-
(`spec.backend.http.version`) independently from `service-upstream`.
446+
- `backend-protocol` remains independently projected as `spec.backend.http.version`. For rewritten backendRefs,
447+
the policy targets the generated `AgentgatewayBackend`; otherwise it targets the original Service.
444448

445449
## AgentgatewayPolicy Projection
446450

@@ -468,9 +472,9 @@ Proxy connect timeout policies are created **per backend Service**:
468472
- `metadata.name: <service-name>-backend-connect-timeout`
469473
- `metadata.namespace: <route-namespace>`
470474

471-
Backend protocol policies are created **per backend Service**:
475+
Backend protocol policies are created **per targeted backend object**:
472476

473-
- `metadata.name: <service-name>-backend-http-version`
477+
- `metadata.name: <backend-name>-backend-http-version`
474478
- `metadata.namespace: <route-namespace>`
475479

476480
### Attachment Semantics

pkg/i2gw/emitters/agentgateway/backend_protocol.go

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ import (
2626
gwv1 "sigs.k8s.io/gateway-api/apis/v1"
2727
)
2828

29-
// applyBackendProtocolPolicy projects ingress-nginx backend-protocol into per-Service backend HTTP version policies.
29+
// applyBackendProtocolPolicy projects ingress-nginx backend-protocol into backend HTTP version policies.
3030
//
3131
// Current semantics:
3232
// - Only BackendProtocolGRPC is produced by the provider IR and maps to HTTP2.
33-
// - The policy is emitted per covered Service backend (same merge behavior as backend TLS/connect timeout).
33+
// - If a backendRef points to AgentgatewayBackend (e.g. service-upstream rewrite), target that backend.
34+
// - Otherwise, for core Service backendRefs, target the Service.
3435
func applyBackendProtocolPolicy(
3536
pol emitterir.Policy,
3637
httpRouteKey types.NamespacedName,
@@ -51,40 +52,48 @@ func applyBackendProtocolPolicy(
5152
}
5253

5354
br := rule.BackendRefs[idx.Backend]
54-
if br.BackendRef.Group != nil && *br.BackendRef.Group != "" {
55-
continue
56-
}
57-
if br.BackendRef.Kind != nil && *br.BackendRef.Kind != "Service" {
55+
refName := string(br.BackendRef.Name)
56+
if refName == "" {
5857
continue
5958
}
6059

61-
svcName := string(br.BackendRef.Name)
62-
if svcName == "" {
60+
targetGroup := gwv1.Group("")
61+
targetKind := gwv1.Kind("Service")
62+
63+
switch {
64+
case br.BackendRef.Group != nil && *br.BackendRef.Group == gwv1.Group(AgentgatewayBackendGVK.Group) &&
65+
br.BackendRef.Kind != nil && *br.BackendRef.Kind == gwv1.Kind(AgentgatewayBackendGVK.Kind):
66+
targetGroup = gwv1.Group(AgentgatewayBackendGVK.Group)
67+
targetKind = gwv1.Kind(AgentgatewayBackendGVK.Kind)
68+
case (br.BackendRef.Group == nil || *br.BackendRef.Group == "") &&
69+
(br.BackendRef.Kind == nil || *br.BackendRef.Kind == "Service"):
70+
// Default path: target core Service backends.
71+
default:
6372
continue
6473
}
6574

66-
svcKey := types.NamespacedName{Namespace: httpRouteKey.Namespace, Name: svcName}
67-
ap, exists := backendPolicies[svcKey]
75+
targetKey := types.NamespacedName{Namespace: httpRouteKey.Namespace, Name: refName}
76+
ap, exists := backendPolicies[targetKey]
6877
if !exists {
6978
ap = &agentgatewayv1alpha1.AgentgatewayPolicy{
7079
ObjectMeta: metav1.ObjectMeta{
71-
Name: svcName + "-backend-http-version",
80+
Name: refName + "-backend-http-version",
7281
Namespace: httpRouteKey.Namespace,
7382
},
7483
Spec: agentgatewayv1alpha1.AgentgatewayPolicySpec{
7584
TargetRefs: []shared.LocalPolicyTargetReferenceWithSectionName{
7685
{
7786
LocalPolicyTargetReference: shared.LocalPolicyTargetReference{
78-
Group: gwv1.Group(""),
79-
Kind: gwv1.Kind("Service"),
80-
Name: gwv1.ObjectName(svcName),
87+
Group: targetGroup,
88+
Kind: targetKind,
89+
Name: gwv1.ObjectName(refName),
8190
},
8291
},
8392
},
8493
},
8594
}
8695
ap.SetGroupVersionKind(AgentgatewayPolicyGVK)
87-
backendPolicies[svcKey] = ap
96+
backendPolicies[targetKey] = ap
8897
}
8998

9099
if ap.Spec.Backend == nil {

pkg/i2gw/emitters/agentgateway/emitter.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,14 +127,6 @@ func (e *Emitter) Emit(ir emitterir.EmitterIR) (i2gw.GatewayResources, field.Err
127127
backendPolicies,
128128
)
129129

130-
// backend-protocol maps to AgentgatewayPolicy.spec.backend.http.version, targeting Services.
131-
applyBackendProtocolPolicy(
132-
pol,
133-
httpRouteKey,
134-
httpRouteContext,
135-
backendPolicies,
136-
)
137-
138130
// rewrite-target maps to AgentgatewayPolicy.spec.traffic.transformation.
139131
// Note: agentgateway attaches policies at the HTTPRoute scope; this feature is only safe when
140132
// it fully covers the route (enforced by the full-coverage check below).
@@ -176,6 +168,16 @@ func (e *Emitter) Emit(ir emitterir.EmitterIR) (i2gw.GatewayResources, field.Err
176168
agentgatewayBackends,
177169
)
178170

171+
// backend-protocol maps to AgentgatewayPolicy.spec.backend.http.version.
172+
// If service-upstream rewrote backendRefs to AgentgatewayBackend, target those backends.
173+
// Otherwise, target core Services.
174+
applyBackendProtocolPolicy(
175+
pol,
176+
httpRouteKey,
177+
httpRouteContext,
178+
backendPolicies,
179+
)
180+
179181
// BasicAuth maps to AgentgatewayPolicy.spec.traffic.basicAuthentication.
180182
// Note: agentgateway expects htpasswd content under a '.htaccess' key; see BasicAuthentication docs.
181183
if applyBasicAuthPolicy(pol, polSourceIngressName, httpRouteKey.Namespace, agentgatewayPolicies) {

pkg/i2gw/emitters/agentgateway/testing/testdata/output/service_upstream.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,16 @@ status: {}
2727
apiVersion: agentgateway.dev/v1alpha1
2828
kind: AgentgatewayPolicy
2929
metadata:
30-
name: myserviceb-backend-http-version
30+
name: myserviceb-service-upstream-backend-http-version
3131
namespace: default
3232
spec:
3333
backend:
3434
http:
3535
version: HTTP2
3636
targetRefs:
37-
- group: ""
38-
kind: Service
39-
name: myserviceb
37+
- group: agentgateway.dev
38+
kind: AgentgatewayBackend
39+
name: myserviceb-service-upstream
4040
status:
4141
ancestors: null
4242
---

pkg/i2gw/providers/ingressnginx/README.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,11 @@ The ingress-nginx provider currently supports translating the following annotati
106106
- Otherwise, the Kgateway emitter does **not** generate Kubernetes `Service` resources. Instead, it emits an **INFO** notification with a `kubectl patch`
107107
command to set `spec.ports[].appProtocol` on the existing Service.
108108
- This annotation is treated as upstream protocol metadata and does not imply `GRPCRoute` projection.
109+
- For the Agentgateway implementation:
110+
- The emitter projects this as `AgentgatewayPolicy.spec.backend.http.version: HTTP2`.
111+
- For standard Service backendRefs, the policy targets the Service.
112+
- If `service-upstream: "true"` rewrites backendRefs to `AgentgatewayBackend`, the policy instead targets the generated
113+
`AgentgatewayBackend`.
109114
- **Values treated as default HTTP/1.x (no-op):** `HTTP`, `HTTPS`, `AUTO_HTTP`
110115
- **Unsupported values (rejected):** `FCGI` (and others)
111116
- **Safety note:** The provider does not attempt to create or mutate Kubernetes Services; implementation emitters decide how to safely project this intent.

0 commit comments

Comments
 (0)