The lab went from one Windows guest to five and there was no way to see what they were all doing without issuing a QEMU screendump per guest by hand. - tools/vmwatch.py: always-on HTTP service serving an auto-refreshing wall of live guest screens. Runs on spicy as vmwatch.service; browse it at http://192.168.3.201:8140/. Click a tile for that guest full size. Guests are discovered from /etc/pve/qemu-server by matching sots-re, so clones appear and vanish on their own. A stopped, paused or unreachable guest gets a labelled placeholder tile carrying the monitor's own error, never a broken image or a 500. Python 3 stdlib only. - tools/vmwatch-install.sh: install/update/uninstall the unit on the host. - tools/vmshot.py: one-shot contact sheet, and --one <id> for a full-size grab. Pulls frames from the vmwatch service when it is up (0.5s) and falls back to ssh + qm monitor when it is not (4s). - guides/lab-screen-wall.md: how to use both, and why. Capture goes over each guest's QMP socket rather than forking qm: qm is a Perl program, and one fork per guest per tick cost ~90% of a host core and a 728 MB cgroup peak. Direct QMP is 0.33 CPU-seconds per 88s and 23 MB RSS. QEMU 11 here dumps PNG natively; the fallback PPM encoder was verified pixel-identical to QEMU's own on a real framebuffer. Read-only throughout: screendump does not perturb the guest (method-rule 19), so reading VM 140's screen is not an experiment and does not take its lock.
63 lines
3 KiB
Markdown
63 lines
3 KiB
Markdown
# Watching the lab guests
|
||
|
||
The lab is five Windows guests now. This is how to see all of them at once.
|
||
|
||
## The live wall
|
||
|
||
<http://192.168.3.201:8140/>
|
||
|
||
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-<ts>.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/<id>.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 <file> -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.
|