diff --git a/plugins/caddy-vhosts/internal-functions b/plugins/caddy-vhosts/internal-functions index 76ce0f5bc..472a4b684 100755 --- a/plugins/caddy-vhosts/internal-functions +++ b/plugins/caddy-vhosts/internal-functions @@ -34,13 +34,16 @@ fn-caddy-route-labels() { # The named matcher accepts both the bare prefix and the prefix-glob form # so requests like /api/v0 and /api/v0/users/42 both match. output="$output --label 'caddy.${matcher_name}.path=${route_path} ${route_path}/*'" - output="$output --label 'caddy.${route_index}_route=${matcher_name}'" + # Use handle (not route) so the directive terminates the matched request. + # Otherwise web's bare `reverse_proxy` (at default-order ~190) runs before + # this route block (~210) and catches everything including /api/v0/*. + output="$output --label 'caddy.${route_index}_handle=${matcher_name}'" local sub_index=0 if [[ "$route_strip" == "1" ]]; then - output="$output --label 'caddy.${route_index}_route.${sub_index}_uri=strip_prefix ${route_path}'" + output="$output --label 'caddy.${route_index}_handle.${sub_index}_uri=strip_prefix ${route_path}'" sub_index=$((sub_index + 1)) fi - output="$output --label \"caddy.${route_index}_route.${sub_index}_reverse_proxy={{upstreams ${route_port}}}\"" + output="$output --label \"caddy.${route_index}_handle.${sub_index}_reverse_proxy={{upstreams ${route_port}}}\"" route_index=$((route_index + 1)) done < <(plugn trigger proxy-routes-list "$APP") diff --git a/plugins/traefik-vhosts/internal-functions b/plugins/traefik-vhosts/internal-functions index 8d4fa5229..10dbd601e 100755 --- a/plugins/traefik-vhosts/internal-functions +++ b/plugins/traefik-vhosts/internal-functions @@ -31,7 +31,9 @@ fn-traefik-route-labels() { output="$output --label \"traefik.http.routers.${router_name}.rule=${rule}\"" output="$output --label traefik.http.routers.${router_name}.entrypoints=$(fn-traefik-computed-http-entry-point)" - output="$output --label traefik.http.routers.${router_name}.priority=${path_len}" + # No explicit priority - traefik's default (rule length) gives + # longest-prefix-wins because our rule includes both Host(...) and + # PathPrefix(...), which is always longer than web's bare Host(...) rule. output="$output --label traefik.http.routers.${router_name}.service=${service_name}" output="$output --label traefik.http.services.${service_name}.loadbalancer.server.port=${route_port}" diff --git a/tests/unit/proxy-route-k3s-nginx.bats b/tests/unit/proxy-route-k3s-nginx.bats index ddcda9d0b..bf9b620dd 100644 --- a/tests/unit/proxy-route-k3s-nginx.bats +++ b/tests/unit/proxy-route-k3s-nginx.bats @@ -40,6 +40,15 @@ teardown() { echo "status: $status" assert_success + # Diagnostic: dump the cluster state so CI logs show whether the api + # Service and the Ingress are wired correctly. + run /bin/bash -c "kubectl get service -o yaml 2>&1" + echo "services: $output" + run /bin/bash -c "kubectl get ingress -o yaml 2>&1" + echo "ingresses: $output" + run /bin/bash -c "kubectl get endpoints -o yaml 2>&1" + echo "endpoints: $output" + # Without --strip-prefix, /api/v0/Procfile reaches api as /api/v0/Procfile # which python's http.server returns 404 for. 404 proves the route reaches # api (web's catch-all would have returned 200). diff --git a/tests/unit/proxy-route-k3s-traefik.bats b/tests/unit/proxy-route-k3s-traefik.bats index 89d6e0243..5e3661d3f 100644 --- a/tests/unit/proxy-route-k3s-traefik.bats +++ b/tests/unit/proxy-route-k3s-traefik.bats @@ -40,6 +40,15 @@ teardown() { echo "status: $status" assert_success + # Diagnostic: dump the cluster state so CI logs show whether the api + # Service and the IngressRoute are wired correctly. + run /bin/bash -c "kubectl get service -o yaml 2>&1" + echo "services: $output" + run /bin/bash -c "kubectl get ingressroute.traefik.io -o yaml 2>&1" + echo "ingressroutes: $output" + run /bin/bash -c "kubectl get endpoints -o yaml 2>&1" + echo "endpoints: $output" + # Without --strip-prefix, /api/v0/Procfile reaches api as /api/v0/Procfile # which python's http.server returns 404 for. 404 proves the route reaches # api (web's catch-all would have returned 200). diff --git a/tests/unit/proxy-route-openresty.bats b/tests/unit/proxy-route-openresty.bats index 3a43e14d4..98b02d5d3 100644 --- a/tests/unit/proxy-route-openresty.bats +++ b/tests/unit/proxy-route-openresty.bats @@ -86,9 +86,15 @@ teardown() { run /bin/bash -c "docker inspect ${TEST_APP}.api.1 --format '{{json .Config.Labels}}' 2>&1 | jq . 2>/dev/null || docker inspect ${TEST_APP}.api.1 --format '{{json .Config.Labels}}' 2>&1" echo "api labels: $output" - # Give the daemon a moment to read the new labels. - sleep 5 - assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server" + # openresty-docker-proxy 0.12.0 has a polling/caching delay before it + # re-renders the config after labels on an existing route key change. + # Give it a longer window than the default HTTP retry. If this still + # times out, dump the sidecar logs so we can file an upstream bug. + HTTP_ASSERT_RETRIES=60 assert_http_localhost_response_contains "http" "${TEST_APP}.${DOKKU_DOMAIN}" "80" "/api/v0/Procfile" "python3 -m http.server" || { + run /bin/bash -c "dokku openresty:logs --num 200 2>&1 || docker logs openresty-openresty-1 --tail 200 2>&1" + echo "openresty sidecar logs: $output" + return 1 + } } @test "(proxy-route:openresty) removing a route falls back to web" {