""" 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 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 # --------------------------------------------------------------------------- # 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