Expand lab seed tiers, OpenAPI PARAMS, and console DATA/Params UX.
This commit is contained in:
+133
-20
@@ -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`` (1–4) 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)
|
||||
|
||||
Reference in New Issue
Block a user