Files
ovirt-api-simulator/app/ovirt/jobs.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

101 lines
3.0 KiB
Python

"""Async job/task helpers for Engine actions — rows are always loaded from Postgres."""
from __future__ import annotations
import json
from datetime import UTC, datetime
from typing import Any
from uuid import uuid4
from asyncpg import Connection
from fastapi import Request, Response
from app.ovirt.repr import action_entity, job_entity
from app.ovirt.serialize import respond
from app.ovirt.settings import (
OPT_DEFAULT_ACTION_STATUS,
OPT_DEFAULT_JOB_STATUS_COMPLETE,
OPT_DEFAULT_JOB_STATUS_STARTED,
OPT_DEFAULT_JOB_STEP_TYPE,
option_value,
)
async def create_job(
conn: Connection,
*,
description: str,
owner_id: Any = None,
auto_complete: bool = True,
action_status: str | None = None,
) -> dict[str, Any]:
job_id = uuid4()
now = datetime.now(UTC)
finished = await option_value(conn, OPT_DEFAULT_JOB_STATUS_COMPLETE)
started = await option_value(conn, OPT_DEFAULT_JOB_STATUS_STARTED)
status = finished if auto_complete else started
ended = now if auto_complete else None
if action_status is None:
action_status = await option_value(conn, OPT_DEFAULT_ACTION_STATUS)
step_type = await option_value(conn, OPT_DEFAULT_JOB_STEP_TYPE)
await conn.execute(
"""INSERT INTO ov_jobs(id, description, status, started, ended, owner_id, data)
VALUES($1, $2, $3, $4, $5, $6, $7::jsonb)""",
job_id,
description,
status,
now,
ended,
owner_id,
json.dumps({"action_status": action_status}),
)
step_id = uuid4()
await conn.execute(
"""INSERT INTO ov_job_steps(id, job_id, description, status, type, number, started, ended)
VALUES($1, $2, $3, $4, $5, 1, $6, $7)""",
step_id,
job_id,
description,
status,
step_type,
now,
ended,
)
row = await conn.fetchrow("SELECT * FROM ov_jobs WHERE id=$1", job_id)
return job_entity(row)
async def complete_job(conn: Connection, job_id: str, *, status: str | None = None) -> None:
now = datetime.now(UTC)
if status is None:
status = await option_value(conn, OPT_DEFAULT_JOB_STATUS_COMPLETE)
await conn.execute(
"UPDATE ov_jobs SET status=$2, ended=$3 WHERE id=$1::uuid",
job_id,
status,
now,
)
await conn.execute(
"UPDATE ov_job_steps SET status=$2, ended=$3 WHERE job_id=$1::uuid",
job_id,
status,
now,
)
async def respond_action(
request: Request,
conn: Connection,
*,
description: str,
owner_id: Any = None,
auto_complete: bool = True,
) -> Response:
"""Persist a job and return an action entity built solely from the DB row."""
job = await create_job(
conn, description=description, owner_id=owner_id, auto_complete=auto_complete
)
row = await conn.fetchrow("SELECT * FROM ov_jobs WHERE id=$1::uuid", job["id"])
return respond(request, element="action", data=action_entity(row))