7.4 KiB
UTM Support Design Document
Design notes for a future incusos-utm script (or --backend utm flag on
incusos-proxmox) that would deploy IncusOS VMs on macOS using UTM as the
hypervisor.
Status: design only. Implementation requires macOS with UTM installed.
Why UTM
UTM is a macOS-native virtualization app built on Apple's Hypervisor.framework
(for arm64 VMs) and QEMU (for x86_64 VMs). It provides a GUI and a CLI
(utmctl) for VM management.
For macOS users who want to run an IncusOS lab locally (instead of on a remote Proxmox host), UTM is the most accessible option. It supports:
- UEFI boot (required by IncusOS)
- TPM 2.0 emulation (required for disk encryption)
- VirtIO devices (required by IncusOS)
- Nested virtualization (via Apple Hypervisor.framework)
- ISO attachment for boot media
Architecture: UTM vs Proxmox
| Feature | Proxmox | UTM |
|---|---|---|
| VM creation | API (POST /qemu) or SSH (qm create) |
utmctl CLI or AppleScript |
| Disk management | API-managed, VMID-based naming | File-based (.utm bundles) |
| ISO attach | API (ide2, ide3 config keys) |
GUI or utmctl, possibly AppleScript |
| Boot monitoring | API (blockstat.scsi0.wr_bytes polling) |
No equivalent -- use timeout + port polling |
| IP detection | ARP after MAC lookup from API | ARP after MAC from utmctl or VM config |
| UEFI/TPM | bios=ovmf, tpmstate0 config keys |
GUI settings per VM |
| Resource pool | Proxmox resource pools | No equivalent (single-user) |
| Remote access | SSH or REST API over network | Local only (no remote API) |
| Automation | Full API + SSH, headless | utmctl CLI, AppleScript, limited headless |
UTM CLI: utmctl
UTM provides utmctl for basic VM management:
# List VMs
utmctl list
# Start/stop
utmctl start <vm-name>
utmctl stop <vm-name>
# Get VM info (includes IP if guest agent is available)
utmctl status <vm-name>
# Clone
utmctl clone <vm-name> --name <new-name>
# Delete
utmctl delete <vm-name>
# Attach USB device
utmctl usb connect <vm-name> <device>
Limitations of utmctl
- No VM creation: VMs must be created via GUI or AppleScript
- No disk management: cannot attach/detach ISOs programmatically
- No hardware config: cannot set CPU count, memory, TPM, etc.
- No boot order control: must use GUI
These limitations mean a fully automated deployment (like incusos-proxmox)
would require AppleScript for VM creation and configuration, with utmctl
for start/stop/status operations.
Proposed Implementation
Option A: Separate script (incusos-utm)
A dedicated script that handles UTM-specific VM creation and management.
Reuses seed generation from incusos-seed.
incusos-utm [OPTIONS] CONFIG_FILE
--dry-run Preview actions
--status Check VM status
--cleanup Delete VMs
--lab-up Start stopped VMs
--lab-down Stop running VMs
Option B: Backend flag on incusos-proxmox
Add --backend utm to the existing script. This requires abstracting the
Proxmox-specific functions behind a backend interface.
incusos-proxmox --backend utm CONFIG_FILE
Recommendation: Option A (separate script) is simpler and avoids complicating the well-tested Proxmox workflow. The scripts can share config format and seed generation.
VM Creation via AppleScript
Since utmctl cannot create VMs, we'd use AppleScript:
tell application "UTM"
-- Create a new VM
set newVM to make new virtual machine with properties {
name: "incus-lab-01",
backend: QEMU,
architecture: x86_64
}
-- Configure hardware
set memory of newVM to 4096
set cpu cores of newVM to 4
-- Add drives
-- (AppleScript API for UTM disk management TBD)
end tell
Note: UTM's AppleScript API may not expose all hardware settings.
Alternative: use UTM's .utm bundle format (plist + disk files) to
create VM bundles programmatically.
Install Detection Without blockstat
Proxmox provides real-time disk I/O statistics via API, which
incusos-proxmox uses to detect when IncusOS installation completes.
UTM has no equivalent.
Proposed alternative: timeout + port polling
# 1. Start VM with boot ISO + SEED_DATA
utmctl start "$vm_name"
# 2. Wait for expected install duration (2-5 minutes)
sleep 120
# 3. Poll port 8443 until it responds (with timeout)
local elapsed=0
while [[ $elapsed -lt 300 ]]; do
if nc -z "$vm_ip" 8443 2>/dev/null; then
echo "IncusOS is up"
break
fi
sleep 10
elapsed=$((elapsed + 10))
done
# 4. If force_reboot is in the seed, the VM reboots after install.
# On reboot, stop the VM, remove ISOs, restart from disk.
IP Detection
UTM VMs on the default shared network get IPs from macOS's built-in DHCP. Detection approaches:
- utmctl status: may report IP if QEMU guest agent is installed (IncusOS doesn't have guest agent)
- ARP lookup: same as Proxmox -- get MAC from VM config, scan ARP table
- DHCP lease file: check
/var/db/dhcpd_leaseson macOS
SEED_DATA Delivery
Two options for attaching the SEED_DATA to a UTM VM:
- ISO on virtual CD-ROM: generate ISO with
incusos-seed --format iso, attach as secondary CD-ROM in UTM - External drive: generate FAT image with
incusos-seed --format fat, attach as secondary disk
ISO is preferred (matches the Proxmox workflow).
Config File Compatibility
The YAML config format should be compatible with incusos-proxmox configs
(minus the proxmox: section). UTM-specific settings could go in a utm:
section:
# utm: section (optional, UTM-specific overrides)
utm:
backend: qemu # qemu or apple (default: qemu)
network: shared # shared, bridged, host-only
display: true # show VM window (default: true for UTM)
defaults:
cores: 4
memory: 4096
disk: 50
vms:
- name: incus-lab-01
app: incus
apply_defaults: true
Limitations and Trade-offs
| Aspect | Proxmox | UTM |
|---|---|---|
| Automation level | Full (API/SSH) | Partial (utmctl + AppleScript) |
| Headless operation | Yes | Limited (UTM needs to be running) |
| Remote deployment | Yes (network API) | No (local only) |
| Multi-node scaling | Tested up to 4 VMs | Limited by host RAM/CPU |
| Install monitoring | Real-time (blockstat) | Timeout-based |
| Resource isolation | Proxmox pools | None |
| Nested virt | Intel VT-x passthrough | Apple HV.framework (arm64) |
When to use which
- Proxmox: production labs, multi-node clusters, automated CI, remote management, teams
- UTM: local development, single-developer labs, macOS-only environments, quick experiments
Implementation Roadmap
- Research phase (now): document UTM capabilities,
utmctlAPI surface, AppleScript integration - Seed generation: already works (
incusos-seedis cross-platform after Phase 3 macOS compatibility) - VM creation: implement AppleScript or
.utmbundle generation - Install flow: implement timeout-based install detection
- Status/lifecycle: implement
--status,--lab-up,--lab-downusingutmctl - Testing: test on macOS with Apple Silicon and Intel Macs