fix(vms): auto-stop running VM/CT before destroy

The destroy endpoints returned 400 'Cannot delete a running container.
Stop it first.' when the user clicked Destroy on a running instance.
Since the destroy dialog already requires typing the instance name to
confirm, the action is unambiguously intentional — now both endpoints
issue stop_container/stop_vm with force=True, wait up to 15s for the
status to leave 'running', and only then proceed with deletion.
This commit is contained in:
markmorado
2026-05-06 21:11:15 +02:00
parent 9da65a46aa
commit a92cb0df33

View File

@@ -700,10 +700,22 @@ async def delete_vm(
if not client.is_connected():
raise HTTPException(status_code=503, detail=t("failed_to_connect", lang))
# Проверяем статус VM
# Auto-stop running VM before destroy (user already typed the name to confirm)
status = client.get_vm_status(node, vmid)
if status and isinstance(status, dict) and status.get('status') == 'running':
raise HTTPException(status_code=400, detail=t("cannot_delete_running_vm", lang))
logger.info(f"VM {vmid} is running, stopping before delete...")
try:
client.stop_vm(node, vmid, force=True)
except Exception as _se:
logger.warning(f"stop_vm({vmid}) failed: {_se}")
import time as _t
for _ in range(30):
_t.sleep(0.5)
st = client.get_vm_status(node, vmid)
if not st or not isinstance(st, dict) or st.get('status') != 'running':
break
else:
raise HTTPException(status_code=400, detail=t("cannot_delete_running_vm", lang))
# Сохраняем конфигурацию VM в базу перед удалением (если не force)
if not force:
@@ -1096,10 +1108,23 @@ async def delete_container(
if not client.is_connected():
raise HTTPException(status_code=503, detail=t("failed_to_connect", lang))
# Проверяем статус контейнера
# Auto-stop running container before destroy (user already typed the name to confirm)
status = client.get_container_status(node, vmid)
if status and isinstance(status, dict) and status.get('status') == 'running':
raise HTTPException(status_code=400, detail=t("cannot_delete_running_container", lang))
logger.info(f"Container {vmid} is running, stopping before delete...")
try:
client.stop_container(node, vmid, force=True)
except Exception as _se:
logger.warning(f"stop_container({vmid}) failed: {_se}")
# Wait up to 15s for it to actually stop
import time as _t
for _ in range(30):
_t.sleep(0.5)
st = client.get_container_status(node, vmid)
if not st or not isinstance(st, dict) or st.get('status') != 'running':
break
else:
raise HTTPException(status_code=400, detail=t("cannot_delete_running_container", lang))
# Archive and delete snapshots before deleting container
container_name = status.get('name') if isinstance(status, dict) else f'CT-{vmid}'