Skip to content

Commit f8bb912

Browse files
MUzairS15jukie
andauthored
feat: support urlrewrite filter for individual backends (#7826)
* feat: support urlrewrite filter for individual backends Signed-off-by: MUzairS15 <muzair.shaikh810@gmail.com> * update release notes Signed-off-by: MUzairS15 <muzair.shaikh810@gmail.com> --------- Signed-off-by: MUzairS15 <muzair.shaikh810@gmail.com> Signed-off-by: Isaac Wilson <10012479+jukie@users.noreply.github.com> Co-authored-by: Isaac Wilson <10012479+jukie@users.noreply.github.com>
1 parent fe57c70 commit f8bb912

14 files changed

+442
-4
lines changed

internal/gatewayapi/route.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2084,6 +2084,9 @@ func applyHTTPFiltersContextToDestinationFilters(httpFiltersContext *HTTPFilters
20842084
if httpFiltersContext.CredentialInjection != nil {
20852085
destFilters.CredentialInjection = httpFiltersContext.CredentialInjection
20862086
}
2087+
if httpFiltersContext.URLRewrite != nil {
2088+
destFilters.URLRewrite = httpFiltersContext.URLRewrite
2089+
}
20872090
}
20882091

20892092
func inspectAppProtocolByRouteKind(kind gwapiv1.Kind) ir.AppProtocol {
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
gateways:
2+
- apiVersion: gateway.networking.k8s.io/v1
3+
kind: Gateway
4+
metadata:
5+
namespace: envoy-gateway
6+
name: gateway-1
7+
spec:
8+
gatewayClassName: envoy-gateway-class
9+
listeners:
10+
- name: http
11+
protocol: HTTP
12+
port: 80
13+
allowedRoutes:
14+
namespaces:
15+
from: All
16+
httpRoutes:
17+
- apiVersion: gateway.networking.k8s.io/v1
18+
kind: HTTPRoute
19+
metadata:
20+
namespace: default
21+
name: httproute-1
22+
spec:
23+
parentRefs:
24+
- namespace: envoy-gateway
25+
name: gateway-1
26+
rules:
27+
- matches:
28+
- path:
29+
value: "/test"
30+
backendRefs:
31+
- name: service-1
32+
port: 8080
33+
weight: 50
34+
filters:
35+
- type: URLRewrite
36+
urlRewrite:
37+
hostname: "rewritten-host-a.example.com"
38+
- name: service-2
39+
port: 8080
40+
weight: 50
41+
filters:
42+
- type: URLRewrite
43+
urlRewrite:
44+
hostname: "rewritten-host-b.example.com"
45+
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
gateways:
2+
- apiVersion: gateway.networking.k8s.io/v1
3+
kind: Gateway
4+
metadata:
5+
name: gateway-1
6+
namespace: envoy-gateway
7+
spec:
8+
gatewayClassName: envoy-gateway-class
9+
listeners:
10+
- allowedRoutes:
11+
namespaces:
12+
from: All
13+
name: http
14+
port: 80
15+
protocol: HTTP
16+
status:
17+
listeners:
18+
- attachedRoutes: 1
19+
conditions:
20+
- lastTransitionTime: null
21+
message: Sending translated listener configuration to the data plane
22+
reason: Programmed
23+
status: "True"
24+
type: Programmed
25+
- lastTransitionTime: null
26+
message: Listener has been successfully translated
27+
reason: Accepted
28+
status: "True"
29+
type: Accepted
30+
- lastTransitionTime: null
31+
message: Listener references have been resolved
32+
reason: ResolvedRefs
33+
status: "True"
34+
type: ResolvedRefs
35+
name: http
36+
supportedKinds:
37+
- group: gateway.networking.k8s.io
38+
kind: HTTPRoute
39+
- group: gateway.networking.k8s.io
40+
kind: GRPCRoute
41+
httpRoutes:
42+
- apiVersion: gateway.networking.k8s.io/v1
43+
kind: HTTPRoute
44+
metadata:
45+
name: httproute-1
46+
namespace: default
47+
spec:
48+
parentRefs:
49+
- name: gateway-1
50+
namespace: envoy-gateway
51+
rules:
52+
- backendRefs:
53+
- filters:
54+
- type: URLRewrite
55+
urlRewrite:
56+
hostname: rewritten-host-a.example.com
57+
name: service-1
58+
port: 8080
59+
weight: 50
60+
- filters:
61+
- type: URLRewrite
62+
urlRewrite:
63+
hostname: rewritten-host-b.example.com
64+
name: service-2
65+
port: 8080
66+
weight: 50
67+
matches:
68+
- path:
69+
value: /test
70+
status:
71+
parents:
72+
- conditions:
73+
- lastTransitionTime: null
74+
message: Route is accepted
75+
reason: Accepted
76+
status: "True"
77+
type: Accepted
78+
- lastTransitionTime: null
79+
message: Resolved all the Object references for the Route
80+
reason: ResolvedRefs
81+
status: "True"
82+
type: ResolvedRefs
83+
controllerName: gateway.envoyproxy.io/gatewayclass-controller
84+
parentRef:
85+
name: gateway-1
86+
namespace: envoy-gateway
87+
infraIR:
88+
envoy-gateway/gateway-1:
89+
proxy:
90+
listeners:
91+
- address: null
92+
name: envoy-gateway/gateway-1/http
93+
ports:
94+
- containerPort: 10080
95+
name: http-80
96+
protocol: HTTP
97+
servicePort: 80
98+
metadata:
99+
labels:
100+
gateway.envoyproxy.io/owning-gateway-name: gateway-1
101+
gateway.envoyproxy.io/owning-gateway-namespace: envoy-gateway
102+
ownerReference:
103+
kind: GatewayClass
104+
name: envoy-gateway-class
105+
name: envoy-gateway/gateway-1
106+
namespace: envoy-gateway-system
107+
xdsIR:
108+
envoy-gateway/gateway-1:
109+
accessLog:
110+
json:
111+
- path: /dev/stdout
112+
globalResources:
113+
proxyServiceCluster:
114+
metadata:
115+
kind: Service
116+
name: envoy-envoy-gateway-gateway-1-196ae069
117+
namespace: envoy-gateway-system
118+
sectionName: "8080"
119+
name: envoy-gateway/gateway-1
120+
settings:
121+
- addressType: IP
122+
endpoints:
123+
- host: 7.6.5.4
124+
port: 8080
125+
zone: zone1
126+
metadata:
127+
kind: Service
128+
name: envoy-envoy-gateway-gateway-1-196ae069
129+
namespace: envoy-gateway-system
130+
sectionName: "8080"
131+
name: envoy-gateway/gateway-1
132+
protocol: TCP
133+
http:
134+
- address: 0.0.0.0
135+
externalPort: 80
136+
hostnames:
137+
- '*'
138+
isHTTP2: false
139+
metadata:
140+
kind: Gateway
141+
name: gateway-1
142+
namespace: envoy-gateway
143+
sectionName: http
144+
name: envoy-gateway/gateway-1/http
145+
path:
146+
escapedSlashesAction: UnescapeAndRedirect
147+
mergeSlashes: true
148+
port: 10080
149+
routes:
150+
- destination:
151+
metadata:
152+
kind: HTTPRoute
153+
name: httproute-1
154+
namespace: default
155+
name: httproute/default/httproute-1/rule/0
156+
settings:
157+
- addressType: IP
158+
endpoints:
159+
- host: 7.7.7.7
160+
port: 8080
161+
filters:
162+
urlRewrite:
163+
host:
164+
name: rewritten-host-a.example.com
165+
metadata:
166+
kind: Service
167+
name: service-1
168+
namespace: default
169+
sectionName: "8080"
170+
name: httproute/default/httproute-1/rule/0/backend/0
171+
protocol: HTTP
172+
weight: 50
173+
- addressType: IP
174+
endpoints:
175+
- host: 7.7.7.7
176+
port: 8080
177+
filters:
178+
urlRewrite:
179+
host:
180+
name: rewritten-host-b.example.com
181+
metadata:
182+
kind: Service
183+
name: service-2
184+
namespace: default
185+
sectionName: "8080"
186+
name: httproute/default/httproute-1/rule/0/backend/1
187+
protocol: HTTP
188+
weight: 50
189+
hostname: '*'
190+
isHTTP2: false
191+
metadata:
192+
kind: HTTPRoute
193+
name: httproute-1
194+
namespace: default
195+
name: httproute/default/httproute-1/rule/0/match/0/*
196+
pathMatch:
197+
distinct: false
198+
name: ""
199+
prefix: /test
200+
readyListener:
201+
address: 0.0.0.0
202+
ipFamily: IPv4
203+
path: /ready
204+
port: 19003

internal/gatewayapi/testdata/httproute-with-invalid-backend-ref-unsupported-filter.out.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ httpRoutes:
7272
type: Accepted
7373
- lastTransitionTime: null
7474
message: 'Failed to process route rule 0 backendRef 0: Specific filter is
75-
not supported within BackendRef, only RequestHeaderModifier, ResponseHeaderModifier
76-
and gateway.envoyproxy.io/HTTPRouteFilter are supported.'
75+
not supported within BackendRef, only RequestHeaderModifier, ResponseHeaderModifier,
76+
URLRewrite and gateway.envoyproxy.io/HTTPRouteFilter are supported.'
7777
reason: UnsupportedRefValue
7878
status: "False"
7979
type: ResolvedRefs

internal/gatewayapi/validate.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,8 @@ func (t *Translator) validateBackendRefFilters(backendRef BackendRefContext, rou
107107
}
108108
if filter.Type != gwapiv1.HTTPRouteFilterRequestHeaderModifier &&
109109
filter.Type != gwapiv1.HTTPRouteFilterResponseHeaderModifier &&
110-
filter.Type != gwapiv1.HTTPRouteFilterExtensionRef {
110+
filter.Type != gwapiv1.HTTPRouteFilterExtensionRef &&
111+
filter.Type != gwapiv1.HTTPRouteFilterURLRewrite {
111112
unsupportedFilters = true
112113
}
113114
}
@@ -123,7 +124,7 @@ func (t *Translator) validateBackendRefFilters(backendRef BackendRefContext, rou
123124
}
124125

125126
if unsupportedFilters {
126-
message := "Specific filter is not supported within BackendRef, only RequestHeaderModifier, ResponseHeaderModifier and gateway.envoyproxy.io/HTTPRouteFilter are supported"
127+
message := "Specific filter is not supported within BackendRef, only RequestHeaderModifier, ResponseHeaderModifier, URLRewrite and gateway.envoyproxy.io/HTTPRouteFilter are supported"
127128
if routeKind == resource.KindGRPCRoute {
128129
message = "Specific filter is not supported within BackendRef, only RequestHeaderModifier and ResponseHeaderModifier are supported"
129130
}

internal/ir/xds.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3306,6 +3306,8 @@ type DestinationFilters struct {
33063306
RemoveResponseHeaders []string `json:"removeResponseHeaders,omitempty" yaml:"removeResponseHeaders,omitempty"`
33073307
// CredentialInjection defines the credential injection configuration.
33083308
CredentialInjection *CredentialInjection `json:"credentialInjection,omitempty" yaml:"credentialInjection,omitempty"`
3309+
// URLRewrite defines the URL rewrite configuration for the backend.
3310+
URLRewrite *URLRewrite `json:"urlRewrite,omitempty" yaml:"urlRewrite,omitempty"`
33093311
}
33103312

33113313
// ResourceMetadata is metadata from the provider resource that is translated to an envoy resource

internal/ir/zz_generated.deepcopy.go

Lines changed: 5 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/xds/translator/route.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,14 @@ func buildXdsWeightedRouteAction(backendWeights *ir.BackendWeights, settings []*
348348
if len(destinationSetting.Filters.RemoveResponseHeaders) > 0 {
349349
validCluster.ResponseHeadersToRemove = append(validCluster.ResponseHeadersToRemove, destinationSetting.Filters.RemoveResponseHeaders...)
350350
}
351+
352+
if destinationSetting.Filters.URLRewrite != nil &&
353+
destinationSetting.Filters.URLRewrite.Host != nil &&
354+
destinationSetting.Filters.URLRewrite.Host.Name != nil {
355+
validCluster.HostRewriteSpecifier = &routev3.WeightedCluster_ClusterWeight_HostRewriteLiteral{
356+
HostRewriteLiteral: *destinationSetting.Filters.URLRewrite.Host.Name,
357+
}
358+
}
351359
}
352360

353361
weightedClusters = append(weightedClusters, validCluster)
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
http:
2+
- name: "first-listener"
3+
address: "::"
4+
hostnames:
5+
- '*'
6+
path:
7+
escapedSlashesAction: UnescapeAndRedirect
8+
mergeSlashes: true
9+
port: 10080
10+
routes:
11+
- destination:
12+
name: "url-rewrite-route-dest"
13+
settings:
14+
- addressType: IP
15+
endpoints:
16+
- host: 1.1.1.1
17+
port: 8080
18+
name: "url-rewrite-route-dest/backend/0"
19+
filters:
20+
urlRewrite:
21+
host:
22+
name: "backend-1.example.com"
23+
protocol: HTTP
24+
weight: 50
25+
- addressType: IP
26+
endpoints:
27+
- host: 2.2.2.2
28+
port: 8080
29+
name: "url-rewrite-route-dest/backend/1"
30+
filters:
31+
urlRewrite:
32+
host:
33+
name: "backend-2.example.com"
34+
protocol: HTTP
35+
weight: 50
36+
hostname: '*'
37+
name: "url-rewrite-route"
38+
pathMatch:
39+
prefix: /
40+

0 commit comments

Comments
 (0)