# Multi-Node Dispatch

This page explains how go-pve-qemu finds which node hosts a VM and decides whether to run `qm` locally or over SSH.

## Locating a VM's Node

The service scans `/etc/pve/nodes/*/qemu-server/*.conf` (the Proxmox cluster filesystem, synced to every node) and derives a node-to-VMID mapping from the path:

```text
/etc/pve/nodes/pve2/qemu-server/120.conf  →  VMID 120 lives on pve2
```

## Where Commands Run

| Condition | Execution |
|---|---|
| VM's node = `MAIN_NODE` | Local `qm <args>` |
| Another node with a matching `NODE_<node>` | `ssh root@<NODE_node> qm <args>` |
| `MAIN_NODE` unset, or no `NODE_<node>` | SSH runs with an empty host and the command fails |

SSH always carries these options so no interactive prompt can block the API:

```text
-o ConnectTimeout=10
-o StrictHostKeyChecking=no
-o UserKnownHostsFile=/dev/null
-o BatchMode=yes
```

## Operations Using Dispatch

| Operation | `qm` subcommand |
|---|---|
| start | `qm start` |
| stop | `qm stop` |
| shutdown | `qm shutdown` |
| reboot | `qm reboot` |
| destroy | `qm destroy` |
| set/cpu | `qm set --cores` |
| set/memory | `qm set --memory [--numa --balloon]` |
| set/disk | `qm disk resize scsi0 +<size>` |
| set/node | `qm migrate <vmid> <node> --with-local-disks` |

## Exceptions

- **Install**: `qm create`, `importdisk`, and `qm set` always run locally on the main node; with `node` set, migration happens after creation, and only start and reboot go through dispatch
- **`GET /vm/:id/status`**: runs `qm status` locally on the main node only, so querying a VM on another node fails
- **VM list**: reads cluster-wide data via `pvesh get /cluster/resources` and needs no dispatch

## Migration

`POST /api/vm/:id/set/node` requires a stopped VM, moves local disks with `--with-local-disks`, and streams `qm migrate` output line by line over SSE.
