diff --git a/plugins/nginx-vhosts/template_test.go b/plugins/nginx-vhosts/template_test.go index fa5beacc9..4248e5532 100644 --- a/plugins/nginx-vhosts/template_test.go +++ b/plugins/nginx-vhosts/template_test.go @@ -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 diff --git a/plugins/traefik-vhosts/internal-functions b/plugins/traefik-vhosts/internal-functions index 10dbd601e..29df8bd6f 100755 --- a/plugins/traefik-vhosts/internal-functions +++ b/plugins/traefik-vhosts/internal-functions @@ -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" } diff --git a/tests/unit/proxy-route-traefik.bats b/tests/unit/proxy-route-traefik.bats index 19609105e..7af93a89c 100644 --- a/tests/unit/proxy-route-traefik.bats +++ b/tests/unit/proxy-route-traefik.bats @@ -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