Files
inecs cbd0adca91 Initial release of the oVirt/RHV Engine API simulator.
Stateful FastAPI lab with contract packs, Compose/Helm, Docker Hub release
targets, and Pulumi coverage across all Engine series (GET/POST/PUT/DELETE/HEAD).
2026-07-18 04:49:28 +03:00

56 lines
1.8 KiB
Python

"""Resolve Engine API version (v3/v4) and active series pack."""
from __future__ import annotations
import re
from dataclasses import dataclass
from fastapi import Request
from app.ovirt.errors import OVirtError
_VERSION_PREFIX = re.compile(r"^/ovirt-engine/api/(v[34])(/.*)?$")
@dataclass(frozen=True)
class ApiVersionContext:
api_version: str # "3" or "4"
series: str
path_suffix: str # path after /ovirt-engine/api[/vN]
def resolve_api_version(request: Request, default_series: str = "4.5") -> ApiVersionContext:
path = request.url.path
header = (request.headers.get("version") or "").strip()
series = getattr(request.app.state, "ovirt_series", None) or default_series
m = _VERSION_PREFIX.match(path)
if m:
ver = m.group(1)[1:] # strip v
rest = m.group(2) or ""
return ApiVersionContext(api_version=ver, series=series, path_suffix=rest or "/")
if path.startswith("/ovirt-engine/api"):
rest = path[len("/ovirt-engine/api") :] or "/"
if header in {"3", "4"}:
return ApiVersionContext(api_version=header, series=series, path_suffix=rest)
# default version 4 for 4.x series, 3 for 3.x
default = "3" if str(series).startswith("3.") else "4"
return ApiVersionContext(api_version=default, series=series, path_suffix=rest)
raise OVirtError("NotFound", f"Unknown path {path}", status_code=404)
def strip_api_prefix(path: str) -> str:
"""Normalize to collection-relative path starting with /."""
for prefix in (
"/ovirt-engine/api/v4",
"/ovirt-engine/api/v3",
"/ovirt-engine/api",
):
if path.startswith(prefix):
rest = path[len(prefix) :] or "/"
return rest if rest.startswith("/") else f"/{rest}"
return path