# 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: ```bash # List VMs utmctl list # Start/stop utmctl start utmctl stop # Get VM info (includes IP if guest agent is available) utmctl status # Clone utmctl clone --name # Delete utmctl delete # Attach USB device utmctl usb connect ``` ### 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: ```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 ```bash # 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: 1. **utmctl status**: may report IP if QEMU guest agent is installed (IncusOS doesn't have guest agent) 2. **ARP lookup**: same as Proxmox -- get MAC from VM config, scan ARP table 3. **DHCP lease file**: check `/var/db/dhcpd_leases` on macOS --- ## SEED_DATA Delivery Two options for attaching the SEED_DATA to a UTM VM: 1. **ISO on virtual CD-ROM**: generate ISO with `incusos-seed --format iso`, attach as secondary CD-ROM in UTM 2. **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: ```yaml # 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 1. **Research phase** (now): document UTM capabilities, `utmctl` API surface, AppleScript integration 2. **Seed generation**: already works (`incusos-seed` is cross-platform after Phase 3 macOS compatibility) 3. **VM creation**: implement AppleScript or `.utm` bundle generation 4. **Install flow**: implement timeout-based install detection 5. **Status/lifecycle**: implement `--status`, `--lab-up`, `--lab-down` using `utmctl` 6. **Testing**: test on macOS with Apple Silicon and Intel Macs --- ## References - [UTM documentation](https://docs.getutm.app/) - [utmctl CLI](https://docs.getutm.app/advanced/remote-control/) - [UTM scripting](https://docs.getutm.app/scripting/scripting/) - [Apple Hypervisor.framework](https://developer.apple.com/documentation/hypervisor)