No description
Find a file
Claus Lohmar c887ccd5a3 fix: uniform /api/v1/ prefix, real EFI detection, spec alignment
Backend:
- All routes now consistently under /api/v1/ (health, analyze, jobs)
- Replace dummy EFI heuristic with actual guestfish-based detect_efi()
- Add path traversal validation on analyze source_filename
- Use typed response models (HealthResponse, CleanupResponse) everywhere
- Clean up unused imports (Path, ErrorResponse)

Models:
- Align AnalyzeResponse with open-api.yaml (add vmid, remove bootable/error,
  make efi_detectable nullable, deduplicate CleanupResponse)

Converter:
- Add detect_efi(disk_path) using guestfish list-filesystems

Frontend:
- Update api_client paths to /api/v1/health and /api/v1/analyze
- Remove unsupported 'network' field from job payload

Spec:
- Promote inline HealthResponse/CleanupResponse to named schemas
- Move /analyze and /health under /api/v1/ prefix

Docs:
- Add README.md with architecture, install, API reference, usage flow
2026-07-21 17:40:08 +00:00
backend fix: uniform /api/v1/ prefix, real EFI detection, spec alignment 2026-07-21 17:40:08 +00:00
frontend fix: uniform /api/v1/ prefix, real EFI detection, spec alignment 2026-07-21 17:40:08 +00:00
.gitignore chore: initial commit — vm-bench frontend + backend 2026-07-21 14:53:29 +00:00
open-api.yaml chore: restore open-api.yaml 2026-07-21 16:50:49 +00:00
README.md fix: uniform /api/v1/ prefix, real EFI detection, spec alignment 2026-07-21 17:40:08 +00:00

VM Bench — Proxmox Image Conversion Frontend

Web GUI and REST API for converting VMware disk images (VMDK, VHD, etc.) into Proxmox-compatible QCOW2 disks and provisioning VMs with automatic OS and boot type detection.

Architecture

Browser            vm-bench LXC             Proxmox Host (srv2)
                  (this container)
──→ :5000 ──→  frontend/app.py  ──→  :9000  backend/app.py
                                      │
                                      ├─ qemu-img   (format, size)
                                      ├─ guestfish  (OS, EFI detection)
                                      ├─ 7z/unzip   (archive extraction)
                                      └─ qm create  (VM provisioning)
  • Frontend (vm-bench LXC) — FastAPI + Jinja2 web UI on port 5000
  • Backend (srv2 Proxmox host) — FastAPI REST API on port 9000
  • Shared storage/mnt/converter/in (staging) and /mnt/converter/out (output)

Directory Layout

/mnt/converter/
├── frontend/                  # Web UI (runs on vm-bench LXC)
│   ├── app.py                 # FastAPI app, routes, session handling
│   ├── api_client.py          # Typed REST client → backend
│   ├── requirements.txt
│   ├── templates/             # Jinja2 HTML templates
│   │   ├── base.html
│   │   ├── index.html         # New session form
│   │   ├── _analysis.html     # Analysis result + confirm form
│   │   └── polling.html       # Progress bar + job status
│   └── static/
│       └── proxmox.css
├── backend/                   # REST API (deploy to Proxmox host srv2)
│   ├── app.py                 # FastAPI app, routes
│   ├── models.py              # Pydantic request/response models
│   ├── converter.py           # Archive extraction, disk probing, OS/EFI detection
│   ├── provisioner.py         # VM provisioning (qm create/importdisk)
│   ├── requirements.txt
│   ├── install.sh             # Systemd installation script
│   └── vm-bench-backend.service
├── open-api.yaml              # API spec (single source of truth)
├── in/                        # Shared staging directory (gitignored)
└── out/                       # Shared output directory (gitignored)

Features

  • File upload or URL download — ingest .vmdk, .vhd, .7z, .zip, .tar.gz archives
  • Automatic archive extraction — 7z, unzip, tar, gunzip
  • Disk analysis — detects format, virtual size, guest OS, EFI bootability
  • VM provisioning — creates Proxmox VM with automatic disk import and boot config
  • Progress polling — real-time job status with progress bar
  • Staging reuse — keep source files to create multiple VMs from one image

