Skip to content

Commit

Permalink
feat: Add support for overriding status code in response overrides
Browse files Browse the repository at this point in the history
Fixes: envoyproxy#4678

Signed-off-by: Arko Dasgupta <[email protected]>
  • Loading branch information
arkodg committed Dec 12, 2024
1 parent 7bb7624 commit 0abf3d3
Show file tree
Hide file tree
Showing 17 changed files with 288 additions and 20 deletions.
10 changes: 9 additions & 1 deletion api/v1alpha1/shared_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,15 @@ type CustomResponse struct {
ContentType *string `json:"contentType,omitempty"`

// Body of the Custom Response
Body CustomResponseBody `json:"body"`
//
// +optional
Body *CustomResponseBody `json:"body,omitempty"`

// Status Code of the Custom Response
// If unset, does not override the status of response.
//
// +optional
StatusCode *int `json:"statusCode,omitempty"`
}

// ResponseValueType defines the types of values for the response body supported by Envoy Gateway.
Expand Down
11 changes: 10 additions & 1 deletion api/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -1071,8 +1071,11 @@ spec:
description: Content Type of the response. This will be
set in the Content-Type header.
type: string
required:
- body
statusCode:
description: |-
Status Code of the Custom Response
If unset, does not override the status of response.
type: integer
type: object
required:
- match
Expand Down
10 changes: 7 additions & 3 deletions internal/gatewayapi/backendtrafficpolicy.go
Original file line number Diff line number Diff line change
Expand Up @@ -878,6 +878,10 @@ func buildResponseOverride(policy *egv1a1.BackendTrafficPolicy, resources *resou
ContentType: ro.Response.ContentType,
}

if ro.Response.StatusCode != nil {
response.StatusCode = ptr.To(uint32(*ro.Response.StatusCode))
}

var err error
response.Body, err = getCustomResponseBody(ro.Response.Body, resources, policy.Namespace)
if err != nil {
Expand All @@ -896,8 +900,8 @@ func buildResponseOverride(policy *egv1a1.BackendTrafficPolicy, resources *resou
}, nil
}

