VIRTUALIZATION.md: storage decision revised — a Disk location picker, plain files on grid's root disk

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Mitchell-Johnson
2026-10-11 14:36:06 -07:00
co-authored by Claude Fable 5.1
parent ae72e45bf5
commit faf444d8ce
+24 -21
View File
@@ -1,20 +1,17 @@
# Virtualization tab — plan (2026-10-09; phase 1 built the same day)
**Status:** phases 1 and 2 are **deployed to all five machines as v0.1.0-188** (2026-10-09).
Incus runs on `grid` (installed from the tab); the other machines show Install or, on `gate`,
unavailable. Phase 2 verified live on `grid` through the hub: ISO fetched by URL with its
sha256 checked, **New VM from ISO** booted Alpine with Secure Boot off, **the VGA console
drew it in a real browser** (headless Chromium, 1280×800 canvas, keyboard and mouse live),
a virtiofs mount appeared in a running VM, an export tarball landed in `virt/exports/` and the
nightly cron line is written, `instance.*` sensors flow and the "VM or container down" alert
default is in. Two things found and fixed on the way: spice-html5 wants the `binary`
websocket subprotocol agreed; and it opens one websocket per SPICE channel, so the bridge
holds **one console operation per VM** and gives each channel its own data websocket on it
(Incus refuses a second operation as "already connected"). **Left from phase 2:** the LAN
bridge step (`br0` on the uplink — needs a live test on a machine that can afford to drop
off the network for a moment, which is a decision, not a build), cloud-init presets beyond
"Use my SSH keys", and a backup line for `grid`'s `virt/exports/` (see `hamlet/docs/backups.md`).
`t-alpine` on `grid` is the live example; delete it from the tab when done.
**Status:** phases 1 and 2 are **deployed to all five machines as v0.1.0-196** (2026-10-11).
Incus runs on `grid` with **plain-files storage on its root disk** (`local`, see decision 1,
revised 2026-10-11 — the file-backed ZFS pool and the test VM are gone); the other machines
show Install or, on `gate`, unavailable. A **Disk location** picker is on both create forms,
with add/remove of locations. Phase 2 verified live on `grid` through the hub on 2026-10-09:
ISO fetched by URL with its sha256 checked, New VM from ISO booted Alpine with Secure Boot
off, the VGA console drew it in a real browser (headless Chromium; needed the `binary`
websocket subprotocol and one console operation per VM with a data websocket per SPICE
channel), a virtiofs mount appeared in a running VM, an export tarball landed and the nightly
cron line is written, `instance.*` sensors flow and the "VM or container down" alert default
is in. **Left:** the LAN bridge step (his call, needs him near the NanoKVM), cloud-init
presets beyond "Use my SSH keys", a backup line for `grid`'s `virt/exports/`.
A tab for creating, watching, consoling into and deleting **LXC containers and KVM virtual
machines**, the way Proxmox does with `pct` and `qm` — **per machine, like every other
@@ -236,12 +233,18 @@ like everything else.
## Layout decisions Ham Lab makes per machine (overridable in the Install dialog)
1. **Storage.** The instance pool's backing lives in Ham Lab's folder: Install creates a
sparse `virt/pool.img` and hands it to Incus as the pool's `source` (zfs or btrfs by the
detection above), or `virt/pool/` as a `dir` pool where neither is available. Sized from
the disk's free space, shown and editable. Bulk data is **bind-mounted in**, not stored in
the pool. The driver, path and size are recorded in `virt.json` so the page can say where
the data is and Install can rebuild the pool from the file after a reinstall.
1. **Storage — revised 2026-10-11.** The create forms carry a **Disk location** picker: a
list of the machine's Incus storage pools, each described by where its bytes land, with
"+ add a location" (any folder on the machine becomes a plain-files pool). On `grid` the
one location is `local`: plain files under `virt/pool/` on the root NVMe, each VM's disk
its own sparse file sized on its own, each container a directory, nothing pre-sized.
*The first design* (a ZFS pool inside one sparse file, handed to Incus as the pool's
source, for instant snapshots and clones) was built, ran for two days, and was taken out
at Mitchell's instruction: one pre-sized file holding every disk is an opaque middle
layer with a number on it that reads as a reservation, and "zfs · hamlab-virt" on the page
read as the NAS pool. The Install dialog still offers zfs/btrfs-in-a-file for a machine
that wants instant snapshots; the labels now say exactly what each is. Bulk data is still
**bind-mounted in**, not stored in the pool.
2. **Bridge subnet, computed.** Incus's `auto` picks a random `10.x.y.0/24`, and **this
LAN is `10.0.0.0/8`** — every host has a /8 on its NIC, so any 10.x bridge collides.
Ham Lab reads the machine's routes and picks the first free /24 from `192.168.0.0/16`,