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()
|
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:
|
def render(name: str, status: int = 200, **ctx) -> HTMLResponse:
|
||||||
tpl = _jinja.get_template(name)
|
tpl = _jinja.get_template(name)
|
||||||
return HTMLResponse(tpl.render(**ctx), status_code=status)
|
return HTMLResponse(tpl.render(**ctx), status_code=status)
|
||||||
|
|
@ -71,6 +82,11 @@ async def start_session(
|
||||||
filename = None
|
filename = None
|
||||||
error = 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/ ---
|
# --- Get the file into /mnt/converter/in/ ---
|
||||||
if source_type == "upload":
|
if source_type == "upload":
|
||||||
if not source_file or not source_file.filename:
|
if not source_file or not source_file.filename:
|
||||||
|
|
@ -134,12 +150,18 @@ async def confirm_session(
|
||||||
boot_type: str = Form("uefi"),
|
boot_type: str = Form("uefi"),
|
||||||
):
|
):
|
||||||
"""Build the job payload and submit to the backend."""
|
"""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 = {
|
payload = {
|
||||||
"vmid": vmid,
|
"vmid": vmid,
|
||||||
"vm_name": vm_name,
|
"vm_name": vm_name,
|
||||||
"cpu_cores": cpu_cores,
|
"cpu_cores": cpu_cores,
|
||||||
"ram_mb": ram_mb,
|
"ram_mb": ram_mb,
|
||||||
"target_storage": target_storage,
|
"target_storage": target_storage,
|
||||||
|
"network": DEFAULT_NETWORK,
|
||||||
"auto_detect_boot": auto_detect_boot == "true",
|
"auto_detect_boot": auto_detect_boot == "true",
|
||||||
"boot_type": boot_type,
|
"boot_type": boot_type,
|
||||||
"boot_disk": {
|
"boot_disk": {
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="vmid">VM ID *</label>
|
<label for="vmid">VM ID *</label>
|
||||||
<input type="number" id="vmid" name="vmid" required
|
<input type="number" id="vmid" name="vmid" required
|
||||||
placeholder="e.g. 10010" min="100" max="999999">
|
placeholder="e.g. 21050" min="21000" max="21100">
|
||||||
<span class="hint">Must be unique on the Proxmox host</span>
|
<span class="hint">Range 21000–21100. Must be unique on the Proxmox host.</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<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