aboutsummaryrefslogtreecommitdiffstats
path: root/vm-manager/README.md
diff options
context:
space:
mode:
Diffstat (limited to 'vm-manager/README.md')
-rw-r--r--vm-manager/README.md97
1 files changed, 97 insertions, 0 deletions
diff --git a/vm-manager/README.md b/vm-manager/README.md
new file mode 100644
index 0000000..e11b7f2
--- /dev/null
+++ b/vm-manager/README.md
@@ -0,0 +1,97 @@
+# vm-manager
+
+A drawer for libvirt virtual machines: state, live statistics, the actions
+that make sense in the current state, and the snapshot list. It replaces the
+menu half of `rofi-qemu.sh`, which could only ever show a list of strings.
+
+ ┌─ buildsystem ───────────────── ● running ─┐
+ │ CPU 4% RAM 0.7/16 GB Disk 60/130 GB │
+ │ 172.16.34.20 │
+ │ [Shutdown] [Reboot] [Suspend] [Reset] │
+ │ snapshots │
+ │ working 2026-03-06 10:27 │
+ └───────────────────────────────────────────┘
+
+## Running it
+
+ qs -p .
+
+`SUPER+v` toggles it, through an IPC call, so the shell has to be running
+first. Both are wired in the Hyprland config:
+
+ -- autostart.lua
+ hl.exec_cmd("qs -p ~/Programming/GIT/quickshell/vm-manager")
+
+ -- keybindings.lua
+ hl.bind(mainMod .. " + v", hl.dsp.exec_cmd(
+ "qs -p ~/Programming/GIT/quickshell/vm-manager ipc call panel toggle"))
+
+Write those two paths out in full in the real config: `exec_cmd` runs the
+command directly, with no shell to expand `~`.
+
+The drawer opens on the monitor named by the `monitor` property at the top of
+`VmPanel.qml`, defaulting to `DP-3`, and falls back to the first screen when
+that one is not connected. It dims the rest of that monitor, because the
+secondary screen usually has a real window on it, and takes keyboard focus so
+Escape closes it and a delete can be confirmed by typing.
+
+## Where the numbers come from
+
+Everything shells out to `virsh`, the same commands the rofi script used. No
+libvirt bindings, no new dependency.
+
+| Row | Source |
+| ---------- | ------------------------------------------------- |
+| state | `virsh domstats --state` |
+| CPU | `cpu.time` sampled twice, divided by vCPU count |
+| RAM | `virsh dommemstat`: `actual - usable` |
+| Disk | guest agent `guest-get-fsinfo`, the `/` mount |
+| address | `virsh domifaddr --source agent` |
+| snapshots | `virsh snapshot-list` |
+
+Three of those need **qemu-guest-agent running inside the guest**. It is not
+up for the first few seconds after boot, and another VM might not have it at
+all, so those rows show `—` and the header says `agent starting` rather than
+substituting a host-side figure. That distinction matters: libvirt's own
+`balloon.current` is memory *allocated* to the VM, which on a VM that has
+booted reads as 100% forever, and `block.0.allocation` is qcow2 growth on the
+host, not usage inside the guest. Showing either in place of the real number
+would be quietly wrong, so they are not used as a fallback.
+
+## Live without polling
+
+`virsh event --all --loop` streams lifecycle changes, and that process runs
+for the whole session, panel open or not. Starting a VM from `virsh` or
+virt-manager updates the drawer, and opening it shows current state rather
+than whatever was true last time.
+
+Statistics do need sampling, on a 2 second timer, but only while the drawer
+is open: `Virsh.sampling` follows the panel's `open`. A closed panel costs one
+idle process waiting on an event socket.
+
+## Destructive actions
+
+`Reset`, `Force stop`, snapshot `Revert` and snapshot `Delete` each take one
+confirmation click. `Delete VM` requires the machine's name to be typed,
+because it runs `virsh undefine --remove-all-storage`, which erases the disk
+image with no undo. The rofi script ran exactly that from a single menu
+selection with no confirmation at all.
+
+Failures are reported with `notify-send`, since a `virsh` error otherwise has
+nowhere to go: the process output is not attached to a terminal.
+
+## Theme
+
+`Theme.qml` is the copy from `volume-osd` with three colours added for state
+dots (green running, yellow transitional, red crashed). The accent still comes
+from `~/.cache/wal/udt-accent.rasi` and still tracks the wallpaper.
+
+The frosting is Hyprland's, matched on this window's namespace:
+
+ hl.layer_rule({
+ name = "blur-vm-manager",
+ match = { namespace = "^(quickshell-vm-manager)$" },
+ blur = true,
+ xray = false,
+ ignore_alpha = 0.1,
+ })