Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support GEP-1731 #5024

Merged
merged 5 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 47 additions & 7 deletions internal/gatewayapi/route.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,11 @@ func (t *Translator) processHTTPRouteRules(httpRoute *HTTPRouteContext, parentRe
return routeRoutes, nil
}

func processRouteTrafficFeatures(irRoute *ir.HTTPRoute, rule gwapiv1.HTTPRouteRule) {
processRouteTimeout(irRoute, rule)
processRouteRetry(irRoute, rule)
}

func processRouteTimeout(irRoute *ir.HTTPRoute, rule gwapiv1.HTTPRouteRule) {
if rule.Timeouts != nil {
if rule.Timeouts.Request != nil {
Expand All @@ -293,6 +298,45 @@ func processRouteTimeout(irRoute *ir.HTTPRoute, rule gwapiv1.HTTPRouteRule) {
}
}

func processRouteRetry(irRoute *ir.HTTPRoute, rule gwapiv1.HTTPRouteRule) {
if rule.Retry == nil {
return
}

retry := rule.Retry
res := &ir.Retry{}
if retry.Attempts != nil {
res.NumRetries = ptr.To(uint32(*retry.Attempts))
}
if retry.Backoff != nil {
backoff, err := time.ParseDuration(string(*retry.Backoff))
if err == nil {
res.PerRetry = &ir.PerRetryPolicy{
BackOff: &ir.BackOffPolicy{
BaseInterval: ptr.To(metav1.Duration{Duration: backoff}),
},
}
// xref: https://gateway-api.sigs.k8s.io/geps/gep-1742/#timeout-values
if rule.Timeouts != nil && rule.Timeouts.BackendRequest != nil {
backendRequestTimeout, err := time.ParseDuration(string(*rule.Timeouts.BackendRequest))
if err == nil {
res.PerRetry.Timeout = &metav1.Duration{Duration: backendRequestTimeout}
}
}
}
zirain marked this conversation as resolved.
Show resolved Hide resolved
}
if len(retry.Codes) > 0 {
codes := make([]ir.HTTPStatus, 0, len(retry.Codes))
for _, code := range retry.Codes {
codes = append(codes, ir.HTTPStatus(code))
}
res.RetryOn = &ir.RetryOn{
HTTPStatusCodes: codes,
}
}
irRoute.Retry = res
}

func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx int, httpFiltersContext *HTTPFiltersContext, rule gwapiv1.HTTPRouteRule) ([]*ir.HTTPRoute, error) {
var ruleRoutes []*ir.HTTPRoute

Expand All @@ -302,7 +346,7 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i
Name: irRouteName(httpRoute, ruleIdx, -1),
}
irRoute.Metadata = buildRouteMetadata(httpRoute, rule.Name)
processRouteTimeout(irRoute, rule)
processRouteTrafficFeatures(irRoute, rule)
applyHTTPFiltersContextToIRRoute(httpFiltersContext, irRoute)
ruleRoutes = append(ruleRoutes, irRoute)
}
Expand Down Expand Up @@ -363,7 +407,7 @@ func (t *Translator) processHTTPRouteRule(httpRoute *HTTPRouteContext, ruleIdx i
SessionPersistence: sessionPersistence,
}
irRoute.Metadata = buildRouteMetadata(httpRoute, rule.Name)
processRouteTimeout(irRoute, rule)
processRouteTrafficFeatures(irRoute, rule)

if match.Path != nil {
switch PathMatchTypeDerefOr(match.Path.Type, gwapiv1.PathMatchPathPrefix) {
Expand Down Expand Up @@ -751,11 +795,7 @@ func (t *Translator) processHTTPRouteParentRefListener(route RouteContext, route
IsHTTP2: routeRoute.IsHTTP2,
SessionPersistence: routeRoute.SessionPersistence,
Timeout: routeRoute.Timeout,
}
if routeRoute.Traffic != nil {
hostRoute.Traffic = &ir.TrafficFeatures{
Retry: routeRoute.Traffic.Retry,
}
Retry: routeRoute.Retry,
}
perHostRoutes = append(perHostRoutes, hostRoute)
}
Expand Down
100 changes: 100 additions & 0 deletions internal/gatewayapi/testdata/httproute-retry.in.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
gateways:
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-1
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
- apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
namespace: envoy-gateway
name: gateway-2
spec:
gatewayClassName: envoy-gateway-class
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
httpRoutes:
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-1
spec:
hostnames:
- gateway.envoyproxy.io
parentRefs:
- namespace: envoy-gateway
name: gateway-2
sectionName: http
rules:
- matches:
- path:
value: "/"
retry:
codes:
- 500
attempts: 3
backoff: 200ms
timeouts:
backendRequest: 3s
backendRefs:
- name: service-1
port: 8080
backendTrafficPolicies:
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: envoy-gateway
name: policy-for-gateway
spec:
targetRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-1
retry:
retryOn:
triggers:
- cancelled
perRetry:
timeout: 250ms
backoff:
baseInterval: 100ms
maxInterval: 10s
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: default
name: policy-for-route
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: httproute-1
retry:
numRetries: 5
retryOn:
httpStatusCodes:
- 429
- 503
triggers:
- connect-failure
- retriable-status-codes
perRetry:
timeout: 250ms
backoff:
baseInterval: 100ms
maxInterval: 10s
Loading
Loading