Skip to content

Commit

Permalink
chore(#8179) Add json error messages to haproxy (#8481)
Browse files Browse the repository at this point in the history
  • Loading branch information
nydr authored Aug 24, 2023
1 parent e0d31ca commit 6c1b854
Show file tree
Hide file tree
Showing 40 changed files with 478 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Nginx test
name: Test nginx and haproxy

on: [push, pull_request]

Expand All @@ -18,3 +18,7 @@ jobs:
cd nginx
make test
)
(
cd haproxy/tests
make test
)
1 change: 1 addition & 0 deletions haproxy/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@ RUN chmod +x /entrypoint.sh
ADD default_frontend.cfg /usr/local/etc/haproxy
ADD backend.cfg.template /usr/local/etc/haproxy
COPY scripts /usr/local/etc/haproxy/
COPY errors/*.http /usr/local/etc/haproxy/errors/

ENTRYPOINT ["/entrypoint.sh"]
5 changes: 2 additions & 3 deletions haproxy/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ In your docker-compose.yml template, the HAproxy container declaration will requ
- HAPROXY_IP: This should be the docker service name, `fqdn`, or set to `0.0.0.0`. If not set, our templates will default this to be a service name of `haproxy`.
*Note*: For Docker Desktop on Mac users, if you wish to expose HAproxy to your host, you will have to set this as `0.0.0.0`, to expose it as `localhost` outside of the docker network.
- HAPROXY_PORT: The port you wish HAProxy to run on. Defaults to 5984.
- COUCHDB1_SERVER: The docker service name or fqdn of the first CouchDB server. Defaults to couchdb-1.local in our templates.
- COUCHDB2_SERVER: The docker service name or fqdn of the second CouchDB server. Defaults to couchdb-2.local in our templates.
- COUCHDB3_SERVER: The docker service name or fqdn of the third CouchDB server. Defaults to couchdb-3.local in our templates.
- COUCHDB_SERVERS: Comma separated list of the docker service name or fqdn of the CouchDB servers. Example: `couchdb-1.local,couchdb-2.local,couchdb-3.local`.
- COUCHDB_USER: The admininstrator that created the couchdb cluster
- COUCHDB_PASSWORD: The above admin's password
- HEALTHCHECK_ADDR: Address to the haproxy healthcheck service
24 changes: 24 additions & 0 deletions haproxy/default_frontend.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,27 @@ global
tune.bufsize 32768
tune.buffers.limit 60000

http-errors json
errorfile 200 /usr/local/etc/haproxy/errors/200-json.http
errorfile 400 /usr/local/etc/haproxy/errors/400-json.http
errorfile 401 /usr/local/etc/haproxy/errors/401-json.http
errorfile 403 /usr/local/etc/haproxy/errors/403-json.http
errorfile 404 /usr/local/etc/haproxy/errors/404-json.http
errorfile 405 /usr/local/etc/haproxy/errors/405-json.http
errorfile 407 /usr/local/etc/haproxy/errors/407-json.http
errorfile 408 /usr/local/etc/haproxy/errors/408-json.http
errorfile 410 /usr/local/etc/haproxy/errors/410-json.http
errorfile 413 /usr/local/etc/haproxy/errors/413-json.http
errorfile 421 /usr/local/etc/haproxy/errors/421-json.http
errorfile 422 /usr/local/etc/haproxy/errors/422-json.http
errorfile 425 /usr/local/etc/haproxy/errors/425-json.http
errorfile 429 /usr/local/etc/haproxy/errors/429-json.http
errorfile 500 /usr/local/etc/haproxy/errors/500-json.http
errorfile 501 /usr/local/etc/haproxy/errors/501-json.http
errorfile 502 /usr/local/etc/haproxy/errors/502-json.http
errorfile 503 /usr/local/etc/haproxy/errors/503-json.http
errorfile 504 /usr/local/etc/haproxy/errors/504-json.http

defaults
mode http
option http-ignore-probes
Expand All @@ -19,6 +40,9 @@ defaults
timeout server 360000000
timeout connect 1500000
timeout http-keep-alive 5m

errorfiles json

stats enable
stats refresh 30s
stats auth $COUCHDB_USER:$COUCHDB_PASSWORD
Expand Down
7 changes: 4 additions & 3 deletions haproxy/entrypoint.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ BACKEND="/usr/local/etc/haproxy/backend.cfg"
cp /usr/local/etc/haproxy/backend.cfg.template $BACKEND
for COUCHDB_SERVER in ${COUCHDB_SERVERS//,/ }
do
printf " server $COUCHDB_SERVER $COUCHDB_SERVER:5984 check agent-check agent-inter 5s agent-addr $HEALTHCHECK_ADDR agent-port 5555\n" >> $BACKEND
echo " server $COUCHDB_SERVER $COUCHDB_SERVER:5984 check agent-check agent-inter 5s agent-addr $HEALTHCHECK_ADDR agent-port 5555" >> $BACKEND
done

# Place environment variables into config
Expand All @@ -18,8 +18,9 @@ envsubst < $BACKEND

#Write pw for healthcheck subshell to work
mkdir -p /srv/storage/haproxy/passwd
echo $COUCHDB_USER > /srv/storage/haproxy/passwd/username
echo $COUCHDB_PASSWORD > /srv/storage/haproxy/passwd/admin
echo "$COUCHDB_USER" > /srv/storage/haproxy/passwd/username
echo "$COUCHDB_PASSWORD" > /srv/storage/haproxy/passwd/admin

# Start haproxy
exec /usr/local/bin/docker-entrypoint.sh -f $DEFAULT -f $BACKEND

10 changes: 10 additions & 0 deletions haproxy/errors/200-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 200 OK
Content-length: 75
Cache-Control: no-cache
Content-Type: application/json

{
"error": "200 OK",
"reason": "Service ready",
"server": "haproxy"
}
11 changes: 11 additions & 0 deletions haproxy/errors/400-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
HTTP/1.1 400 Bad request
Content-length: 107
Connection: Close
Cache-Control: no-cache
Content-Type: application/json

{
"error": "400 Bad request",
"reason": "Your browser sent an invalid request",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/401-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 401 Unauthorized
Content-length: 129
Cache-Control: no-cache
Content-Type: application/json

{
"error": "401 Unauthorized",
"reason": "You need a valid user and password to access this content",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/403-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 403 Forbidden
Content-length: 110
Cache-Control: no-cache
Content-Type: application/json

{
"error": "403 Forbidden",
"reason": "Request forbidden by administrative rules",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/404-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 404 Not Found
Content-length: 100
Cache-Control: no-cache
Content-Type: application/json

{
"error": "404 Not Found",
"reason": "The resource could not be found",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/405-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 405 Method Not Allowed
Content-length: 164
Cache-Control: no-cache
Content-Type: application/json

{
"error": "405 Method Not Allowed",
"reason": "A request was made of a resource using a request method not supported by that resource",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/407-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 407 Unauthorized
Content-length: 129
Cache-Control: no-cache
Content-Type: application/json

{
"error": "407 Unauthorized",
"reason": "You need a valid user and password to access this content",
"server": "haproxy"
}
11 changes: 11 additions & 0 deletions haproxy/errors/408-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
HTTP/1.1 408 Request Time-out
Content-length: 127
Connection: Close
Cache-Control: no-cache
Content-Type: application/json

{
"error": "408 Request Time-out",
"reason": "Your browser didn't send a complete request in time",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/410-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 410 Gone
Content-length: 131
Cache-Control: no-cache
Content-Type: application/json

{
"error": "410 Gone",
"reason": "The resource is no longer available and will not be available again",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/413-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 413 Payload Too Large
Content-length: 123
Cache-Control: no-cache
Content-Type: application/json

{
"error": "413 Payload Too Large",
"reason": "The request entity exceeds the maximum allowed",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/421-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 421 Misdirected Request
Content-length: 121
Cache-Control: no-cache
Content-Type: application/json

{
"error": "421 Misdirected Request",
"reason": "Request sent to a non-authoritative server",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/422-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 422 Unprocessable Content
Content-length: 133
Cache-Control: no-cache
Content-Type: application/json

{
"error": "422 Unprocessable Content",
"reason": "The server cannot process the contained instructions",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/425-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 425 Too Early
Content-length: 97
Cache-Control: no-cache
Content-Type: application/json

{
"error": "425 Too Early",
"reason": "Your browser sent early data",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/429-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 429 Too Many Requests
Content-length: 134
Cache-Control: no-cache
Content-Type: application/json

{
"error": "429 Too Many Requests",
"reason": "You have sent too many requests in a given amount of time",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/500-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 500 Internal Server Error
Content-length: 114
Cache-Control: no-cache
Content-Type: application/json

{
"error": "500 Internal Server Error",
"reason": "An internal server error occurred",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/501-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 501 Not Implemented
Content-length: 152
Cache-Control: no-cache
Content-Type: application/json

{
"error": "501 Not Implemented",
"reason": "The server does not support the functionality required to fulfill the request",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/502-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 502 Bad Gateway
Content-length: 124
Cache-Control: no-cache
Content-Type: application/json

{
"error": "502 Bad Gateway",
"reason": "The server returned an invalid or incomplete response",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/503-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 503 Service Unavailable
Content-length: 124
Cache-Control: no-cache
Content-Type: application/json

{
"error": "503 Service Unavailable",
"reason": "No server is available to handle this request",
"server": "haproxy"
}
10 changes: 10 additions & 0 deletions haproxy/errors/504-json.http
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
HTTP/1.1 504 Gateway Time-out
Content-length: 109
Cache-Control: no-cache
Content-Type: application/json

{
"error": "504 Gateway Time-out",
"reason": "The server didn't respond in time",
"server": "haproxy"
}
4 changes: 4 additions & 0 deletions haproxy/errors/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# nginx_error_messages

This directory contains error pages for haproxy. Do not update the error pages
manually, instead look in `generate.sh` and the `template.json` file
71 changes: 71 additions & 0 deletions haproxy/errors/generate.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#!/bin/bash
###########################################################
#
# Script to generate static error pages for haproxy
#
# To update: change messages below or the respective template file
# and rerun this script
#
###########################################################
set -eu -o pipefail
unset IFS

DIR="$(dirname "$(readlink -f "${BASH_SOURCE[0]}")")"

TEMPDIR="$(mktemp -d)"
trap 'rm -rf "$TEMPDIR"' EXIT

declare -ar MESSAGES=(
"200|200 OK|Service ready|"
"400|400 Bad request|Your browser sent an invalid request|Connection: Close"
"401|401 Unauthorized|You need a valid user and password to access this content|"
"403|403 Forbidden|Request forbidden by administrative rules|"
"404|404 Not Found|The resource could not be found|"
"405|405 Method Not Allowed|A request was made of a resource using a request method not supported by that resource|"
"407|407 Unauthorized|You need a valid user and password to access this content|"
"408|408 Request Time-out|Your browser didn't send a complete request in time|Connection: Close"
"410|410 Gone|The resource is no longer available and will not be available again|"
"413|413 Payload Too Large|The request entity exceeds the maximum allowed|"
"421|421 Misdirected Request|Request sent to a non-authoritative server|"
"422|422 Unprocessable Content|The server cannot process the contained instructions|"
"425|425 Too Early|Your browser sent early data|"
"429|429 Too Many Requests|You have sent too many requests in a given amount of time|"
"500|500 Internal Server Error|An internal server error occurred|"
"501|501 Not Implemented|The server does not support the functionality required to fulfill the request|"
"502|502 Bad Gateway|The server returned an invalid or incomplete response|"
"503|503 Service Unavailable|No server is available to handle this request|"
"504|504 Gateway Time-out|The server didn't respond in time|"
)

echo 'http-errors json'
for message in "${MESSAGES[@]}"; do
IFS='|' read -r -a message_parts <<<"$message"
status_code="${message_parts[0]}"
status_message="${message_parts[1]}"
status_reason="${message_parts[2]}"
extra_header="${message_parts[3]:-}"

error_file="$DIR/${status_code}-json.http"

LC_ALL="C" # So content-length/$http_body is >1 for multibyte characters

http_body="$(sed -e "s/__MESSAGE__/$status_message/" -e "s/__REASON__/$status_reason/" <"$DIR/template.json")"

cat <<EOF >"$error_file"
HTTP/1.1 $status_message
Content-length: ${#http_body}
EOF

[[ -n "$extra_header" ]] && echo "$extra_header" >>"$error_file"

cat <<EOF >>"$error_file"
Cache-Control: no-cache
Content-Type: application/json
EOF

echo -n "$http_body" >>"$error_file"

echo " errorfile $status_code /usr/local/etc/haproxy/errors/${status_code}-json.http"

done
Loading

0 comments on commit 6c1b854

Please sign in to comment.