Files
proxmox-api-simulator/tests/unit/test_cluster_meta_handlers.py
T
Sergey Antropoff 777926487b Add a stateful Proxmox API console and broad handler coverage beyond the
initial QEMU slice, backed by imported contracts for majors 6–9.
- Implement durable handlers for access/auth, cluster, LXC, storage, HA,
  firewall, Ceph, SDN, ACME, notifications, pools, mapping, and node ops
- Serve an interactive Web UI with catalog browsing, demo seed controls,
  and OpenAPI/help surfaces
- Bundle PVE 6.4-15, 7.4-16, and 8.4.5 contract revisions alongside 9.2.3
- Support in-memory runtime contract Apply (POST /ui/api/contract/apply)
  so /version and /api2 routes follow the selected major until restart
- Expand seed profiles (including demo-cluster), migrations 007–008, TLS
  gateway config, Compose/Makefile tooling, and compatibility evidence
- Tighten .gitignore for macOS, hidden directories (.*/), and local secrets
2026-07-16 01:08:01 +03:00

139 lines
4.2 KiB
Python

"""Mapping / ACME / cluster-config durable handlers."""
from __future__ import annotations
import json
from typing import Any, cast
from uuid import uuid4
from fastapi import FastAPI, Request
from app.api.registry import HandlerRegistry
from app.db.pool import AsyncpgDatabase
from app.handlers.acme import register_acme_handlers
from app.handlers.cluster_config import register_cluster_config_handlers
from app.handlers.mapping import register_mapping_handlers
class MetaPool:
def __init__(self) -> None:
self.metadata: dict[str, Any] = {}
self.nodes = {"pve1": {"status": "online"}}
self.cluster_name = "pve-simulator"
async def fetch(self, query: str, *_arguments: object) -> list[dict[str, Any]]:
if "FROM nodes" in query:
return [{"name": name, "status": data["status"]} for name, data in self.nodes.items()]
raise AssertionError(query)
async def fetchrow(self, query: str, *_arguments: object) -> dict[str, Any] | None:
if "FROM clusters WHERE id" in query:
return {"metadata": json.dumps(self.metadata)}
raise AssertionError(query)
async def fetchval(self, query: str, *arguments: object) -> Any:
if "EXISTS(SELECT 1 FROM nodes" in query:
return str(arguments[0]) in self.nodes
raise AssertionError(query)
async def execute(self, query: str, *arguments: object) -> str:
if "UPDATE clusters SET metadata" in query:
self.metadata = json.loads(str(arguments[1]))
return "UPDATE 1"
if "UPDATE clusters" in query and "SET name" in query:
self.cluster_name = str(arguments[0])
return "UPDATE 1"
if "INSERT INTO nodes" in query:
self.nodes[str(arguments[0])] = {"status": "online"}
return "INSERT 0 1"
if "UPDATE nodes SET status" in query:
self.nodes[str(arguments[0])]["status"] = "offline"
return "UPDATE 1"
raise AssertionError(query)
async def call(
registry: HandlerRegistry, path: str, verb: str, http: Request, inputs: dict[str, Any]
) -> Any:
handler = registry.get(path, verb)
assert handler is not None
return await handler(http, inputs)
def request(pool: MetaPool) -> Request:
app = FastAPI()
app.state.database = cast(AsyncpgDatabase, type("DB", (), {"pool": pool})())
return Request(
{
"type": "http",
"app": app,
"method": "POST",
"path": "/",
"headers": [],
"query_string": b"",
"server": ("test", 80),
"client": ("test", 123),
"scheme": "http",
}
)
async def test_mapping_acme_config_persist() -> None:
registry = HandlerRegistry()
register_mapping_handlers(registry)
register_acme_handlers(registry)
register_cluster_config_handlers(registry)
pool = MetaPool()
http = request(pool)
await call(
registry,
"/cluster/mapping/pci",
"POST",
http,
{"values": {"id": "gpu0", "map": "0000:01:00.0"}, "provided": frozenset()},
)
pci = await call(
registry,
"/cluster/mapping/pci/{id}",
"GET",
http,
{"values": {"id": "gpu0"}, "provided": frozenset()},
)
assert pci["map"] == "0000:01:00.0"
await call(
registry,
"/cluster/acme/account",
"POST",
http,
{
"values": {"name": "default", "contact": "admin@example.com", "eab-hmac-key": "x"},
"provided": frozenset(),
},
)
account = await call(
registry,
"/cluster/acme/account/{name}",
"GET",
http,
{"values": {"name": "default"}, "provided": frozenset()},
)
assert account["name"] == "default"
assert "eab-hmac-key" not in account
await call(
registry,
"/cluster/config",
"POST",
http,
{"values": {"clustername": "lab"}, "provided": frozenset()},
)
assert pool.metadata["cluster_config"]["clustername"] == "lab"
assert pool.cluster_name == "lab"
totem = await call(
registry, "/cluster/config/totem", "GET", http, {"values": {}, "provided": frozenset()}
)
assert totem["cluster_name"] == "lab"
assert uuid4()