"""Legacy `/rest/...` JSON wrappers mirroring Automation API `/api` paths.""" from __future__ import annotations from typing import Any from fastapi import APIRouter, Depends, Query, Request, Response from app.db.pool import Database from app.dependencies import get_database from app.vsphere.domain import vm_ops from app.vsphere.errors import invalid_argument from app.vsphere.rest import router as core from app.vsphere.rest import tagging_rest from app.vsphere.security.authz import require_privilege, require_read from app.vsphere.security.session import SessionInfo router = APIRouter(tags=["vSphere Legacy REST"]) def _value(payload: Any) -> dict[str, Any]: return {"value": payload} @router.get("/rest/vcenter/vm") async def rest_list_vms( database: Database = Depends(get_database), session: SessionInfo = Depends(require_read), names: list[str] | None = Query(default=None), power_states: list[str] | None = Query(default=None), hosts: list[str] | None = Query(default=None), folders: list[str] | None = Query(default=None), limit: int | None = Query(default=None, ge=1, le=5000), cursor: int = Query(default=0, ge=0), ) -> dict[str, Any]: payload = await core.list_vms( database=database, _=session, names=names, power_states=power_states, hosts=hosts, folders=folders, datacenters=None, clusters=None, resource_pools=None, limit=limit, cursor=cursor, ) return _value(payload) @router.get("/rest/vcenter/vm/{vm}") async def rest_get_vm( vm: str, database: Database = Depends(get_database), session: SessionInfo = Depends(require_read), ) -> dict[str, Any]: return _value(await core.get_vm(vm=vm, database=database, _=session)) @router.get("/rest/vcenter/host") async def rest_list_hosts( database: Database = Depends(get_database), session: SessionInfo = Depends(require_read), ) -> dict[str, Any]: return _value(await core.list_hosts(database=database, _=session)) @router.get("/rest/vcenter/datastore") async def rest_list_datastores( database: Database = Depends(get_database), session: SessionInfo = Depends(require_read), ) -> dict[str, Any]: return _value(await core.list_datastores(database=database, _=session)) @router.get("/rest/vcenter/network") async def rest_list_networks( database: Database = Depends(get_database), session: SessionInfo = Depends(require_read), ) -> dict[str, Any]: return _value(await core.list_networks(database=database, _=session)) @router.get("/rest/vcenter/datacenter") async def rest_list_datacenters( database: Database = Depends(get_database), session: SessionInfo = Depends(require_read), ) -> dict[str, Any]: return _value(await core.list_datacenters(database=database, _=session)) @router.get("/rest/vcenter/cluster") async def rest_list_clusters( database: Database = Depends(get_database), session: SessionInfo = Depends(require_read), ) -> dict[str, Any]: return _value(await core.list_clusters(database=database, _=session)) @router.get("/rest/appliance/system/version") async def rest_appliance_version( request: Request, database: Database = Depends(get_database), _: SessionInfo = Depends(require_read), ) -> dict[str, Any]: return _value(await core.appliance_version(request=request, database=database)) @router.post("/rest/vcenter/vm/{vm}/power") async def rest_power_vm( vm: str, action: str = Query(...), database: Database = Depends(get_database), _: SessionInfo = Depends(require_privilege("VirtualMachine.Interact.PowerOn")), ) -> dict[str, Any]: task_id = await vm_ops.set_power(database, vm, action.lower()) return _value({"task": task_id}) # --- CIS tagging (govmomi / terraform-provider-vsphere / pulumi-vsphere) --- @router.get("/rest/com/vmware/cis/tagging/category") async def rest_list_categories( database: Database = Depends(get_database), session: SessionInfo = Depends(require_read), ) -> dict[str, Any]: return _value(await tagging_rest.list_categories(database=database, _=session)) @router.post("/rest/com/vmware/cis/tagging/category") async def rest_category_action( body: dict[str, Any] | None = None, action: str | None = Query(default=None, alias="~action"), database: Database = Depends(get_database), session: SessionInfo = Depends(require_privilege("InventoryService.Tagging.CreateCategory")), ) -> Any: payload = body or {} act = (action or "create").lower() if act == "create": return _value( await tagging_rest.create_category(body=payload, database=database, _=session) ) raise invalid_argument(f"unsupported ~action {act}") @router.get("/rest/com/vmware/cis/tagging/category/{category_id}") async def rest_get_category( category_id: str, database: Database = Depends(get_database), session: SessionInfo = Depends(require_read), ) -> dict[str, Any]: return _value( await tagging_rest.get_category(category_id=category_id, database=database, _=session) ) @router.delete("/rest/com/vmware/cis/tagging/category/{category_id}") async def rest_delete_category( category_id: str, database: Database = Depends(get_database), session: SessionInfo = Depends(require_privilege("InventoryService.Tagging.CreateCategory")), ) -> Response: return await tagging_rest.delete_category(category_id=category_id, database=database, _=session) @router.get("/rest/com/vmware/cis/tagging/tag") async def rest_list_tags( database: Database = Depends(get_database), session: SessionInfo = Depends(require_read), ) -> dict[str, Any]: return _value(await tagging_rest.list_tags(database=database, _=session)) @router.post("/rest/com/vmware/cis/tagging/tag") async def rest_tag_action( body: dict[str, Any] | None = None, action: str | None = Query(default=None, alias="~action"), database: Database = Depends(get_database), session: SessionInfo = Depends(require_privilege("InventoryService.Tagging.CreateTag")), ) -> Any: payload = body or {} act = (action or "create").lower() if act == "create": return _value(await tagging_rest.create_tag(body=payload, database=database, _=session)) raise invalid_argument(f"unsupported ~action {act}") @router.get("/rest/com/vmware/cis/tagging/tag/{tag_id}") async def rest_get_tag( tag_id: str, database: Database = Depends(get_database), session: SessionInfo = Depends(require_read), ) -> dict[str, Any]: return _value(await tagging_rest.get_tag(tag_id=tag_id, database=database, _=session)) @router.delete("/rest/com/vmware/cis/tagging/tag/{tag_id}") async def rest_delete_tag( tag_id: str, database: Database = Depends(get_database), session: SessionInfo = Depends(require_privilege("InventoryService.Tagging.CreateTag")), ) -> Response: return await tagging_rest.delete_tag(tag_id=tag_id, database=database, _=session) @router.post("/rest/com/vmware/cis/tagging/tag-association") async def rest_tag_association( request: Request, body: dict[str, Any] | None = None, action: str | None = Query(default=None, alias="~action"), database: Database = Depends(get_database), session: SessionInfo = Depends(require_privilege("InventoryService.Tagging.AttachTag")), ) -> Any: """govmomi/terraform use ``?~action=`` instead of JSON ``action``.""" payload = dict(body or {}) # Some clients send ``?~action=``; FastAPI alias can miss ``~`` — also read raw query. resolved = ( action or request.query_params.get("~action") or request.query_params.get("action") or payload.get("action") ) if resolved: payload["action"] = resolved result = await tagging_rest.tag_association( body=payload, action=str(resolved) if resolved else None, database=database, _=session, ) if isinstance(result, Response): return result return _value(result)