- 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
136 lines
3.2 KiB
Python
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
|