Initial commit: router front-door vLLM stack

Three always-running vLLM services (text TP=2 GPU0+1, ocr + embed on GPU2,
sleep mode) behind a FastAPI router that auto-wakes models on request.
Tiered idle (sleep 15 min / offload 3 h), depth-aware 503s with
Retry-After, persisted wake-intent recovery, admin API on 127.0.0.1:8010.
Routine control via vllmctl is pure HTTP — no docker on the request path.

Verified: 91 router unit tests + 15-test E2E on real hardware
(measurements in CALIBRATION.md; design record in
.claude/memory/router-front-door-plan.md).

Old nginx stack files removed before git init; design survives in
.claude/memory/sleep-mode-implementation-plan.md.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-17 10:17:42 +00:00
commit 80eef4ce6a
35 changed files with 6506 additions and 0 deletions

146
router/tests/test_paths.py Normal file
View File

@@ -0,0 +1,146 @@
"""Allowlist: only /v1/*, /health (and /metrics when enabled) are public."""
from __future__ import annotations
import httpx
from app import build_apps
from conftest import raw_asgi
DEV_ENDPOINTS = [
"/sleep",
"/wake_up",
"/collective_rpc",
"/reset_prefix_cache",
"/is_sleeping",
]
ADMIN_PATHS = ["/admin/status", "/admin/wake/text", "/admin/sleep/text?level=1"]
async def test_dev_endpoints_404_on_public(pub, backend):
for path in DEV_ENDPOINTS:
r = await pub.post(path)
assert r.status_code == 404, path
assert r.json()["error"]["code"] == "not_found"
for path in DEV_ENDPOINTS:
r = await pub.get(path)
assert r.status_code == 404, path
assert backend.calls == []
async def test_admin_not_on_public(pub, backend):
for path in ADMIN_PATHS:
r = await pub.request("POST", path)
assert r.status_code == 404, path
r = await pub.get(path)
assert r.status_code == 404, path
assert backend.calls == []
async def test_docs_and_openapi_404(pub):
for path in ("/docs", "/redoc", "/openapi.json", "/"):
r = await pub.get(path)
assert r.status_code == 404, path
async def test_dotted_paths_404(pub):
for path in ("/v1/../sleep", "/v1/..%2fsleep", "/health/../sleep", "/./sleep"):
r = await pub.post(path)
assert r.status_code == 404, path
async def test_raw_traversal_404(stack, backend):
"""Percent-encoded traversal that a normal client would normalise."""
cases = [
("POST", "/v1%2f..%2fsleep"),
("POST", "/v1%2F..%2Fsleep"),
("GET", "/v1/%2e%2e/wake_up"),
("POST", "/v1/%2e%2e%2fcollective_rpc"),
("POST", "/v1//../sleep"),
("GET", "/v1/models/../../is_sleeping"),
]
for method, raw in cases:
status, body = await raw_asgi(stack.public, method, raw,
headers=[("content-type", "application/json")],
body=b"{}")
assert status == 404, (method, raw, body)
assert backend.calls == []
async def test_normalised_traversal_still_reaches_v1(stack, backend):
"""A traversal that lands inside /v1 must still work (not over-block)."""
status, body = await raw_asgi(
stack.public, "POST", "/v1/../v1/chat/completions",
headers=[("content-type", "application/json")],
body=b'{"model": "text"}',
)
assert status == 200, body
assert backend.count("POST vllm-text/v1/chat/completions") == 1
async def test_public_health(pub, backend):
r = await pub.get("/health")
assert r.status_code == 200
body = r.json()
assert body["status"] == "ok"
assert set(body["services"]) == {"text", "ocr", "embed"}
# liveness must not depend on backend state
backend.services["vllm-text"]["reachable"] = False
r = await pub.get("/health")
assert r.status_code == 200
async def test_public_models_lists_all_three(pub, backend):
r = await pub.get("/v1/models")
assert r.status_code == 200
body = r.json()
assert body["object"] == "list"
assert [m["id"] for m in body["data"]] == [
"Qwen3.6-35B-A3B-FP8", "OvisOCR2", "Qwen3-Embedding-8B",
]
# answered by the router itself, no backend contact
assert backend.calls == []
async def test_metrics_disabled_by_default(pub):
assert (await pub.get("/metrics")).status_code == 404
async def test_metrics_enabled_when_configured(stack, pub):
stack.cfg.metrics_enabled = True
r = await pub.get("/metrics")
assert r.status_code == 200
assert "vllm_router_service_depth" in r.text
async def test_unknown_http_method_on_v1(stack):
status, _ = await raw_asgi(stack.public, "PROPFIND", "/v1/chat/completions")
assert status in (404, 405)
async def test_admin_listener_is_a_separate_app(stack):
"""The admin app answers /admin/*; the public app must not."""
status, body = await raw_asgi(stack.admin, "GET", "/admin/status")
assert status == 200
status, _ = await raw_asgi(stack.public, "GET", "/admin/status")
assert status == 404
async def test_request_body_cap(cfg, backend):
"""ROUTER_MAX_BODY_BYTES must be wired as middleware (413, not OOM)."""
cfg.max_body_bytes = 64
public_app, _admin, manager = build_apps(cfg, transport=backend)
ok_body = b'{"model": "text", "messages": []}'
assert len(ok_body) < 64
try:
async with httpx.AsyncClient(transport=httpx.ASGITransport(app=public_app),
base_url="http://router.test") as client:
r = await client.post("/v1/chat/completions", content=ok_body,
headers={"content-type": "application/json"})
assert r.status_code == 200
r = await client.post("/v1/chat/completions", content=ok_body + b" " * 512,
headers={"content-type": "application/json"})
assert r.status_code == 413
finally:
await manager.proxy_client.aclose()
await manager.ctrl_client.aclose()