Skip to content

Commit

Permalink
Add support for error pages for VS/VSR
Browse files Browse the repository at this point in the history
  • Loading branch information
Raul Marrero authored and Rulox committed Feb 11, 2020
1 parent 65c0fef commit c2bccae
Show file tree
Hide file tree
Showing 11 changed files with 1,729 additions and 175 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ This document is the reference documentation for the resources. To see additiona
- [Split](#split)
- [Match](#match)
- [Condition](#condition)
- [ErrorPage](#errorpage)
- [ErrorPage.Redirect](#errorpage-redirect)
- [ErrorPage.Return](#errorpage-return)
- [Using VirtualServer and VirtualServerRoute](#using-virtualserver-and-virtualserverroute)
- [Validation](#validation)
- [Customization via ConfigMap](#customization-via-configmap)
Expand Down Expand Up @@ -186,6 +189,10 @@ The route defines rules for matching client requests to actions like passing a r
- The name of a VirtualServerRoute resource that defines this route. If the VirtualServerRoute belongs to a different namespace than the VirtualServer, you need to include the namespace. For example, ``tea-namespace/tea``.
- ``string``
- No*
* - ``errorPages``
- The custom responses for error codes. NGINX will use those responses instead of returning the error responses from the upstream servers or the default responses generated by NGINX. A custom response can be a redirect or a canned response. For example, a redirect to another URL if an upstream server responded with a 404 status code.
- `[]errorPage <#errorpage>`_
- No
```
\* -- a route must include exactly one of the following: `action`, `splits`, or `route`.
Expand Down Expand Up @@ -299,6 +306,10 @@ action:
- The matching rules for advanced content-based routing. Requires the default ``action`` or ``splits``. Unmatched requests will be handled by the default ``action`` or ``splits``.
- `matches <#match>`_
- No
* - ``errorPages``
- The custom responses for error codes. NGINX will use those responses instead of returning the error responses from the upstream servers or the default responses generated by NGINX. A custom response can be a redirect or a canned response. For example, a redirect to another URL if an upstream server responded with a 404 status code.
- `[]errorPage <#errorpage>`_
- No
```
\* -- a subroute must include exactly one of the following: `action` or `splits`.
Expand Down Expand Up @@ -930,6 +941,148 @@ The value supports two kinds of matching:

**Note**: a value must not include any unescaped double quotes (`"`) and must not end with an unescaped backslash (`\`). For example, the following are invalid values: `some"value`, `somevalue\`.


### ErrorPage

The errorPage defines a custom response for a route for the case when either an upstream server responds with (or NGINX generates) an error status code. The custom response can be a redirect or a canned response. See the [error_page](https://nginx.org/en/docs/http/ngx_http_core_module.html#error_page) directive for more information.
```yaml
path: /coffee
errorPages:
- codes: [502, 503]
redirect:
code: 301
url: https://nginx.org
- codes: [404]
return:
code: 200
body: "Original resource not found, but success!"
```

```eval_rst
.. list-table::
:header-rows: 1
* - Field
- Description
- Type
- Required
* - ``codes``
- A list of error status codes.
- ``[]int``
- Yes
* - ``redirect``
- The redirect action for the given status codes.
- `errorPage.Redirect <#errorpage-redirect>`_
- No*
* - ``return``
- The canned response action for the given status codes.
- `errorPage.Return <#errorpage-return>`_
- No*
```
\* -- an errorPage must include exactly one of the following: `return` or `redirect`.

### ErrorPage.Redirect

The redirect defines a redirect for an errorPage.

In the example below, NGINX responds with a redirect when a response from an upstream server has a 404 status code.

```yaml
codes: [404]
redirect:
code: 301
url: ${scheme}://cafe.example.com/error_${status}.html
```

```eval_rst
.. list-table::
:header-rows: 1
* - Field
- Description
- Type
- Required
* - ``code``
- The status code of a redirect. The allowed values are: ``301``\ , ``302``\ , ``307``\ , ``308``. The default is ``301``.
- ``int``
- No
* - ``url``
- The URL to redirect the request to. Supported NGINX variables: ``$scheme``\ , ``$status``\ and ``$http_x_forwarded_proto``\. Variables must be inclosed in curly braces. For example: ``${scheme}``.
- ``string``
- Yes
```

### ErrorPage.Return

The return defines a canned response for an errorPage.

In the example below, NGINX responds with a canned response when a response from an upstream server has either 401 or 403 status code.

```yaml
codes: [401, 403]
return:
code: 200
type: application/json
body: "{\"msg\": \"You don't have permission to do this\"}"
headers:
- name: x-debug-original-status
value: ${status}
```

```eval_rst
.. list-table::
:header-rows: 1
* - Field
- Description
- Type
- Required
* - ``code``
- The status code of the response. The default is the status code of the original response.
- ``int``
- No
* - ``type``
- The MIME type of the response. The default is ``text/html``.
- ``string``
- No
* - ``body``
- The body of the response. Supported NGINX variable: ``$status`` \ . Variables must be inclosed in curly braces. For example: ``${status}``.
- ``string``
- Yes
* - ``headers``
- The custom headers of the response.
- `errorPage.Redirect.Header <#errorpage-return-header>`_
- No
```
### ErrorPage.Return.Header
The header defines an HTTP Header for a canned response in an errorPage:
```yaml
name: x-debug-original-status
value: ${status}
```
```eval_rst
.. list-table::
:header-rows: 1

* - Field
- Description
- Type
- Required
* - ``name``
- The name of the header.
- ``string``
- Yes
* - ``value``
- The value of the header. Supported NGINX variables: ``$status`` \ . Variables must be inclosed in curly braces. For example: ``${status}``.
- ``string``
- No
```
## Using VirtualServer and VirtualServerRoute
You can use the usual `kubectl` commands to work with VirtualServer and VirtualServerRoute resources, similar to Ingress resources.
Expand Down
25 changes: 25 additions & 0 deletions internal/configs/version2/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ type Server struct {
Snippets []string
InternalRedirectLocations []InternalRedirectLocation
Locations []Location
ErrorPageLocations []ErrorPageLocation
HealthChecks []HealthCheck
TLSRedirect *TLSRedirect
}
Expand All @@ -58,6 +59,7 @@ type SSL struct {
// Location defines a location.
type Location struct {
Path string
Internal bool
Snippets []string
ProxyConnectTimeout string
ProxyReadTimeout string
Expand All @@ -71,9 +73,11 @@ type Location struct {
ProxyNextUpstream string
ProxyNextUpstreamTimeout string
ProxyNextUpstreamTries int
ProxyInterceptErrors bool
HasKeepalive bool
DefaultType string
Return *Return
ErrorPages []ErrorPage
}

// SplitClient defines a split_clients.
Expand All @@ -89,6 +93,27 @@ type Return struct {
Text string
}

// ErrorPage defines an error_page of a location.
type ErrorPage struct {
Name string
Codes string
ResponseCode int
}

// ErrorPageLocation defines a named location for an error_page directive.
type ErrorPageLocation struct {
Name string
DefaultType string
Return *Return
Headers []Header
}

// Header defines a header to use with add_header directive.
type Header struct {
Name string
Value string
}

// HealthCheck defines a HealthCheck for an upstream in a Server.
type HealthCheck struct {
Name string
Expand Down
27 changes: 24 additions & 3 deletions internal/configs/version2/nginx-plus.virtualserver.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -88,8 +88,7 @@ server {

{{ range $l := $s.InternalRedirectLocations }}
location {{ $l.Path }} {
error_page 418 = {{ $l.Destination }};
return 418;
rewrite ^ {{ $l.Destination }} last;
}
{{ end }}

Expand All @@ -107,8 +106,24 @@ server {
}
{{ end }}

{{ range $e := $s.ErrorPageLocations }}
location {{ $e.Name }} {
{{ if $e.DefaultType }}
default_type "{{ $e.DefaultType }}";
{{ end }}
{{ range $h := $e.Headers }}
add_header {{ $h.Name }} "{{ $h.Value }}" always;
{{ end }}
# status code is ignored here, using 0
return 0 "{{ $e.Return.Text }}";
}
{{ end }}

{{ range $l := $s.Locations }}
location {{ $l.Path }} {
{{ if $l.Internal }}
internal;
{{ end }}
{{ range $snippet := $l.Snippets }}
{{ $snippet }}
{{ end }}
Expand All @@ -121,6 +136,10 @@ server {
{{ end }}

{{ if $l.ProxyPass }}
{{ range $e := $l.ErrorPages }}
error_page {{ $e.Codes }} {{ if ne 0 $e.ResponseCode }}={{ $e.ResponseCode }}{{ end }} "{{ $e.Name }}";
{{ end }}

proxy_connect_timeout {{ $l.ProxyConnectTimeout }};
proxy_read_timeout {{ $l.ProxyReadTimeout }};
proxy_send_timeout {{ $l.ProxySendTimeout }};
Expand All @@ -137,7 +156,9 @@ server {
{{ if $l.ProxyBufferSize }}
proxy_buffer_size {{ $l.ProxyBufferSize }};
{{ end }}

{{ if $l.ProxyInterceptErrors }}
proxy_intercept_errors on;
{{ end }}
proxy_http_version 1.1;

set $default_connection_header {{ if $l.HasKeepalive }}""{{ else }}close{{ end }};
Expand Down
27 changes: 24 additions & 3 deletions internal/configs/version2/nginx.virtualserver.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,28 @@ server {

{{ range $l := $s.InternalRedirectLocations }}
location {{ $l.Path }} {
error_page 418 = {{ $l.Destination }};
return 418;
rewrite ^ {{ $l.Destination }} last;
}
{{ end }}

{{ range $e := $s.ErrorPageLocations }}
location {{ $e.Name }} {
{{ if $e.DefaultType }}
default_type "{{ $e.DefaultType }}";
{{ end }}
{{ range $h := $e.Headers }}
add_header {{ $h.Name }} "{{ $h.Value }}" always;
{{ end }}
# status code is ignored here, using 0
return 0 "{{ $e.Return.Text }}";
}
{{ end }}

{{ range $l := $s.Locations }}
location {{ $l.Path }} {
{{ if $l.Internal }}
internal;
{{ end }}
{{ range $snippet := $l.Snippets }}
{{ $snippet }}
{{ end }}
Expand All @@ -90,6 +105,10 @@ server {
{{ end }}

{{ if $l.ProxyPass }}
{{ range $e := $l.ErrorPages }}
error_page {{ $e.Codes }} {{ if ne 0 $e.ResponseCode }}={{ $e.ResponseCode }}{{ end }} "{{ $e.Name }}";
{{ end }}

proxy_connect_timeout {{ $l.ProxyConnectTimeout }};
proxy_read_timeout {{ $l.ProxyReadTimeout }};
proxy_send_timeout {{ $l.ProxySendTimeout }};
Expand All @@ -106,7 +125,9 @@ server {
{{ if $l.ProxyBufferSize }}
proxy_buffer_size {{ $l.ProxyBufferSize }};
{{ end }}

{{ if $l.ProxyInterceptErrors }}
proxy_intercept_errors on;
{{ end }}
proxy_http_version 1.1;

set $default_connection_header {{ if $l.HasKeepalive }}""{{ else }}close{{ end }};
Expand Down
Loading

0 comments on commit c2bccae

Please sign in to comment.