chore: VM ID range 21000-21100, network default vmbr0, target_storage default local-lvm
This commit is contained in:
parent
be756e33bf
commit
6bcb68c552
3 changed files with 24 additions and 247 deletions
|
|
@ -43,6 +43,17 @@ STAGING = Path("/mnt/converter/in")
|
|||
|
||||
api = ApiClient()
|
||||
|
||||
# Config
|
||||
VM_ID_MIN = 21000
|
||||
VM_ID_MAX = 21100
|
||||
DEFAULT_STORAGE = "local-lvm"
|
||||
DEFAULT_NETWORK = "vmbr0"
|
||||
|
||||
def _validate_vmid(vmid: int) -> Optional[str]:
|
||||
if not (VM_ID_MIN <= vmid <= VM_ID_MAX):
|
||||
return f"VM ID must be between {VM_ID_MIN} and {VM_ID_MAX}."
|
||||
return None
|
||||
|
||||
def render(name: str, status: int = 200, **ctx) -> HTMLResponse:
|
||||
tpl = _jinja.get_template(name)
|
||||
return HTMLResponse(tpl.render(**ctx), status_code=status)
|
||||
|
|
@ -71,6 +82,11 @@ async def start_session(
|
|||
filename = None
|
||||
error = None
|
||||
|
||||
# Validate VM ID range
|
||||
err = _validate_vmid(vmid)
|
||||
if err:
|
||||
return render("_analysis.html", request=request, error=err)
|
||||
|
||||
# --- Get the file into /mnt/converter/in/ ---
|
||||
if source_type == "upload":
|
||||
if not source_file or not source_file.filename:
|
||||
|
|
@ -134,12 +150,18 @@ async def confirm_session(
|
|||
boot_type: str = Form("uefi"),
|
||||
):
|
||||
"""Build the job payload and submit to the backend."""
|
||||
# Validate VM ID range
|
||||
err = _validate_vmid(vmid)
|
||||
if err:
|
||||
return render("_analysis.html", request=request, error=err)
|
||||
|
||||
payload = {
|
||||
"vmid": vmid,
|
||||
"vm_name": vm_name,
|
||||
"cpu_cores": cpu_cores,
|
||||
"ram_mb": ram_mb,
|
||||
"target_storage": target_storage,
|
||||
"network": DEFAULT_NETWORK,
|
||||
"auto_detect_boot": auto_detect_boot == "true",
|
||||
"boot_type": boot_type,
|
||||
"boot_disk": {
|
||||
|
|
|
|||
|
|
@ -9,8 +9,8 @@
|
|||
<div class="form-group">
|
||||
<label for="vmid">VM ID *</label>
|
||||
<input type="number" id="vmid" name="vmid" required
|
||||
placeholder="e.g. 10010" min="100" max="999999">
|
||||
<span class="hint">Must be unique on the Proxmox host</span>
|
||||
placeholder="e.g. 21050" min="21000" max="21100">
|
||||
<span class="hint">Range 21000–21100. Must be unique on the Proxmox host.</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
|
|
|
|||
245
open-api.yaml
245
open-api.yaml
|
|
@ -1,245 +0,0 @@
|
|||
openapi: 3.0.3
|
||||
info:
|
||||
title: Proxmox Image Conversion Engine
|
||||
description: |
|
||||
Backend API that runs on the Proxmox host (`srv2`) to convert VMware images
|
||||
(VMDK, VHD, etc.) to Proxmox‑compatible QCOW2, optionally shrink the disk,
|
||||
and provision a VM with automatic boot‑type detection.
|
||||
version: 1.1.0
|
||||
contact:
|
||||
name: Support
|
||||
url: https://github.com/your-org/converter
|
||||
|
||||
servers:
|
||||
- url: http://10.2.0.2:9000/api/v1
|
||||
description: Internal Proxmox host (srv2)
|
||||
|
||||
paths:
|
||||
/jobs:
|
||||
post:
|
||||
summary: Submit a new VM conversion and creation job
|
||||
operationId: createJob
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/JobSubmissionRequest'
|
||||
responses:
|
||||
'202':
|
||||
description: Job accepted and queued for processing
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/JobStatusResponse'
|
||||
'400':
|
||||
description: Invalid request or source file not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/jobs/{job_id}:
|
||||
get:
|
||||
summary: Get the current status of a conversion job
|
||||
operationId: getJobStatus
|
||||
parameters:
|
||||
- name: job_id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
example: "job_10007_1784637888"
|
||||
responses:
|
||||
'200':
|
||||
description: Job status details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/JobStatusResponse'
|
||||
'404':
|
||||
description: Job not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ErrorResponse'
|
||||
|
||||
/jobs/{job_id}/cleanup:
|
||||
post:
|
||||
summary: Delete staging files or preserve them for reuse
|
||||
operationId: cleanupJob
|
||||
parameters:
|
||||
- name: job_id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
example: "job_10007_1784637888"
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CleanupRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Cleanup action performed
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
job_id:
|
||||
type: string
|
||||
action_taken:
|
||||
type: string
|
||||
enum: [purged, retained]
|
||||
message:
|
||||
type: string
|
||||
|
||||
/health:
|
||||
get:
|
||||
summary: Health check endpoint
|
||||
operationId: healthCheck
|
||||
responses:
|
||||
'200':
|
||||
description: Service is healthy
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
example: ok
|
||||
|
||||
components:
|
||||
schemas:
|
||||
DiskSpec:
|
||||
type: object
|
||||
required:
|
||||
- disk_type
|
||||
properties:
|
||||
disk_type:
|
||||
type: string
|
||||
enum: [image_file, empty_disk]
|
||||
description: |
|
||||
`image_file` – convert an existing file from `source_filename`.
|
||||
`empty_disk` – create a blank disk of the given `size_gb`.
|
||||
source_filename:
|
||||
type: string
|
||||
nullable: true
|
||||
description: Path relative to `/mnt/converter/in` (required if `disk_type=image_file`)
|
||||
example: "64bit/Debian 12.11.0 (64bit).vmdk"
|
||||
size_gb:
|
||||
type: integer
|
||||
nullable: true
|
||||
description: Size in GiB (required if `disk_type=empty_disk`)
|
||||
example: 50
|
||||
format:
|
||||
type: string
|
||||
enum: [qcow2, raw, vmdk]
|
||||
default: qcow2
|
||||
description: Source image format (for `image_file`)
|
||||
|
||||
JobSubmissionRequest:
|
||||
type: object
|
||||
required:
|
||||
- vmid
|
||||
- vm_name
|
||||
- boot_disk
|
||||
properties:
|
||||
vmid:
|
||||
type: integer
|
||||
description: Proxmox VM ID (must be unique on host)
|
||||
example: 10007
|
||||
vm_name:
|
||||
type: string
|
||||
description: Display name for the VM
|
||||
example: "debian-default-shrink"
|
||||
boot_type:
|
||||
type: string
|
||||
enum: [uefi, legacy]
|
||||
default: uefi
|
||||
description: Boot firmware type (ignored if `auto_detect_boot=true`)
|
||||
auto_detect_boot:
|
||||
type: boolean
|
||||
default: true
|
||||
description: |
|
||||
If `true`, automatically detects whether the disk is EFI‑bootable and
|
||||
overrides `boot_type`. Falls back to `legacy` if detection fails.
|
||||
cpu_cores:
|
||||
type: integer
|
||||
default: 4
|
||||
minimum: 1
|
||||
example: 2
|
||||
ram_mb:
|
||||
type: integer
|
||||
default: 8192
|
||||
minimum: 512
|
||||
example: 4096
|
||||
target_storage:
|
||||
type: string
|
||||
default: "local-lvm"
|
||||
description: Proxmox storage pool for the VM disks
|
||||
example: "local-lvm"
|
||||
boot_disk:
|
||||
$ref: '#/components/schemas/DiskSpec'
|
||||
additional_disks:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/DiskSpec'
|
||||
description: Additional data disks (converted or empty)
|
||||
target_disk_size_gb:
|
||||
type: integer
|
||||
nullable: true
|
||||
description: |
|
||||
If provided, the boot disk (and only the boot disk) is resized to this
|
||||
size (GiB). If omitted and the boot disk is larger than 30 GiB, it is
|
||||
automatically shrunk to 30 GiB. Only shrinks when disk_type=image_file.
|
||||
example: 40
|
||||
|
||||
JobStatusResponse:
|
||||
type: object
|
||||
properties:
|
||||
job_id:
|
||||
type: string
|
||||
example: "job_10007_1784637888"
|
||||
vmid:
|
||||
type: integer
|
||||
example: 10007
|
||||
status:
|
||||
type: string
|
||||
enum: [queued, processing_conversion, importing_storage, completed, failed]
|
||||
description: Current job phase
|
||||
progress_percentage:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
example: 75
|
||||
message:
|
||||
type: string
|
||||
description: Human‑readable status message
|
||||
example: "Creating VM and importing disks..."
|
||||
error_details:
|
||||
type: string
|
||||
nullable: true
|
||||
description: If status is `failed`, contains the error reason
|
||||
|
||||
CleanupRequest:
|
||||
type: object
|
||||
required:
|
||||
- delete_staging_files
|
||||
properties:
|
||||
delete_staging_files:
|
||||
type: boolean
|
||||
description: |
|
||||
`true` – delete extracted source files and converted disk images.
|
||||
`false` – keep files so another VM can be created from the same source.
|
||||
|
||||
ErrorResponse:
|
||||
type: object
|
||||
properties:
|
||||
detail:
|
||||
type: string
|
||||
example: "Source file not found: 64bit/Debian 12.11.0 (64bit).vmdk"
|
||||
Loading…
Reference in a new issue