Files
ovirt-api-simulator/tools/ovirt_api_inventory/generate_packs.py
T
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

119 lines
3.6 KiB
Python

#!/usr/bin/env python3
"""Generate contracts/ovirt/<series>/ packs from the master catalog."""
from __future__ import annotations
import hashlib
import json
import sys
from datetime import datetime, timezone
from pathlib import Path
ROOT = Path(__file__).resolve().parents[2]
sys.path.insert(0, str(ROOT))
from tools.ovirt_api_inventory.catalog import ( # noqa: E402
SERIES,
SERIES_MAJOR,
SERIES_PRODUCT,
api_version_for_series,
build_operations,
entry_point_links,
)
def emit_series(series: str, out_root: Path) -> dict:
ops = build_operations(series)
series_dir = out_root / series
series_dir.mkdir(parents=True, exist_ok=True)
api_ver = api_version_for_series(series)
product = SERIES_PRODUCT[series]
operations = [
{
"operation_id": op.operation_id,
"method": op.method,
"path": op.path,
"resource_type": op.resource_type,
"collection_key": op.collection_key,
"element": op.element,
"kind": op.kind,
"search": op.search,
"introduced_in": op.introduced_in,
"requires_auth": op.kind != "root",
"status_code": 200 if op.method != "POST" or op.kind == "action" else 201,
"create_status": 201,
"notes": op.notes,
}
for op in ops
]
payload = {
"service": "engine",
"type": "ovirt-engine",
"api_version": api_ver,
"series": series,
"product": product,
"operations": operations,
}
api_path = series_dir / "api.json"
raw = json.dumps(payload, indent=2, sort_keys=True) + "\n"
api_path.write_text(raw)
checksum = hashlib.sha256(raw.encode()).hexdigest()
# Series deltas vs previous
idx = SERIES.index(series)
prev_ops = set()
if idx > 0:
prev = build_operations(SERIES[idx - 1])
prev_ops = {(o.method, o.path) for o in prev}
cur_ops = {(o.method, o.path) for o in ops}
added = sorted(f"{m} {p}" for m, p in (cur_ops - prev_ops))
removed = sorted(f"{m} {p}" for m, p in (prev_ops - cur_ops))
deltas = {
"series": series,
"previous": SERIES[idx - 1] if idx > 0 else None,
"added_count": len(added),
"removed_count": len(removed),
"added": added[:200],
"removed": removed[:200],
}
(series_dir / "deltas.json").write_text(json.dumps(deltas, indent=2) + "\n")
manifest = {
"series": series,
"major": SERIES_MAJOR[series],
"api_version": api_ver,
"product": product,
"operation_count": len(operations),
"service_count": 1,
"services": ["engine"],
"checksum": checksum,
"generated_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
"entry_point_links": entry_point_links(series),
"deltas": {"added": deltas["added_count"], "removed": deltas["removed_count"]},
}
(series_dir / "manifest.json").write_text(json.dumps(manifest, indent=2) + "\n")
return manifest
def main() -> int:
out = ROOT / "contracts" / "ovirt"
out.mkdir(parents=True, exist_ok=True)
summaries = []
for series in SERIES:
man = emit_series(series, out)
summaries.append(man)
print(f"{series}: {man['operation_count']} ops (api v{man['api_version']})")
index = {
"series": summaries,
"generated_at": datetime.now(timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"),
}
(out / "index.json").write_text(json.dumps(index, indent=2) + "\n")
return 0
if __name__ == "__main__":
raise SystemExit(main())