Files
inecs 6033967e6a Initial commit: stateful OpenStack API laboratory simulator.
Ship Keystone auth, multi-service handlers (Yoga→Dalmatian), Compose/Helm
packaging, API contract packs, and pytest/Pulumi coverage labs.
2026-07-18 04:26:48 +03:00

62 lines
2.0 KiB
Python

"""Port-aware root / version discovery (and HTML console for browsers)."""
from __future__ import annotations
from typing import Annotated
from asyncpg import Connection
from fastapi import APIRouter, Depends, Request
from fastapi.responses import HTMLResponse, JSONResponse
from app.openstack.db_docs import require_doc
from app.openstack.deps import get_conn
from app.openstack.dispatch import resolve_service
from app.web.assets import console_html
router = APIRouter(tags=["OpenStack"])
def _service_name(request: Request) -> str:
headers = {k.lower(): v for k, v in request.headers.items()}
# Prefer explicit gateway port/service; also pass path for disambiguation.
resolved = resolve_service(headers, path=request.url.path)
if resolved and resolved not in ("", "https"):
return resolved
# Fallback: Host:port when proxies strip/alter X-Forwarded-Port.
host = headers.get("host") or ""
if ":" in host:
try:
port = int(host.rsplit(":", 1)[1])
except ValueError:
port = None
if port is not None:
from app.openstack.dispatch import _PORT_TO_SERVICE
by_host = _PORT_TO_SERVICE.get(port)
if by_host:
return by_host
return "keystone"
def _wants_html(request: Request) -> bool:
accept = (request.headers.get("accept") or "*/*").lower()
if accept.startswith("application/json"):
return False
return "text/html" in accept.split(",")[0] or (
"text/html" in accept and "application/json" not in accept
)
async def _json_versions(conn: Connection, name: str) -> dict[str, object]:
return await require_doc(conn, service=name, resource_type="discovery_version", name="default")
@router.get("/")
async def root(
request: Request,
conn: Annotated[Connection, Depends(get_conn)],
):
if _wants_html(request):
return HTMLResponse(console_html(), headers={"Cache-Control": "no-store"})
return JSONResponse(await _json_versions(conn, _service_name(request)))