116 lines
3.4 KiB
Python
116 lines
3.4 KiB
Python
"""
|
|
VM provisioning on the Proxmox host.
|
|
|
|
This module is a stub — the real Proxmox integration (qm create, qm importdisk,
|
|
qm set) runs on the backend host (srv2). Fill in the actual Proxmox commands
|
|
when you deploy the backend to the host.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
import uuid
|
|
import time
|
|
from pathlib import Path
|
|
from typing import Optional
|
|
|
|
from models import (
|
|
JobSubmissionRequest,
|
|
JobStatusResponse,
|
|
JobStatus,
|
|
)
|
|
|
|
STAGING_OUT = Path("/mnt/converter/out")
|
|
|
|
|
|
def submit_job(req: JobSubmissionRequest) -> JobStatusResponse:
|
|
"""Submit a conversion + provisioning job. Returns initial status."""
|
|
job_id = f"job_{req.vmid}_{int(time.time())}"
|
|
|
|
# Create output staging directory
|
|
out_dir = STAGING_OUT / str(req.vmid)
|
|
out_dir.mkdir(parents=True, exist_ok=True)
|
|
|
|
# In the real backend, this would:
|
|
# 1. Convert the source image to QCOW2 via qemu-img convert
|
|
# 2. Resize if target_disk_size_gb is set
|
|
# 3. Create the VM with qm create
|
|
# 4. Import the disk: qm importdisk <vmid> <qcow2> <storage>
|
|
# 5. Configure boot: qm set <vmid> --boot order=scsi0 --bios ovmf
|
|
# 6. Auto-start if configured: qm set <vmid> --onboot 1
|
|
|
|
# Stub: simulate a job being queued
|
|
return JobStatusResponse(
|
|
job_id=job_id,
|
|
vmid=req.vmid,
|
|
status=JobStatus.QUEUED,
|
|
progress_percentage=0,
|
|
message="Job queued for processing",
|
|
error_details=None,
|
|
)
|
|
|
|
|
|
def get_job_status(job_id: str) -> JobStatusResponse:
|
|
"""Query the current status of a job.
|
|
|
|
In the real backend, this would check the actual conversion process
|
|
(qemu-img progress, qm task status, etc.).
|
|
|
|
For now, returns a simulated progressing status to demonstrate the flow.
|
|
"""
|
|
# Stub: simulate progress advancing
|
|
parts = job_id.split("_")
|
|
vmid = int(parts[1]) if len(parts) >= 2 else 0
|
|
ts = int(parts[2]) if len(parts) >= 3 else 0
|
|
elapsed = int(time.time()) - ts
|
|
|
|
if elapsed < 5:
|
|
progress = min(int(elapsed * 10), 40)
|
|
status = JobStatus.PROCESSING_CONVERSION
|
|
msg = "Converting disk image..."
|
|
elif elapsed < 10:
|
|
progress = 40 + min(int((elapsed - 5) * 10), 50)
|
|
status = JobStatus.IMPORTING_STORAGE
|
|
msg = "Importing disk to Proxmox storage..."
|
|
else:
|
|
progress = 100
|
|
status = JobStatus.COMPLETED
|
|
msg = "VM created successfully"
|
|
|
|
return JobStatusResponse(
|
|
job_id=job_id,
|
|
vmid=vmid,
|
|
status=status,
|
|
progress_percentage=progress,
|
|
message=msg,
|
|
error_details=None,
|
|
)
|
|
|
|
|
|
def cleanup_staging(vmid: int, delete: bool) -> dict:
|
|
"""Remove staging files for a VM ID. Returns action details."""
|
|
in_dir = Path("/mnt/converter/in")
|
|
out_dir = STAGING_OUT / str(vmid)
|
|
|
|
if not delete:
|
|
return {
|
|
"job_id": f"job_{vmid}",
|
|
"action_taken": "retained",
|
|
"message": f"Staging files preserved for VM {vmid}",
|
|
}
|
|
|
|
# Remove extracted source files in /mnt/converter/in for this vmid
|
|
# (In production, you'd track which files belong to which job)
|
|
cleaned_in = False
|
|
cleaned_out = False
|
|
|
|
if out_dir.exists():
|
|
import shutil
|
|
shutil.rmtree(out_dir, ignore_errors=True)
|
|
cleaned_out = True
|
|
|
|
return {
|
|
"job_id": f"job_{vmid}",
|
|
"action_taken": "purged",
|
|
"message": f"Staging files deleted for VM {vmid}",
|
|
}
|