Initial commit: VMware vSphere API simulator scaffold.

Add the FastAPI app, PostgreSQL migrations, Docker/Helm packaging, API
contracts, docs, client examples, and the unit/integration/compatibility
test suite for local client and tooling labs without a real vCenter.
This commit is contained in:
2026-07-18 04:42:11 +03:00
commit f8d3cbdd59
422 changed files with 361335 additions and 0 deletions
+103
View File
@@ -0,0 +1,103 @@
"""CIS-style asynchronous tasks shared by REST and SOAP."""
from __future__ import annotations
import json
import secrets
from datetime import UTC, datetime
from typing import Any
from app.db.pool import Database
def _pool(database: Database) -> Any:
return database.pool # type: ignore[attr-defined]
async def create_task(
database: Database,
*,
description: str,
service: str,
operation: str,
status: str = "SUCCEEDED",
result: dict[str, Any] | None = None,
error: dict[str, Any] | None = None,
task_id: str | None = None,
) -> str:
resolved_id = task_id or f"task-{secrets.token_hex(8)}"
now = datetime.now(UTC)
completed = now if status in {"SUCCEEDED", "FAILED"} else None
pool = _pool(database)
async with pool.acquire() as conn:
await conn.execute(
"""
INSERT INTO vsphere_tasks
(id, description, status, service, operation, result, error, completed_at)
VALUES ($1, $2, $3, $4, $5, $6::jsonb, $7::jsonb, $8)
ON CONFLICT (id) DO UPDATE SET
description = EXCLUDED.description,
status = EXCLUDED.status,
service = EXCLUDED.service,
operation = EXCLUDED.operation,
result = EXCLUDED.result,
error = EXCLUDED.error,
completed_at = EXCLUDED.completed_at
""",
resolved_id,
description,
status,
service,
operation,
json.dumps(result) if result is not None else None,
json.dumps(error) if error is not None else None,
completed,
)
return resolved_id
async def get_task(database: Database, task_id: str) -> dict[str, Any] | None:
pool = _pool(database)
async with pool.acquire() as conn:
row = await conn.fetchrow("SELECT * FROM vsphere_tasks WHERE id = $1", task_id)
if row is None:
return None
return _row(row)
async def list_tasks(database: Database) -> list[dict[str, Any]]:
pool = _pool(database)
async with pool.acquire() as conn:
rows = await conn.fetch("SELECT * FROM vsphere_tasks ORDER BY created_at DESC LIMIT 200")
return [_row(row) for row in rows]
def _row(row: Any) -> dict[str, Any]:
result = row["result"]
error = row["error"]
if isinstance(result, str):
result = json.loads(result)
if isinstance(error, str):
error = json.loads(error)
status = row["status"]
state = {
"PENDING": "PENDING",
"RUNNING": "RUNNING",
"SUCCEEDED": "SUCCEEDED",
"FAILED": "FAILED",
}.get(status, status)
return {
"task": row["id"],
"description": row["description"],
"status": status,
"state": state,
"service": row["service"],
"operation": row["operation"],
"progress": 100 if status in {"SUCCEEDED", "FAILED"} else 50,
"result": result,
"error": error,
"start_time": row["created_at"].isoformat() if row["created_at"] else None,
"end_time": row["completed_at"].isoformat() if row["completed_at"] else None,
"created_at": row["created_at"].isoformat() if row["created_at"] else None,
"completed_at": row["completed_at"].isoformat() if row["completed_at"] else None,
}