feat(backups): restore target node/storage selection + task progress tracking
Add target node and storage overrides to single and bulk restore flows, and track Proxmox task progress (parse_task_progress in the monitoring worker, new ProxmoxTask progress column + migration, enriched task API responses). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -19,6 +19,7 @@ from ...auth import PermissionChecker
|
||||
from ...logging_service import LoggingService
|
||||
from ._helpers import _get_proxmox_client
|
||||
from ...proxmox import _run_in_executor
|
||||
from .tasks import ProxmoxTaskService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
@@ -322,16 +323,18 @@ async def restore_backup(
|
||||
node = data.get("node")
|
||||
vmid = data.get("vmid")
|
||||
archive = data.get("archive") # volume id
|
||||
storage = data.get("storage")
|
||||
# Target storage for the restored disks. Empty => "from backup configuration"
|
||||
# (disks go to the storage recorded in the backup). NOT the backup storage.
|
||||
storage = data.get("storage") or None
|
||||
vm_type = data.get("vm_type", "qemu")
|
||||
new_vmid = data.get("new_vmid")
|
||||
start = bool(data.get("start", False))
|
||||
unique = bool(data.get("unique", True))
|
||||
|
||||
if not all([server_id, node, vmid, archive, storage]):
|
||||
if not all([server_id, node, vmid, archive]):
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="server_id, node, vmid, archive, storage are required",
|
||||
detail="server_id, node, vmid, archive are required",
|
||||
)
|
||||
|
||||
server = db.query(ProxmoxServer).filter(ProxmoxServer.id == server_id).first()
|
||||
@@ -356,6 +359,21 @@ async def restore_backup(
|
||||
)
|
||||
|
||||
if result.get("success"):
|
||||
target_vmid = int(new_vmid) if new_vmid else int(vmid)
|
||||
upid = result.get("upid")
|
||||
# Track the restore as a Proxmox UPID task so it shows up on the Tasks
|
||||
# page and the poller can report live progress / final status.
|
||||
if upid:
|
||||
try:
|
||||
ptask = ProxmoxTaskService.register(
|
||||
db=db, upid=upid, server_id=server_id, user_id=current_user.id,
|
||||
action="backup_restore", node=node, vmid=target_vmid,
|
||||
vm_type=vm_type, description=f"Восстановление {vm_type.upper()} {target_vmid}",
|
||||
)
|
||||
ptask.progress = 0
|
||||
db.commit()
|
||||
except Exception as _te:
|
||||
logger.warning(f"Could not register restore task: {_te}")
|
||||
LoggingService.log_proxmox_action(
|
||||
db=db, action="backup_restore", resource_type="backup",
|
||||
resource_id=str(vmid), username=current_user.username,
|
||||
@@ -363,7 +381,7 @@ async def restore_backup(
|
||||
node_name=node, success=True,
|
||||
details={"archive": archive, "storage": storage, "vm_type": vm_type},
|
||||
)
|
||||
return JSONResponse(content={"success": True, "upid": result.get("upid")})
|
||||
return JSONResponse(content={"success": True, "upid": upid})
|
||||
raise HTTPException(status_code=400, detail=result.get("error", "Failed"))
|
||||
except HTTPException:
|
||||
raise
|
||||
@@ -389,13 +407,14 @@ async def restore_backup_bulk(
|
||||
"""
|
||||
data = await request.json()
|
||||
server_id = data.get("server_id")
|
||||
storage = data.get("storage")
|
||||
# Target storage for restored disks. Empty => "from backup configuration".
|
||||
storage = data.get("storage") or None
|
||||
mode = data.get("mode", "in_place")
|
||||
start = bool(data.get("start", False))
|
||||
items = data.get("items", [])
|
||||
|
||||
if not server_id or not storage or not items:
|
||||
raise HTTPException(status_code=400, detail="server_id, storage and items are required")
|
||||
if not server_id or not items:
|
||||
raise HTTPException(status_code=400, detail="server_id and items are required")
|
||||
if mode not in ("in_place", "new_vmid"):
|
||||
raise HTTPException(status_code=400, detail="mode must be 'in_place' or 'new_vmid'")
|
||||
|
||||
@@ -466,6 +485,18 @@ async def restore_backup_bulk(
|
||||
if r.get("success"):
|
||||
results.append({"vmid": vmid, "target_vmid": target, "archive": archive,
|
||||
"success": True, "upid": r.get("upid")})
|
||||
upid = r.get("upid")
|
||||
if upid:
|
||||
try:
|
||||
ptask = ProxmoxTaskService.register(
|
||||
db=db, upid=upid, server_id=server_id, user_id=current_user.id,
|
||||
action="backup_restore", node=node, vmid=target,
|
||||
vm_type=vm_type, description=f"Восстановление {vm_type.upper()} {target}",
|
||||
)
|
||||
ptask.progress = 0
|
||||
db.commit()
|
||||
except Exception as _te:
|
||||
logger.warning(f"Could not register bulk restore task: {_te}")
|
||||
LoggingService.log_proxmox_action(
|
||||
db=db, action="backup_restore", resource_type="backup",
|
||||
resource_id=str(target), username=current_user.username,
|
||||
|
||||
@@ -223,8 +223,28 @@ def get_all_tasks(
|
||||
proxmox_tasks = proxmox_q.order_by(ProxmoxTask.created_at.desc()).limit(limit).all()
|
||||
deploy_tasks = deploy_q.order_by(DeployTask.created_at.desc()).limit(limit).all()
|
||||
|
||||
# Resolve server_id -> name once for enrichment (proxmox/deploy tasks carry server_id).
|
||||
server_ids = {t.server_id for t in proxmox_tasks if t.server_id} | {t.server_id for t in deploy_tasks if t.server_id}
|
||||
server_names = {}
|
||||
if server_ids:
|
||||
for sid, sname in db.query(ProxmoxServer.id, ProxmoxServer.name).filter(ProxmoxServer.id.in_(server_ids)).all():
|
||||
server_names[sid] = sname
|
||||
|
||||
def _enrich(d: dict) -> dict:
|
||||
# All listed tasks belong to the current user.
|
||||
if not d.get("user"):
|
||||
d["user"] = current_user.username
|
||||
if d.get("server_id") and not d.get("server_name"):
|
||||
d["server_name"] = server_names.get(d["server_id"])
|
||||
# Тип column reads `type` first; fall back to action/task_type/kind.
|
||||
if not d.get("type"):
|
||||
d["type"] = d.get("action") or d.get("task_type") or d.get("kind")
|
||||
return d
|
||||
|
||||
all_tasks = sorted(
|
||||
[t.to_dict() for t in bulk_tasks] + [t.to_dict() for t in proxmox_tasks] + [t.to_dict() for t in deploy_tasks],
|
||||
[_enrich(t.to_dict()) for t in bulk_tasks]
|
||||
+ [_enrich(t.to_dict()) for t in proxmox_tasks]
|
||||
+ [_enrich(t.to_dict()) for t in deploy_tasks],
|
||||
key=lambda t: t.get("created_at") or "",
|
||||
reverse=True,
|
||||
)[:limit]
|
||||
|
||||
Reference in New Issue
Block a user