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

199 lines
7.3 KiB
Python

"""Engine runtime settings stored in `ov_api_objects` (collection=options)."""
from __future__ import annotations
import json
from typing import Any
from asyncpg import Connection
from app.ovirt.ids import stable_id
# Seeded option names (values live only in Postgres).
OPT_DEFAULT_VM_MEMORY = "DEFAULT_VM_MEMORY"
OPT_DEFAULT_DISK_SIZE = "DEFAULT_DISK_SIZE"
OPT_DEFAULT_HOST_MEMORY = "DEFAULT_HOST_MEMORY"
OPT_DEFAULT_HOST_CPU_CORES = "DEFAULT_HOST_CPU_CORES"
OPT_DEFAULT_CPU_SOCKETS = "DEFAULT_CPU_SOCKETS"
OPT_DEFAULT_CPU_CORES = "DEFAULT_CPU_CORES"
OPT_DEFAULT_CPU_THREADS = "DEFAULT_CPU_THREADS"
OPT_DEFAULT_NIC_INTERFACE = "DEFAULT_NIC_INTERFACE"
OPT_DEFAULT_DISK_INTERFACE = "DEFAULT_DISK_INTERFACE"
OPT_DEFAULT_DISK_FORMAT = "DEFAULT_DISK_FORMAT"
OPT_DEFAULT_VM_TYPE = "DEFAULT_VM_TYPE"
OPT_DEFAULT_OS_TYPE = "DEFAULT_OS_TYPE"
OPT_DEFAULT_VM_STATUS = "DEFAULT_VM_STATUS"
OPT_DEFAULT_HOST_STATUS = "DEFAULT_HOST_STATUS"
OPT_DEFAULT_DC_STATUS = "DEFAULT_DC_STATUS"
OPT_DEFAULT_SD_STATUS = "DEFAULT_SD_STATUS"
OPT_DEFAULT_HOST_ADDRESS = "DEFAULT_HOST_ADDRESS"
OPT_DEFAULT_CLUSTER_CPU_TYPE = "DEFAULT_CLUSTER_CPU_TYPE"
OPT_DEFAULT_SD_TYPE = "DEFAULT_SD_TYPE"
OPT_DEFAULT_STORAGE_TYPE = "DEFAULT_STORAGE_TYPE"
OPT_DEFAULT_SD_AVAILABLE = "DEFAULT_SD_AVAILABLE"
OPT_DEFAULT_STORAGE_CONNECTION_TYPE = "DEFAULT_STORAGE_CONNECTION_TYPE"
OPT_DEFAULT_MAC_PREFIX = "DEFAULT_MAC_PREFIX"
OPT_DEFAULT_NIC_NAME = "DEFAULT_NIC_NAME"
OPT_DEFAULT_SNAPSHOT_DESCRIPTION = "DEFAULT_SNAPSHOT_DESCRIPTION"
OPT_DEFAULT_TAG_NAME = "DEFAULT_TAG_NAME"
OPT_DEFAULT_API_OBJECT_STATUS = "DEFAULT_API_OBJECT_STATUS"
OPT_DEFAULT_ACTION_STATUS = "DEFAULT_ACTION_STATUS"
OPT_DEFAULT_JOB_STATUS_COMPLETE = "DEFAULT_JOB_STATUS_COMPLETE"
OPT_DEFAULT_JOB_STATUS_STARTED = "DEFAULT_JOB_STATUS_STARTED"
OPT_DEFAULT_JOB_STEP_TYPE = "DEFAULT_JOB_STEP_TYPE"
OPT_DEFAULT_AUTH_DOMAIN = "DEFAULT_AUTH_DOMAIN"
OPT_DEFAULT_API_SCOPE = "DEFAULT_API_SCOPE"
OPT_DEFAULT_TOKEN_TYPE = "DEFAULT_TOKEN_TYPE"
OPT_DEFAULT_USER_ROLE = "DEFAULT_USER_ROLE"
OPT_OAUTH_TOKEN_TTL_SECONDS = "OAUTH_TOKEN_TTL_SECONDS"
OPT_BASIC_SESSION_TTL_SECONDS = "BASIC_SESSION_TTL_SECONDS"
OPT_SD_ATTACH_ACTIVE = "SD_ATTACH_STATUS_ACTIVE"
OPT_SD_ATTACH_MAINTENANCE = "SD_ATTACH_STATUS_MAINTENANCE"
OPT_PRODUCT_NAME = "PRODUCT_NAME"
OPT_PRODUCT_VENDOR = "PRODUCT_VENDOR"
OPT_PRODUCT_MAJOR = "PRODUCT_MAJOR"
OPT_PRODUCT_MINOR = "PRODUCT_MINOR"
OPT_PRODUCT_BUILD = "PRODUCT_BUILD"
OPT_PRODUCT_REVISION = "PRODUCT_REVISION"
OPT_PRODUCT_FULL = "PRODUCT_FULL"
OPT_ENGINE_API_DEFAULT_VERSION = "ENGINE_API_DEFAULT_VERSION"
OPT_VM_ACTION_STATUS_MAP = "VM_ACTION_STATUS_MAP"
OPT_HOST_ACTION_STATUS_MAP = "HOST_ACTION_STATUS_MAP"
_VM_ACTION_MAP = {
"start": "up",
"stop": "down",
"shutdown": "down",
"reboot": "up",
"suspend": "suspended",
"migrate": "up",
"cancelmigration": "up",
"maintenance": "down",
"logon": "up",
"freeze_filesystems": "up",
"thaw_filesystems": "up",
}
_HOST_ACTION_MAP = {
"activate": "up",
"deactivate": "maintenance",
"approve": "up",
"install": "up",
"fence": "down",
"refresh": "up",
"upgrade": "up",
"upgradecheck": "up",
"commitnetconfig": "up",
"enrollcertificate": "up",
"iscsidiscover": "up",
"iscsilogin": "up",
"unregisteredstoragedomainsdiscover": "up",
}
_DEFAULT_OPTIONS: list[tuple[str, str]] = [
(OPT_DEFAULT_VM_MEMORY, str(1024**3)),
(OPT_DEFAULT_DISK_SIZE, str(10 * 1024**3)),
(OPT_DEFAULT_HOST_MEMORY, str(64 * 1024**3)),
(OPT_DEFAULT_HOST_CPU_CORES, "16"),
(OPT_DEFAULT_CPU_SOCKETS, "1"),
(OPT_DEFAULT_CPU_CORES, "1"),
(OPT_DEFAULT_CPU_THREADS, "1"),
(OPT_DEFAULT_NIC_INTERFACE, "virtio"),
(OPT_DEFAULT_DISK_INTERFACE, "virtio_scsi"),
(OPT_DEFAULT_DISK_FORMAT, "cow"),
(OPT_DEFAULT_VM_TYPE, "server"),
(OPT_DEFAULT_OS_TYPE, "other"),
(OPT_DEFAULT_VM_STATUS, "down"),
(OPT_DEFAULT_HOST_STATUS, "up"),
(OPT_DEFAULT_DC_STATUS, "up"),
(OPT_DEFAULT_SD_STATUS, "active"),
(OPT_DEFAULT_HOST_ADDRESS, "127.0.0.1"),
(OPT_DEFAULT_CLUSTER_CPU_TYPE, "Intel Conroe Family"),
(OPT_DEFAULT_SD_TYPE, "data"),
(OPT_DEFAULT_STORAGE_TYPE, "nfs"),
(OPT_DEFAULT_SD_AVAILABLE, str(1024**4)),
(OPT_DEFAULT_STORAGE_CONNECTION_TYPE, "nfs"),
(OPT_DEFAULT_MAC_PREFIX, "00:1a:4a"),
(OPT_DEFAULT_NIC_NAME, "nic1"),
(OPT_DEFAULT_SNAPSHOT_DESCRIPTION, "snapshot"),
(OPT_DEFAULT_TAG_NAME, "tag"),
(OPT_DEFAULT_API_OBJECT_STATUS, "ok"),
(OPT_DEFAULT_ACTION_STATUS, "complete"),
(OPT_DEFAULT_JOB_STATUS_COMPLETE, "finished"),
(OPT_DEFAULT_JOB_STATUS_STARTED, "started"),
(OPT_DEFAULT_JOB_STEP_TYPE, "executing"),
(OPT_DEFAULT_AUTH_DOMAIN, "internal"),
(OPT_DEFAULT_API_SCOPE, "ovirt-app-api"),
(OPT_DEFAULT_TOKEN_TYPE, "bearer"),
(OPT_DEFAULT_USER_ROLE, "UserRole"),
(OPT_OAUTH_TOKEN_TTL_SECONDS, "3600"),
(OPT_BASIC_SESSION_TTL_SECONDS, "7200"),
(OPT_SD_ATTACH_ACTIVE, "active"),
(OPT_SD_ATTACH_MAINTENANCE, "maintenance"),
(OPT_PRODUCT_NAME, "oVirt Engine"),
(OPT_PRODUCT_VENDOR, "ovirt.org"),
(OPT_PRODUCT_MAJOR, "4"),
(OPT_PRODUCT_MINOR, "5"),
(OPT_PRODUCT_BUILD, "0"),
(OPT_PRODUCT_REVISION, "0"),
(OPT_PRODUCT_FULL, "4.5.0"),
(OPT_ENGINE_API_DEFAULT_VERSION, "4"),
(OPT_VM_ACTION_STATUS_MAP, json.dumps(_VM_ACTION_MAP, separators=(",", ":"))),
(OPT_HOST_ACTION_STATUS_MAP, json.dumps(_HOST_ACTION_MAP, separators=(",", ":"))),
]
async def seed_engine_options(conn: Connection) -> None:
"""Upsert Engine options used by handlers (create defaults + product_info)."""
for name, value in _DEFAULT_OPTIONS:
await conn.execute(
"""INSERT INTO ov_api_objects(id, collection, name, status, data)
VALUES($1,'options',$2,'ok',$3::jsonb)
ON CONFLICT (id) DO UPDATE SET
data=EXCLUDED.data, name=EXCLUDED.name, status='ok', updated_at=now()""",
stable_id("obj", "options", name),
name,
json.dumps({"name": name, "value": value, "description": f"engine option {name}"}),
)
async def option_value(conn: Connection, name: str) -> str:
row = await conn.fetchrow(
"""SELECT data FROM ov_api_objects
WHERE collection='options' AND name=$1""",
name,
)
if row is None:
raise RuntimeError(f"missing engine option in DB: {name} (reload seed)")
data = row["data"]
if isinstance(data, str):
data = json.loads(data)
data = dict(data or {})
if "value" in data and data["value"] is not None:
return str(data["value"])
raise RuntimeError(f"engine option {name} has no value in DB")
async def option_int(conn: Connection, name: str) -> int:
return int(await option_value(conn, name))
async def option_json(conn: Connection, name: str) -> Any:
raw = await option_value(conn, name)
return json.loads(raw)
async def product_info_from_db(conn: Connection) -> dict[str, Any]:
return {
"name": await option_value(conn, OPT_PRODUCT_NAME),
"vendor": await option_value(conn, OPT_PRODUCT_VENDOR),
"version": {
"major": await option_value(conn, OPT_PRODUCT_MAJOR),
"minor": await option_value(conn, OPT_PRODUCT_MINOR),
"build": await option_value(conn, OPT_PRODUCT_BUILD),
"revision": await option_value(conn, OPT_PRODUCT_REVISION),
"full_version": await option_value(conn, OPT_PRODUCT_FULL),
},
}