func getCustomResponseBody(body egv1a1.CustomResponseBody, resources *resource.Resources, policyNs string) (*string, error) {
if body.Type != nil && *body.Type == egv1a1.ResponseValueTypeValueRef {
func getCustomResponseBody(body *egv1a1.CustomResponseBody, resources *resource.Resources, policyNs string) (*string, error) {
if body != nil && body.Type != nil && *body.Type == egv1a1.ResponseValueTypeValueRef {
cm := resources.GetConfigMap(policyNs, string(body.ValueRef.Name))
if cm != nil {
b, dataOk := cm.Data["response.body"]
Expand All @@ -917,7 +921,7 @@ func getCustomResponseBody(body egv1a1.CustomResponseBody, resources *resource.R
} else {
return nil, fmt.Errorf("can't find the referenced configmap %s", body.ValueRef.Name)
}
} else if body.Inline != nil {
} else if body != nil && body.Inline != nil {
return body.Inline, nil
}

Expand Down
2 changes: 1 addition & 1 deletion internal/gatewayapi/filters.go
Original file line number Diff line number Diff line change
Expand Up @@ -905,7 +905,7 @@ func (t *Translator) processExtensionRefHTTPFilter(extFilter *gwapiv1.LocalObjec
dr := &ir.CustomResponse{}
if hrf.Spec.DirectResponse.Body != nil {
var err error
if dr.Body, err = getCustomResponseBody(*hrf.Spec.DirectResponse.Body, resources, filterNs); err != nil {
if dr.Body, err = getCustomResponseBody(hrf.Spec.DirectResponse.Body, resources, filterNs); err != nil {
t.processInvalidHTTPFilter(string(extFilter.Kind), filterContext, err)
return
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,26 @@ httpRoutes:
name: httproute-1
spec:
hostnames:
- gateway.envoyproxy.io
- foo.envoyproxy.io
parentRefs:
- namespace: default
name: gateway-2
sectionName: http
rules:
- matches:
- path:
value: "/"
backendRefs:
- name: service-1
port: 8080
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
namespace: default
name: httproute-2
spec:
hostnames:
- bar.envoyproxy.io
parentRefs:
- namespace: default
name: gateway-2
Expand Down Expand Up @@ -114,7 +133,7 @@ backendTrafficPolicies:
kind: BackendTrafficPolicy
metadata:
namespace: default
name: policy-for-route
name: policy-for-route-1
spec:
targetRef:
group: gateway.networking.k8s.io
Expand Down Expand Up @@ -143,3 +162,19 @@ backendTrafficPolicies:
group: ""
kind: ConfigMap
name: response-override-config
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
namespace: default
name: policy-for-route-2
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: httproute-2
responseOverride:
- match:
statusCodes:
- value: 403
response:
statusCode: 401
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ backendTrafficPolicies:
kind: BackendTrafficPolicy
metadata:
creationTimestamp: null
name: policy-for-route
name: policy-for-route-1
namespace: default
spec:
responseOverride:
Expand Down Expand Up @@ -51,6 +51,39 @@ backendTrafficPolicies:
status: "True"
type: Accepted
controllerName: gateway.envoyproxy.io/gatewayclass-controller
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
creationTimestamp: null
name: policy-for-route-2
namespace: default
spec:
responseOverride:
- match:
statusCodes:
- type: null
value: 403
response:
statusCode: 401
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: httproute-2
status:
ancestors:
- ancestorRef:
group: gateway.networking.k8s.io
kind: Gateway
name: gateway-2
namespace: default
sectionName: http
conditions:
- lastTransitionTime: null
message: Policy has been accepted.
reason: Accepted
status: "True"
type: Accepted
controllerName: gateway.envoyproxy.io/gatewayclass-controller
- apiVersion: gateway.envoyproxy.io/v1alpha1
kind: BackendTrafficPolicy
metadata:
Expand Down Expand Up @@ -160,7 +193,7 @@ gateways:
protocol: HTTP
status:
listeners:
- attachedRoutes: 1
- attachedRoutes: 2
conditions:
- lastTransitionTime: null
message: Sending translated listener configuration to the data plane
Expand Down Expand Up @@ -226,7 +259,45 @@ httpRoutes:
namespace: default
spec:
hostnames:
- gateway.envoyproxy.io
- foo.envoyproxy.io
parentRefs:
- name: gateway-2
namespace: default
sectionName: http
rules:
- backendRefs:
- name: service-1
port: 8080
matches:
- path:
value: /
status:
parents:
- conditions:
- lastTransitionTime: null
message: Route is accepted
reason: Accepted
status: "True"
type: Accepted
- lastTransitionTime: null
message: Resolved all the Object references for the Route
reason: ResolvedRefs
status: "True"
type: ResolvedRefs
controllerName: gateway.envoyproxy.io/gatewayclass-controller
parentRef:
name: gateway-2
namespace: default
sectionName: http
- apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
creationTimestamp: null
name: httproute-2
namespace: default
spec:
hostnames:
- bar.envoyproxy.io
parentRefs:
- name: gateway-2
namespace: default
Expand Down Expand Up @@ -377,25 +448,25 @@ xdsIR:
port: 8080
protocol: HTTP
weight: 1
hostname: gateway.envoyproxy.io
hostname: foo.envoyproxy.io
isHTTP2: false
metadata:
kind: HTTPRoute
name: httproute-1
namespace: default
name: httproute/default/httproute-1/rule/0/match/0/gateway_envoyproxy_io
name: httproute/default/httproute-1/rule/0/match/0/foo_envoyproxy_io
pathMatch:
distinct: false
name: ""
prefix: /
traffic:
responseOverride:
name: backendtrafficpolicy/default/policy-for-route
name: backendtrafficpolicy/default/policy-for-route-1
rules:
- match:
statusCodes:
- value: 404
name: backendtrafficpolicy/default/policy-for-route/responseoverride/rule/0
name: backendtrafficpolicy/default/policy-for-route-1/responseoverride/rule/0
response:
body: httproute-1 Not Found
contentType: text/plain
Expand All @@ -405,10 +476,40 @@ xdsIR:
- range:
end: 511
start: 501
name: backendtrafficpolicy/default/policy-for-route/responseoverride/rule/1
name: backendtrafficpolicy/default/policy-for-route-1/responseoverride/rule/1
response:
body: |
{
"error": "Internal Server Error"
}
contentType: application/json
- destination:
name: httproute/default/httproute-2/rule/0
settings:
- addressType: IP
endpoints:
- host: 7.7.7.7
port: 8080
protocol: HTTP
weight: 1
hostname: bar.envoyproxy.io
isHTTP2: false
metadata:
kind: HTTPRoute
name: httproute-2
namespace: default
name: httproute/default/httproute-2/rule/0/match/0/bar_envoyproxy_io
pathMatch:
distinct: false
name: ""
prefix: /
traffic:
responseOverride:
name: backendtrafficpolicy/default/policy-for-route-2
rules:
- match:
statusCodes:
- value: 403
name: backendtrafficpolicy/default/policy-for-route-2/responseoverride/rule/0
response:
statusCode: 401
5 changes: 5 additions & 0 deletions internal/xds/translator/custom_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
envoymatcherv3 "github.com/envoyproxy/go-control-plane/envoy/type/matcher/v3"
expr "google.golang.org/genproto/googleapis/api/expr/v1alpha1"
"google.golang.org/protobuf/types/known/anypb"
"google.golang.org/protobuf/types/known/wrapperspb"

egv1a1 "github.com/envoyproxy/gateway/api/v1alpha1"
"github.com/envoyproxy/gateway/internal/ir"
Expand Down Expand Up @@ -395,6 +396,10 @@ func (c *customResponse) buildAction(r ir.ResponseOverrideRule) (*matcherv3.Matc
})
}

if r.Response.StatusCode != nil {
response.StatusCode = &wrapperspb.UInt32Value{Value: *r.Response.StatusCode}
}

var (
pb *anypb.Any
err error
Expand Down
26 changes: 26 additions & 0 deletions internal/xds/translator/testdata/in/xds-ir/custom-response.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,3 +54,29 @@ http:
"error": "Internal Server Error"
}
contentType: application/json
- destination:
name: httproute/default/httproute-2/rule/0
settings:
- addressType: IP
endpoints:
- host: 7.7.7.7
port: 8080
protocol: HTTP
weight: 1
hostname: "*"
isHTTP2: false
metadata:
kind: HTTPRoute
name: httproute-2
namespace: default
name: httproute/default/httproute-2/rule/0/match/-1/*
traffic:
responseOverride:
name: backendtrafficpolicy/default/policy-for-route
rules:
- match:
statusCodes:
- value: 403
name: backendtrafficpolicy/default/policy-for-route/responseoverride/rule/0
response:
statusCode: 404
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,20 @@
name: httproute/default/httproute-1/rule/0
perConnectionBufferLimitBytes: 32768
type: EDS
- circuitBreakers:
thresholds:
- maxRetries: 1024
commonLbConfig:
localityWeightedLbConfig: {}
connectTimeout: 10s
dnsLookupFamily: V4_PREFERRED
edsClusterConfig:
edsConfig:
ads: {}
resourceApiVersion: V3
serviceName: httproute/default/httproute-2/rule/0
ignoreHealthOnHostRemoval: true
lbPolicy: LEAST_REQUEST
name: httproute/default/httproute-2/rule/0
perConnectionBufferLimitBytes: 32768
type: EDS
Loading

0 comments on commit 0abf3d3

Please sign in to comment.