vm-bench/backend/models.py
Claus Lohmar 75f90f16bb feat: multi-disk support — discover all disks in archive, select boot disk, additional disks included in job
- Storage pool discovery now uses pvesm status (reliable) with Custom... option
- discover_all_disks returns all found disk images sorted by size
- Analysis shows all disks with radio button for boot disk selection
- Confirm form passes boot disk + additional disks to job payload
2026-07-27 08:53:53 +00:00

136 lines
3.2 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"
class AnalyzeStatus(str, Enum):
QUEUED = "queued"
PROCESSING = "processing"
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
session_id: str = ""
class CleanupRequest(BaseModel):
delete_staging_files: bool
session_id: str = ""
# ---------------------------------------------------------------------------
# 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
all_disks: list = []
# ---------------------------------------------------------------------------
# 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
class AnalyzeStatusResponse(BaseModel):
analysis_id: str
vmid: int
status: AnalyzeStatus
message: str = ""
result: Optional[AnalyzeResponse] = None
error_details: Optional[str] = None