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.
This commit is contained in:
2026-07-18 04:26:48 +03:00
commit 6033967e6a
509 changed files with 464404 additions and 0 deletions
+109
View File
@@ -0,0 +1,109 @@
"""Per-path OpenStack contract registration (Proxmox-style)."""
from __future__ import annotations
from fastapi import FastAPI
from fastapi.routing import APIRoute
from app.openstack.contract_loader import ensure_loaded, load_series_pack
from app.openstack.mount import build_openstack_handlers, mount_openstack_routes
from app.openstack.registry import (
HandlerRegistry,
normalize_path_template,
register_specialized_handlers,
)
from app.openstack.routes import nova
from app.openstack.schema_engine import remount_schema_services
def test_normalize_path_template_collapses_param_names() -> None:
assert normalize_path_template("/v2.1/servers/{id}") == normalize_path_template(
"/v2.1/servers/{server_id}"
)
assert normalize_path_template("/v1/{account}/{container}/{object}") == normalize_path_template(
"/v1/{account}/{container}/{object_name:path}"
)
def test_swift_object_handler_resolves_from_contract_path() -> None:
registry = build_openstack_handlers()
assert registry.get("swift", "/v1/{account}/{container}/{object}", "GET") is not None
assert registry.get("swift", "/v1/{account}/{container}/{object}", "PUT") is not None
def test_handler_registry_structural_lookup() -> None:
registry = HandlerRegistry()
async def handler(request): # noqa: ANN001
return request
registry.register("nova", "/v2.1/servers/{server_id}", "GET", handler)
found = registry.get("nova", "/v2.1/servers/{id}", "GET")
assert found is handler
def test_specialized_handlers_imported_from_nova_router() -> None:
registry = HandlerRegistry()
count = register_specialized_handlers(registry, "nova", nova.router)
assert count > 0
assert registry.get("nova", "/v2.1/servers", "GET") is not None
assert registry.get("nova", "/v2.1/servers/{id}", "GET") is not None
def test_mount_registers_one_route_per_unique_method_path() -> None:
app = FastAPI()
mount_openstack_routes(app, series="dalmatian")
packs = load_series_pack("dalmatian")
expected = 0
for pack in packs.values():
expected += len({(op.method, op.path) for op in pack.operations})
contract_routes = [
route
for route in app.router.routes
if isinstance(route, APIRoute)
and isinstance(route.name, str)
and route.name.startswith("os-contract:")
]
# Contract paths plus specialized-only aliases (trailing slash, PUT tags, …).
assert len(contract_routes) >= expected
assert app.state.openstack_schema_ops == len(contract_routes)
# name format: os-contract:{service}:{METHOD}:{path}
mounted_ops = set()
for route in contract_routes:
rest = route.name[len("os-contract:") :]
_service, _, remainder = rest.partition(":")
method, _, path = remainder.partition(":")
mounted_ops.add((method, path))
for pack in packs.values():
for op in pack.operations:
assert (op.method, op.path) in mounted_ops
# No legacy schema-* route names.
assert not any(
isinstance(getattr(r, "name", None), str) and str(r.name).startswith("schema-")
for r in app.router.routes
)
def test_remount_preserves_handlers_and_route_count() -> None:
app = FastAPI()
mount_openstack_routes(app, series="dalmatian")
handlers = app.state.openstack_handlers
assert isinstance(handlers, HandlerRegistry)
before = app.state.openstack_schema_ops
ensure_loaded("caracal")
summary = remount_schema_services(app, "caracal")
assert app.state.openstack_handlers is handlers
assert summary["routes_mounted"] == app.state.openstack_schema_ops
assert app.state.openstack_schema_ops > 0
# Switching series rebuilds routes; count may differ by series deltas.
assert isinstance(before, int)
def test_build_openstack_handlers_covers_core_services() -> None:
registry = build_openstack_handlers()
for service in ("keystone", "nova", "neutron", "glance", "cinder"):
keys = [k for k in registry.keys() if k[0] == service]
assert keys, f"expected handlers for {service}"