diff --git a/backend/app/proxmox_actions.py b/backend/app/proxmox_actions.py index 682a514..80eff81 100644 --- a/backend/app/proxmox_actions.py +++ b/backend/app/proxmox_actions.py @@ -1,6 +1,8 @@ from .config import settings from .proxmox_client import _client, _wait_task +_VALID_ACTIONS = {"start", "stop", "shutdown", "reboot"} + def _is_not_found(error: Exception) -> bool: """Определяет ответ Proxmox об отсутствующем госте.""" @@ -10,31 +12,59 @@ def _is_not_found(error: Exception) -> bool: return getattr(response, "status_code", None) == 404 +def _endpoint(client, guest_type: str, vmid: int): + """Возвращает endpoint VM или LXC.""" + node = settings.pve_node + return client.nodes(node).qemu(vmid) if guest_type == "vm" else client.nodes(node).lxc(vmid) + + def delete_guest(guest_type: str, vmid: int) -> None: """Останавливает и удаляет VM/LXC, ожидая завершения задач Proxmox.""" client = _client() node = settings.pve_node - endpoint = client.nodes(node).qemu(vmid) if guest_type == "vm" else client.nodes(node).lxc(vmid) - + endpoint = _endpoint(client, guest_type, vmid) try: current = endpoint.status.current.get() except Exception as error: if _is_not_found(error): return raise - - # Proxmox не удаляет запущенную VM/LXC, поэтому сначала останавливаем её. if current.get("status") == "running": stop_upid = endpoint.status.stop.post() if stop_upid: _wait_task(client, node, stop_upid) - try: delete_upid = endpoint.delete() except Exception as error: if _is_not_found(error): return raise - if delete_upid: _wait_task(client, node, delete_upid) + + +def guest_action(guest_type: str, vmid: int, action: str) -> None: + """Выполняет start, stop, shutdown или reboot.""" + if action not in _VALID_ACTIONS: + raise ValueError("Недопустимое действие") + client = _client() + node = settings.pve_node + endpoint = _endpoint(client, guest_type, vmid) + upid = getattr(endpoint.status, action).post() + if upid: + _wait_task(client, node, upid, timeout=300) + + +def get_live_stats(guest_type: str, vmid: int) -> dict: + """Возвращает CPU, RAM, uptime и фактический статус гостя.""" + client = _client() + status = _endpoint(client, guest_type, vmid).status.current.get() + return { + "status": status.get("status", "unknown"), + "cpu_pct": round(float(status.get("cpu", 0)) * 100, 1), + "memory_used_bytes": int(status.get("mem", 0)), + "memory_total_bytes": int(status.get("maxmem", 0)), + "disk_used_bytes": int(status.get("disk", 0)), + "disk_total_bytes": int(status.get("maxdisk", 0)), + "uptime_seconds": int(status.get("uptime", 0)), + }