# Watching the lab guests The lab is five Windows guests now. This is how to see all of them at once. ## The live wall Leave the tab open. Tiles refresh every 5 s; click a tile for that guest full size. Each tile carries the VM id, name, status and the capture timestamp. A guest that is stopped, paused or unreachable shows a labelled `NO SIGNAL` tile with the monitor's own error text, never a broken image. Served by `vmwatch.service` on **spicy** (`/opt/vmwatch/vmwatch.py`, systemd, enabled at boot). Source of truth is `tools/vmwatch.py` in this repo; redeploy with: tools/vmwatch-install.sh spicy # install or update tools/vmwatch-install.sh spicy --uninstall Nothing was installed on spicy beyond that file and its unit — the service is Python 3 standard library only (spicy has no ImageMagick, no netpbm, no Pillow). ## The one-shot contact sheet tools/vmshot.py # all guests -> dumps/vmshot/sheet-.png + latest.png tools/vmshot.py --one 140 # one guest, full size tools/vmshot.py 144 145 --cols 2 tools/vmshot.py --ssh # bypass the service, capture over SSH `vmshot` pulls frames from the vmwatch service when it is reachable (~0.5 s, no extra load on the guests) and falls back to SSH + `qm monitor` when it is not (~4 s). Output lands in `dumps/vmshot/`, which is gitignored. ## Why this mechanism Both tools capture with QEMU `screendump`, reached over each guest's `/var/run/qemu-server/.qmp` socket — the same socket and command `qm monitor` uses. * It needs **no guest agent, no guest network and nothing installed in the guest**. * It does **not perturb the guest**. That is the point (method-rule 19: an instrument that perturbs the thing it measures has already cost this campaign once). Reading VM 140's screen is therefore *not* an experiment and does **not** take 140's exclusivity lock. * The campaign board already records that `qm monitor` screendump is more reliable than the in-guest click helper's `shot`. ## Two things worth knowing **Do not fork `qm` in a loop.** The first version of vmwatch shelled out to `qm monitor` once per guest per 5 s tick. `qm` is a Perl program: that cost **~90 % of a host core and a 728 MB cgroup peak**. Talking to the QMP socket directly — same socket, same command, no fork — brought it to **0.33 CPU-seconds per 88 s and 23 MB RSS**, roughly a 300× reduction. The fleet list comes from `/etc/pve/qemu-server/*.conf` plus `query-status` for the same reason. `qm` remains the fallback path only. **QEMU 11 on spicy dumps PNG natively** (`screendump -f png`), so no PPM conversion is needed. `vmwatch.ppm_to_png` exists as a fallback for an older QEMU and was checked against QEMU's own encoder on a real 1024×768 framebuffer: pixel-identical. Guests are discovered dynamically by matching `sots-re` in the guest name, so clones added or destroyed later appear and vanish on their own — nothing to edit. Both tools are strictly read-only. Neither starts, stops, resets nor reconfigures a VM.