Files
vmware-api-simulator/app/vsphere/domain/inventory_ops.py
T

273 lines
7.7 KiB
Python

"""CRUD for folders, datacenters, clusters, resource pools, hosts, DVS."""
from __future__ import annotations
from typing import Any
from app.db.pool import Database
from app.vsphere import inventory
from app.vsphere.errors import invalid_argument, not_found
async def create_folder(
database: Database,
*,
name: str,
parent: str,
folder_type: str = "VIRTUAL_MACHINE",
) -> str:
parent_obj = await inventory.get_object(database, parent)
if parent_obj is None:
raise not_found(f"Parent {parent} not found")
moid = await inventory.next_moid(database, "group")
# next_moid with group- may not work well; use folder- style
import secrets
moid = f"group-{secrets.token_hex(3)}"
await inventory.upsert_object(
database,
moid=moid,
type_name="Folder",
name=name,
parent_moid=parent,
props={"folder_type": folder_type},
)
return moid
async def create_datacenter(database: Database, *, name: str, folder: str = "group-d1") -> str:
import secrets
parent_obj = await inventory.get_object(database, folder)
if parent_obj is None:
raise not_found(f"Parent {folder} not found")
moid = f"datacenter-{secrets.randbelow(900) + 100}"
host_folder = f"group-h{secrets.randbelow(90) + 10}"
vm_folder = f"group-v{secrets.randbelow(90) + 10}"
ds_folder = f"group-s{secrets.randbelow(90) + 10}"
net_folder = f"group-n{secrets.randbelow(90) + 10}"
await inventory.upsert_object(
database,
moid=moid,
type_name="Datacenter",
name=name,
parent_moid=folder,
props={
"datastore_folder": ds_folder,
"host_folder": host_folder,
"vm_folder": vm_folder,
"network_folder": net_folder,
},
)
for child_moid, child_name, ftype in (
(host_folder, "host", "HOST"),
(vm_folder, "vm", "VIRTUAL_MACHINE"),
(ds_folder, "datastore", "DATASTORE"),
(net_folder, "network", "NETWORK"),
):
await inventory.upsert_object(
database,
moid=child_moid,
type_name="Folder",
name=child_name,
parent_moid=moid,
props={"folder_type": ftype},
)
return moid
async def create_cluster(
database: Database,
*,
name: str,
folder: str = "group-h23",
drs_enabled: bool = True,
ha_enabled: bool = True,
) -> str:
import secrets
parent_obj = await inventory.get_object(database, folder)
if parent_obj is None:
raise not_found(f"Parent {folder} not found")
moid = f"domain-c{secrets.randbelow(900) + 100}"
rp = f"resgroup-{secrets.randbelow(900) + 100}"
await inventory.upsert_object(
database,
moid=moid,
type_name="ClusterComputeResource",
name=name,
parent_moid=folder,
props={"drs_enabled": drs_enabled, "ha_enabled": ha_enabled, "resource_pool": rp},
)
await inventory.upsert_object(
database,
moid=rp,
type_name="ResourcePool",
name="Resources",
parent_moid=moid,
props={"cpu_limit_mhz": -1, "memory_limit_mib": -1},
)
return moid
async def create_resource_pool(
database: Database,
*,
name: str,
parent: str,
) -> str:
parent_obj = await inventory.get_object(database, parent)
if parent_obj is None:
raise not_found(f"Parent {parent} not found")
import secrets
moid = f"resgroup-{secrets.randbelow(900) + 100}"
await inventory.upsert_object(
database,
moid=moid,
type_name="ResourcePool",
name=name,
parent_moid=parent,
props={"cpu_limit_mhz": -1, "memory_limit_mib": -1},
)
return moid
async def rename_object(database: Database, moid: str, name: str) -> None:
obj = await inventory.get_object(database, moid)
if obj is None:
raise not_found(f"Object {moid} not found")
await inventory.upsert_object(
database,
moid=obj.moid,
type_name=obj.type,
name=name,
parent_moid=obj.parent_moid,
props=obj.props,
)
async def move_object(database: Database, moid: str, parent: str) -> None:
obj = await inventory.get_object(database, moid)
if obj is None:
raise not_found(f"Object {moid} not found")
parent_obj = await inventory.get_object(database, parent)
if parent_obj is None:
raise not_found(f"Parent {parent} not found")
await inventory.upsert_object(
database,
moid=obj.moid,
type_name=obj.type,
name=obj.name,
parent_moid=parent,
props=obj.props,
)
async def delete_managed(database: Database, moid: str) -> None:
obj = await inventory.get_object(database, moid)
if obj is None:
raise not_found(f"Object {moid} not found")
# Protect the lab seed spine so surface/matrix probes cannot empty the inventory dump.
if moid in _SEED_PROTECTED_MOIDS or _is_seed_host_or_named_vm(moid, obj):
raise invalid_argument(f"Cannot delete protected seed object {moid}")
children = [
child for child in await inventory.list_objects(database) if child.parent_moid == moid
]
if children:
raise invalid_argument(f"Object {moid} still has children")
await inventory.delete_object(database, moid)
# Stable MOIDs from profiles._topology / small named VMs (all seed sizes).
_SEED_PROTECTED_MOIDS = frozenset(
{
"group-d1",
"datacenter-21",
"group-h23",
"group-v23",
"group-s23",
"group-n23",
"domain-c21",
"resgroup-22",
"group-v100",
"group-v101",
"group-v102",
"network-41",
"dvs-51",
*(f"datastore-{30 + n}" for n in range(1, 9)),
*(f"dvportgroup-{40 + n}" for n in range(2, 9)),
*(f"group-v{103 + n}" for n in range(0, 8)),
"vm-101",
"vm-102",
"vm-103",
"vm-104",
"vm-105",
}
)
def _is_seed_host_or_named_vm(moid: str, obj: Any) -> bool:
if obj.type == "HostSystem" and moid.startswith("host-"):
# Seed hosts are host-11..host-N; probe hosts use other patterns if any.
try:
return 11 <= int(moid.split("-", 1)[1]) <= 40
except ValueError:
return False
return False
async def set_host_maintenance(database: Database, host: str, enabled: bool) -> dict[str, Any]:
obj = await inventory.get_object(database, host)
if obj is None or obj.type != "HostSystem":
raise not_found(f"Host {host} not found")
props = dict(obj.props)
props["connection_state"] = "CONNECTED"
props["maintenance_mode"] = enabled
await inventory.update_props(database, host, props)
return {"host": host, "maintenance_mode": enabled}
async def create_dvs(
database: Database,
*,
name: str,
folder: str = "group-n23",
) -> str:
import secrets
moid = f"dvs-{secrets.randbelow(900) + 100}"
await inventory.upsert_object(
database,
moid=moid,
type_name="VmwareDistributedVirtualSwitch",
name=name,
parent_moid=folder,
props={"version": "8.0.0", "num_ports": 128},
)
return moid
async def create_dvpg(
database: Database,
*,
name: str,
dvs: str,
vlan_id: int = 0,
) -> str:
parent = await inventory.get_object(database, dvs)
if parent is None:
raise not_found(f"DVS {dvs} not found")
import secrets
moid = f"dvportgroup-{secrets.randbelow(900) + 100}"
await inventory.upsert_object(
database,
moid=moid,
type_name="DistributedVirtualPortgroup",
name=name,
parent_moid=dvs,
props={"type": "DISTRIBUTED_PORTGROUP", "vlan_id": vlan_id, "dvs": dvs},
)
return moid