vm-bench/backend/models.py
Claus Lohmar 9eb0f15261 feat: Clone (qm clone) + Copy (re-convert) buttons on completion
After conversion completes, the user sees a form with VM Name and ID
prefilled, and three buttons:

- Clone (instant): qm clone --full via backend, takes seconds
- Copy (re-convert): shows CPU/RAM/Disk fields, re-runs full pipeline
- Clean Up & Finish: deletes staging, returns to start page

Backend: new /api/v1/clone endpoint → provisioner.clone_vm()
Frontend: new /session/clone proxy, api_client.clone_vm()
2026-07-23 09:02:57 +00:00

117 lines
2.8 KiB
Python

"""
Pydantic models matching open-api.yaml v1.1.0 exactly.
Single source of truth: /mnt/converter/open-api.yaml
"""
from __future__ import annotations
from enum import Enum
from typing import Optional, List
from pydantic import BaseModel, Field
class DiskType(str, Enum):
IMAGE_FILE = "image_file"
EMPTY_DISK = "empty_disk"
class DiskFormat(str, Enum):
QCOW2 = "qcow2"
RAW = "raw"
VMDK = "vmdk"
class BootType(str, Enum):
UEFI = "uefi"
LEGACY = "legacy"
class JobStatus(str, Enum):
QUEUED = "queued"
PROCESSING_CONVERSION = "processing_conversion"
IMPORTING_STORAGE = "importing_storage"
COMPLETED = "completed"
FAILED = "failed"
# ---------------------------------------------------------------------------
# Request schemas
# ---------------------------------------------------------------------------
class DiskSpec(BaseModel):
disk_type: DiskType = DiskType.IMAGE_FILE
source_filename: Optional[str] = None
size_gb: Optional[int] = None
format: DiskFormat = DiskFormat.QCOW2
class JobSubmissionRequest(BaseModel):
vmid: int
vm_name: str
boot_disk: DiskSpec
boot_type: BootType = BootType.UEFI
auto_detect_boot: bool = True
cpu_cores: int = Field(default=4, ge=1)
ram_mb: int = Field(default=8192, ge=512)
target_storage: str = "local-lvm"
additional_disks: List[DiskSpec] = []
target_disk_size_gb: Optional[int] = None
class CleanupRequest(BaseModel):
delete_staging_files: bool
# ---------------------------------------------------------------------------
# Response schemas
# ---------------------------------------------------------------------------
class JobStatusResponse(BaseModel):
job_id: str
vmid: int
status: JobStatus
progress_percentage: int = Field(default=0, ge=0, le=100)
message: str = ""
error_details: Optional[str] = None
class ErrorResponse(BaseModel):
detail: str
# ---------------------------------------------------------------------------
# /api/v1/analyze endpoint
# ---------------------------------------------------------------------------
class AnalyzeRequest(BaseModel):
vmid: int
source_filename: str
source_type: str = "upload" # "upload" | "url"
class AnalyzeResponse(BaseModel):
vmid: int
filename: str
disk_format: str
disk_size_gb: float
os_type: Optional[str] = None
efi_detectable: Optional[bool] = None
# ---------------------------------------------------------------------------
# Utility response schemas
# ---------------------------------------------------------------------------
class HealthResponse(BaseModel):
status: str = "ok"
class CleanupResponse(BaseModel):
job_id: str
action_taken: str # "purged" | "retained"
message: str
class CloneRequest(BaseModel):
source_vmid: int
target_vmid: int
target_name: str