feat(vm-ops): make reinstall/clone/change-password async via DeployTask

Backend:
- Add DeployTask.kind column ('deploy'|'reinstall'|'clone'|'change_password')
  + Migration 23: ALTER TABLE deploy_tasks ADD kind, drop NOT NULL on template_id
- Update DeployTask.to_dict() with kind-aware Russian descriptions
- New backend/app/api/proxmox/async_ops.py with three workers:
    _do_reinstall_sync, _do_clone_sync, _do_change_password_sync
  All run on shared _deploy_executor thread pool from templates.py and
  report progress through _update_deploy_task (DB + WebSocket broadcast)
- Rewrite five vms.py endpoints to return 202 + DeployTaskStartResponse:
    POST /vm/{vmid}/clone, /container/{vmid}/clone,
    POST /vm/{vmid}/reinstall,
    POST /vm/{vmid}/change-password, /container/{vmid}/change-password

Frontend:
- DeployTask: add 'kind' and 'server_id' fields
- useCloneInstance/useReinstallInstance/useChangePassword now return
  AsyncTaskResponse {task_id, status, name}; remove invalidateQueries
- InstanceActionDialogs: each onSuccess pushes task to deploy-tasks-store
  with appropriate kind, shows 'launched in background' toast
- InstancesPage:
  * ghostRows only for kind in {deploy, clone}, deduped by (server_id, vmid)
  * reinstall / change_password tasks shown as inline overlay (badge + ring)
    on the existing VM row's status column
This commit is contained in:
markmorado
2026-04-30 00:08:41 +02:00
parent 89d70654fc
commit 79d6864d43
9 changed files with 578 additions and 207 deletions

View File

@@ -1287,6 +1287,31 @@ def migrate_deploy_tasks(conn):
logger.info("✓ deploy_tasks table created")
def migrate_deploy_tasks_kind(conn):
"""Migration 23: Add 'kind' column to deploy_tasks (deploy/reinstall/clone/change_password)"""
# Check if column exists
result = conn.execute(text("""
SELECT column_name FROM information_schema.columns
WHERE table_name = 'deploy_tasks' AND column_name = 'kind'
"""))
if result.fetchone():
logger.info("✓ deploy_tasks.kind already exists")
return
conn.execute(text("""
ALTER TABLE deploy_tasks
ADD COLUMN kind VARCHAR(30) NOT NULL DEFAULT 'deploy'
"""))
conn.execute(text("""
CREATE INDEX IF NOT EXISTS idx_deploy_tasks_kind
ON deploy_tasks (kind)
"""))
# template_id may be NULL for non-deploy tasks (clone/reinstall don't always need it)
conn.execute(text("""
ALTER TABLE deploy_tasks ALTER COLUMN template_id DROP NOT NULL
"""))
logger.info("✓ deploy_tasks.kind column added")
def run_all_migrations(engine, db_session=None):
"""
Run all migrations in order.
@@ -1477,6 +1502,14 @@ def run_all_migrations(engine, db_session=None):
logger.warning(f"Deploy tasks migration: {e}")
conn.rollback()
# Migration 23: deploy_tasks.kind column
try:
migrate_deploy_tasks_kind(conn)
conn.commit()
except Exception as e:
logger.warning(f"Deploy tasks kind migration: {e}")
conn.rollback()
logger.info("=" * 50)
logger.info("✓ All migrations completed successfully")
logger.info("=" * 50)