Provisioning Pipeline
This page walks through what POST /api/vm/install does, stage by stage, from the request to an SSH-ready VM.
Stage Overview
Each SSE event's step field reads <stage> > <step>.
| Stage | Step | Action |
|---|---|---|
preparation |
checking VMID |
Runs VMID allocation when id is omitted; an explicit id is used as is, without an availability check |
assigning IP |
First three octets of GATEWAY + VMID, with /24 |
|
validating CPU and RAM |
CPU ≤ 0 → 1; above VM_MAX_CPU is clamped. RAM < 512 → 512; above VM_MAX_RAM is clamped |
|
validating disk size |
Parses the number after stripping a trailing G; < 16 → 16G; ≥ VM_MAX_DISK → the cap |
|
setting default config values |
Appends -<vmid> to the name, fills the default user and password |
|
checking storage pool |
pvesm status confirms ASSIGN_STORAGE is active and of type dir / zfspool / lvmthin / nfs |
|
OS preparation |
getting OS image |
Resolves the image URL from os / version |
validating OS image URL |
HEAD request must return 200 within 15 seconds |
|
downloading OS image |
Downloads to /tmp; skipped when the file already exists (using OS image) |
|
SSH preparation |
checking SSH key |
Generates a key with ssh-keygen -t ed25519 when the main node has none |
VM creation |
creating VM |
qm create with the cluster baseline CPU type, or kvm64 when detection fails |
importing disk image |
qm importdisk into ASSIGN_STORAGE |
|
VM initialization |
initializing configuration |
qm set in order: SSH keys, password, --ciupgrade 0, OS tag, scsi0, cloud-init disk, boot order; qm resize to the target size (3 attempts, 5 seconds apart); finally ipconfig0 |
migrating VM |
Runs qm migrate --with-local-disks only when the request sets node |
|
waiting for ready |
After boot, tries SSH every 5 seconds, up to 60 times | |
SSH initialization |
Runs the OS init script inside the VM and relays each output line as SSE | |
rebooting VM |
qm reboot, then waits for SSH again |
|
finalizing |
Reports total duration, VMID, IP, and user |
qm create Arguments
| Argument | Value |
|---|---|
--cores |
Requested cpu (after clamping) |
--cpu |
Cluster baseline, or kvm64 |
--memory |
Requested ram (after clamping) |
--scsihw |
virtio-scsi-pci |
--ostype |
l26 |
--agent |
1 |
--net0 |
virtio,bridge=vmbr0 |
--serial0 |
socket |
--numa / --balloon |
Per the ballooning rule |
--ciupgrade 0 turns off cloud-init's boot-time package upgrade so it does not fight the init script for the package lock.
Failure Handling
| Failure point | Handling |
|---|---|
Preparation, image, SSH key, qm create |
Sends an error event and stops; no VM is left (not created yet, or creation failed) |
importing disk image, initializing configuration, SSH initialization |
Force-stops and runs qm destroy --purge --skiplock to remove the partial VM |
| Migrate, start, or reboot command fails | Stops immediately; the VM stays in the cluster |
| SSH wait times out | Sends an error event and stops; the VM stays so you can debug it on the node |
Success or failure, the handler always ends with event: close.
Image Cache
Downloads are stored in /tmp under version-specific names (e.g. /tmp/debian-12-generic-amd64.qcow2) and reused by later installs of the same version. Delete the file manually to pick up a newer upstream image.