vm-bench/backend/models.py
Claus Lohmar 63659e4f93 feat: session GUID isolation for multi-user support
Each browser gets a UUID stored in localStorage, set as a cookie,
and attached to every API call. Files go to session-specific dirs:

  /mnt/converter/in/{guid}/    — uploads, downloads, SCP pulls
  /mnt/converter/out/{guid}/   — converted QCOW2s

Changes:
- base.html: generates UUID via crypto.randomUUID(), stores in
  localStorage + cookie, exposes as window.VM_BENCH_SID
- Frontend: all endpoints accept session_id, _staging() helper
  creates session-aware paths on demand
- JavaScript: session_id appended to all FormData, set as
  X-Session-ID header on raw uploads
- Backend models: JobSubmissionRequest.session_id field added
- Provisioner: _staging_in/_staging_out helpers, source path
  resolution uses session-aware directory
- Converter: extract_if_needed skips re-extraction if dir exists
2026-07-23 09:32:16 +00:00

118 lines
2.9 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
session_id: str = ""
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