Prerequisites

Backend (Proxmox host srv2)

  • Python 3.13+
  • qemu-img (from qemu-utils)
  • guestfish (from libguestfs-tools)
  • 7z, unzip, tar (for archive extraction)
  • systemd (for service management)

Frontend (vm-bench LXC)

  • Python 3.13+
  • wget (for URL downloads)
  • systemd (for service management)
  • Network access to backend at 10.2.0.2:9000

Installation

1. Backend (on Proxmox host srv2)

# The backend code is shared via /mnt/converter/backend/
cd /mnt/converter/backend
bash install.sh

This installs Python dependencies, copies the systemd service, and starts vm-bench-backend on port 9000. Verify:

curl http://127.0.0.1:9000/api/v1/health
# → {"status":"ok"}

2. Frontend (on vm-bench LXC)

# Install dependencies
cd /mnt/converter/frontend
pip3 install --break-system-packages -r requirements.txt

# Copy service file and start
cp /etc/systemd/system/vm-bench.service /etc/systemd/system/
systemctl daemon-reload
systemctl enable --now vm-bench

The frontend serves on port 5000. Open http://<vm-bench-ip>:5000 in a browser.

API Reference

All endpoints are under /api/v1/. Full specification in open-api.yaml.

Method Path Description
GET /api/v1/health Health check
POST /api/v1/analyze Probe source image (format, size, OS, EFI)
POST /api/v1/jobs Submit conversion + provisioning job
GET /api/v1/jobs/{id} Poll job status and progress
POST /api/v1/jobs/{id}/cleanup Delete or preserve staging files

Example: Analyze a source image

curl -X POST http://10.2.0.2:9000/api/v1/analyze \
  -H "Content-Type: application/json" \
  -d '{"vmid": 21050, "source_filename": "64bit/Debian 12.11.0 (64bit).vmdk"}'

# Response:
# {
#   "vmid": 21050,
#   "filename": "Debian 12.11.0 (64bit).vmdk",
#   "disk_format": "vmdk",
#   "disk_size_gb": 7.5,
#   "os_type": "Debian",
#   "efi_detectable": true
# }

Example: Submit a conversion job

curl -X POST http://10.2.0.2:9000/api/v1/jobs \
  -H "Content-Type: application/json" \
  -d '{
    "vmid": 21050,
    "vm_name": "debian-test",
    "boot_disk": {
      "disk_type": "image_file",
      "source_filename": "64bit/Debian 12.11.0 (64bit).vmdk",
      "format": "vmdk"
    },
    "cpu_cores": 2,
    "ram_mb": 4096,
    "target_storage": "local-lvm"
  }'

# Response:
# { "job_id": "job_21050_1737480000", "vmid": 21050, "status": "queued", ... }

Usage Flow

  1. Open the web UI → new session form
  2. Upload or download a source image → file lands in /mnt/converter/in/
  3. Backend analyses the image → shows format, size, OS, EFI status
  4. Configure VM settings → name, CPU, RAM, storage, boot type
  5. Submit job → backend converts, shrinks (if needed), creates VM
  6. Poll progress → real-time status bar updates every 2 seconds
  7. Reuse or cleanup → create another VM from same source, or delete staging files

Configuration

Variable Default Description
BACKEND_URL http://10.2.0.2:9000 Backend API base URL (set in systemd unit)
VM_ID_MIN 21000 Minimum allowed Proxmox VM ID
VM_ID_MAX 21100 Maximum allowed Proxmox VM ID

Development

Source of truth: open-api.yaml — always derive models from this file.

Backend tool requirements (on srv2):

  • qemu-img — disk format and size detection
  • guestfish / virt-inspector — OS type and EFI boot detection
  • 7z, unzip, tar, gunzip, bunzip2, xz — archive extraction

Provisioner note: backend/provisioner.py is currently a stub with simulated progress. Replace with real qm create, qm importdisk, and qm set commands when deploying to the Proxmox host.

Staging files: /mnt/converter/in/ and /mnt/converter/out/ are gitignored — they contain user data, not code.