cbd0adca91
Stateful FastAPI lab with contract packs, Compose/Helm, Docker Hub release targets, and Pulumi coverage across all Engine series (GET/POST/PUT/DELETE/HEAD).
101 lines
3.0 KiB
Python
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))
|