fix: correct traefik route label escaping
Path-based route rules for traefik kept a stray backslash before each backtick, so traefik rejected the router and requests fell through to the web process. The nginx template tests now also supply the route variables and cover route rendering.
This commit is contained in:
@@ -60,6 +60,8 @@ func defaultVars() map[string]interface{} {
|
||||
"PROXY_X_FORWARDED_PROTO": "$scheme",
|
||||
"PROXY_X_FORWARDED_SSL": "",
|
||||
"HTTP2_DIRECTIVE_SUPPORTED": "true",
|
||||
"PROXY_ROUTES": "",
|
||||
"PROXY_ROUTE_LISTENERS": "",
|
||||
}
|
||||
}
|
||||
|
||||
@@ -265,6 +267,50 @@ func TestTemplate_XForwardedSSL(t *testing.T) {
|
||||
mustNotContain(t, out2, "X-Forwarded-Ssl")
|
||||
}
|
||||
|
||||
func TestTemplate_RouteLocationAndUpstream(t *testing.T) {
|
||||
v := defaultVars()
|
||||
v["PROXY_ROUTES"] = "api|5001|/api/v0|0"
|
||||
v["PROXY_ROUTE_LISTENERS"] = "api|5001|10.0.0.3:5001,10.0.0.4:5001"
|
||||
out := renderTemplate(t, v)
|
||||
mustContain(t, out, "location /api/v0 {")
|
||||
mustContain(t, out, "proxy_pass http://app-api-5001;")
|
||||
mustNotContain(t, out, "proxy_pass http://app-api-5001/;")
|
||||
mustContain(t, out, "upstream app-api-5001 {")
|
||||
mustContain(t, out, "server 10.0.0.3:5001;")
|
||||
mustContain(t, out, "server 10.0.0.4:5001;")
|
||||
}
|
||||
|
||||
func TestTemplate_RouteStripPrefix(t *testing.T) {
|
||||
v := defaultVars()
|
||||
v["PROXY_ROUTES"] = "api|5001|/api/v0|1"
|
||||
v["PROXY_ROUTE_LISTENERS"] = "api|5001|10.0.0.3:5001"
|
||||
out := renderTemplate(t, v)
|
||||
mustContain(t, out, "proxy_pass http://app-api-5001/;")
|
||||
}
|
||||
|
||||
func TestTemplate_RouteOmittedOnRedirect(t *testing.T) {
|
||||
v := defaultVars()
|
||||
v["PROXY_PORT_MAP"] = "http:80:5000 https:443:5000"
|
||||
v["SSL_INUSE"] = "true"
|
||||
v["SSL_SERVER_NAME"] = "app.example.com"
|
||||
v["PROXY_ROUTES"] = "api|5001|/api/v0|0"
|
||||
v["PROXY_ROUTE_LISTENERS"] = "api|5001|10.0.0.3:5001"
|
||||
out := renderTemplate(t, v)
|
||||
|
||||
port80, port443, ok := strings.Cut(out, "listen [::]:443")
|
||||
if !ok {
|
||||
t.Fatalf("expected an https server block in output:\n%s", out)
|
||||
}
|
||||
mustNotContain(t, port80, "location /api/v0")
|
||||
mustContain(t, port443, "location /api/v0 {")
|
||||
}
|
||||
|
||||
func TestTemplate_NoRoutesRendersNoRouteBlocks(t *testing.T) {
|
||||
out := renderTemplate(t, defaultVars())
|
||||
mustNotContain(t, out, "upstream app-api-")
|
||||
mustNotContain(t, out, "location /api/v0")
|
||||
}
|
||||
|
||||
func TestTemplate_NginxConfDIncludeAlways(t *testing.T) {
|
||||
cases := []struct {
|
||||
name string
|
||||
|
||||
@@ -23,8 +23,7 @@ fn-traefik-route-labels() {
|
||||
service_name="${APP}-${route_proc}-${route_slug}"
|
||||
path_len="${#route_path}"
|
||||
|
||||
# Triple-backslash for the same eval-survival reason as fn-traefik-host-rule.
|
||||
local rule="PathPrefix(\\\`${route_path}\\\`)"
|
||||
local rule="PathPrefix(\`${route_path}\`)"
|
||||
if [[ -n "$host_rule" ]]; then
|
||||
rule="(${host_rule}) && ${rule}"
|
||||
fi
|
||||
@@ -78,17 +77,12 @@ fn-traefik-host-rule() {
|
||||
return
|
||||
fi
|
||||
|
||||
# Backticks must be double-escaped so they survive the docker-args eval
|
||||
# path. A single backslash leaves a bare backtick in the final string,
|
||||
# which then runs as a command substitution at eval time and breaks the
|
||||
# docker run invocation. Triple-backslash matches the existing emission
|
||||
# convention used by docker-args-process-deploy.
|
||||
for domain in $(echo "$app_domains" | xargs); do
|
||||
if [[ -z "$result" ]]; then
|
||||
result="Host(\\\`${domain}\\\`)"
|
||||
result="Host(\`${domain}\`)"
|
||||
continue
|
||||
fi
|
||||
result="${result} || Host(\\\`${domain}\\\`)"
|
||||
result="${result} || Host(\`${domain}\`)"
|
||||
done
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
@@ -39,6 +39,12 @@ teardown() {
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
|
||||
run /bin/bash -c "docker inspect $TEST_APP.api.1 --format '{{ index .Config.Labels \"traefik.http.routers.$TEST_APP-api-api-v0.rule\" }}'"
|
||||
echo "output: $output"
|
||||
echo "status: $status"
|
||||
assert_success
|
||||
assert_output "(Host(\`$TEST_APP.$DOKKU_DOMAIN\`)) && PathPrefix(\`/api/v0\`)"
|
||||
|
||||
# Give the daemon a moment to read the new labels.
|
||||
sleep 5
|
||||
|
||||
|
||||
Reference in New Issue
Block a user