Expand lab seed tiers, OpenAPI PARAMS, and console DATA/Params UX.

This commit is contained in:
2026-07-18 08:46:39 +03:00
parent f8d3cbdd59
commit 63cc409424
71 changed files with 38380 additions and 796 deletions
+133 -20
View File
@@ -65,19 +65,92 @@ async def create_library(
return lib_id
def _props(value: Any) -> dict[str, Any]:
if isinstance(value, dict):
return value
if isinstance(value, str):
import json
try:
decoded = json.loads(value)
except json.JSONDecodeError:
return {}
return decoded if isinstance(decoded, dict) else {}
return {}
def _library_info(row: Any) -> dict[str, Any]:
props = _props(row["props"])
return {
"id": row["id"],
"name": row["name"],
"description": row["description"] or "",
"type": row["type"],
"creation_time": props.get("creation_time"),
"last_modified_time": props.get("last_modified_time"),
"storage_backings": props.get("storage_backings")
or [{"type": "DATASTORE", "datastore_id": "datastore-31"}],
"state": props.get("state") or "ACTIVE",
"version": str(props.get("version") or "1"),
}
def _library_item_info(row: Any) -> dict[str, Any]:
props = _props(row["props"])
return {
"id": row["id"],
"library_id": row["library_id"],
"name": row["name"],
"type": row["type"],
"description": row["description"] or "",
"content_version": str(props.get("content_version") or "1"),
"creation_time": props.get("creation_time"),
"last_modified_time": props.get("last_modified_time"),
"size": int(props.get("size") or 0),
"cached": bool(props.get("cached", True)),
"security_compliance": bool(props.get("security_compliance", True)),
}
async def list_libraries(database: Database) -> list[dict[str, Any]]:
pool = _pool(database)
async with pool.acquire() as conn:
rows = await conn.fetch("SELECT * FROM vsphere_libraries ORDER BY name")
return [
{
"id": row["id"],
"name": row["name"],
"description": row["description"],
"type": row["type"],
}
for row in rows
]
return [_library_info(row) for row in rows]
async def get_library(database: Database, library_id: str) -> dict[str, Any]:
pool = _pool(database)
async with pool.acquire() as conn:
row = await conn.fetchrow("SELECT * FROM vsphere_libraries WHERE id = $1", library_id)
if row is None:
raise not_found(f"Library {library_id} not found")
return _library_info(row)
async def delete_library(database: Database, library_id: str) -> None:
pool = _pool(database)
async with pool.acquire() as conn:
result = await conn.execute("DELETE FROM vsphere_libraries WHERE id = $1", library_id)
if result == "DELETE 0":
raise not_found(f"Library {library_id} not found")
async def get_library_item(database: Database, item_id: str) -> dict[str, Any]:
pool = _pool(database)
async with pool.acquire() as conn:
row = await conn.fetchrow("SELECT * FROM vsphere_library_items WHERE id = $1", item_id)
if row is None:
raise not_found(f"Library item {item_id} not found")
return _library_item_info(row)
async def delete_library_item(database: Database, item_id: str) -> None:
pool = _pool(database)
async with pool.acquire() as conn:
result = await conn.execute("DELETE FROM vsphere_library_items WHERE id = $1", item_id)
if result == "DELETE 0":
raise not_found(f"Library item {item_id} not found")
async def create_library_item(
@@ -138,16 +211,7 @@ async def list_library_items(database: Database, library_id: str) -> list[dict[s
"SELECT * FROM vsphere_library_items WHERE library_id = $1 ORDER BY name",
library_id,
)
return [
{
"id": row["id"],
"library_id": row["library_id"],
"name": row["name"],
"type": row["type"],
"description": row["description"],
}
for row in rows
]
return [_library_item_info(row) for row in rows]
_LAB_SESSION_ID = "session-lab-1"
@@ -411,6 +475,7 @@ async def deploy_ovf_from_library(
folder: str = "group-v23",
host: str = "host-11",
datastore: str = "datastore-31",
resource_pool: str | None = None,
) -> tuple[str, str]:
pool = _pool(database)
async with pool.acquire() as conn:
@@ -432,6 +497,7 @@ async def deploy_ovf_from_library(
"hardware_version": "VMX_19",
"host": host,
"datastore": datastore,
"resource_pool": resource_pool or "resgroup-22",
"networks": ["network-41"],
"identity": {"name": name},
"deployed_from_library_item": item_id,
@@ -496,15 +562,18 @@ async def put_datastore_file(
)
async def seed_platform_extras(database: Database) -> None:
async def seed_platform_extras(database: Database, *, scale: int = 1) -> None:
"""Idempotent demo libraries/tags/files/sessions when platform tables exist.
Always ensures stable lab IDs so probes and clients hit non-empty GETs:
``lib-local-1``, ``item-ubuntu``, ``cat-lab-1``, ``tag-lab-1``, ``session-lab-1``, …
``scale`` (14) adds proportional extra libraries/items/files for larger profiles.
"""
from app.vsphere.domain import tasks as task_store
scale = max(1, min(int(scale or 1), 8))
# Ensure lab libraries/items even when older random-id rows already exist.
lib = await create_library(
database,
@@ -543,6 +612,23 @@ async def seed_platform_extras(database: Database) -> None:
item_id="item-golden",
)
# Proportional extras for large/big tiers.
for index in range(2, scale + 1):
extra_lib = await create_library(
database,
name=f"Team Library {index}",
description=f"Scaled lab library {index}",
library_id=f"lib-local-{index}",
)
await create_library_item(
database,
library_id=extra_lib,
name=f"template-{index:02d}",
item_type="ovf",
description=f"Scaled template {index}",
item_id=f"item-lab-{index}",
)
env = await tagging.create_category(
database,
name="Environment",
@@ -592,6 +678,25 @@ async def seed_platform_extras(database: Database) -> None:
await tagging.attach_tag(database, prod, "VirtualMachine", "vm-102")
await tagging.attach_tag(database, "tag-lab-1", "VirtualMachine", "vm-101")
# Proportional categories/tags for larger tiers (extras_scale).
for index in range(2, scale + 1):
cat_id = f"cat-scale-{index}"
tag_id = f"tag-scale-{index}"
await tagging.create_category(
database,
name=f"Scale {index}",
description=f"Scaled category {index}",
associable_types=["VirtualMachine", "HostSystem"],
category_id=cat_id,
)
await tagging.create_tag(
database,
category_id=cat_id,
name=f"tier-{index}",
tag_id=tag_id,
)
await tagging.attach_tag(database, tag_id, "VirtualMachine", "vm-101")
await put_datastore_file(
database, "datastore-31", "[datastore1] ISO/ubuntu.iso", size=900000000
)
@@ -602,6 +707,14 @@ async def seed_platform_extras(database: Database) -> None:
await put_datastore_file(
database, "datastore-31", "[datastore1] web-01/web-01.vmdk", size=42949672960
)
for index in range(2, scale + 1):
ds = f"datastore-{30 + min(index, 8)}"
await put_datastore_file(
database,
ds,
f"[ds-{index:02d}] ISO/lab-media-{index}.iso",
size=50_000_000 * index,
)
item_id = _LAB_ITEM_ID
pool = _pool(database)