diff --git a/VIRTUALIZATION.md b/VIRTUALIZATION.md index b704486..2ace1fc 100644 --- a/VIRTUALIZATION.md +++ b/VIRTUALIZATION.md @@ -100,18 +100,75 @@ destructive ones confirmed by typing the name. - **Resources** — edit CPU and memory limits (live for containers; VMs take CPU hotplug and memory balloon live with the agent, else on restart), grow the root disk, add a bind mount (a host path into a container; virtiofs into a VM). -- **Images** — what is cached locally, delete, aliases; **publish** a stopped instance as an - image (Proxmox's "convert to template"). +- **Library** — ISOs for VMs and images (container templates and VM images). Its own + section below. - **Storage and networks** — the pools with their fill, the bridges with their subnets. Read-only in v1 beyond what Create and Install need. - **Sensors** — `instance..cpu`, `.memory`, `.running` from Incus's state, like the `container.*` sensors, so Alerts gets an "instance down" default and widgets can show one. +## Library: ISOs and images (asked for 2026-10-09) + +Proxmox has a storage view with **ISO Images** and **CT Templates**. Incus has the same two +things under other names, and the tab gives them one home, a **Library** sub-tab, per machine +like everything else. + +| Proxmox calls it | Incus calls it | What it is here | +|---|---|---| +| ISO Images | an ISO file attached to a VM as a `disk` device (added as a ROM device; VMs only), or a custom storage volume of type `iso` | **A directory of `.iso` files on the machine that Ham Lab indexes** — no copy into the pool | +| CT Templates | **images** — the `images:` remote (linuxcontainers.org), the local image store, anything imported or published | **The local image store**, with the remote as the catalogue to pull from | + +### ISOs + +- **One ISO directory per machine**, chosen in the Install dialog and changeable later. + Default is under Ham Lab's data directory; on `grid` it should be the existing + **`/tank/software/isos/`** — 105 GiB already there (`linux/`, `windows/`, `truenas/`, + `virtio_drivers/`, `pi/`, `hackberry/`, `sipeed/`), scanned recursively. +- **Getting an ISO in:** upload from the browser (the Files tab's `PUT /api/files/upload` + with its progress bar, reused), **download from a URL** as a followed task with an optional + checksum (the usual way — an ISO starts as a link), or **import from a path** already on the + machine. Rename, delete (refused while a VM has it attached, naming the VM). +- **Using one:** attach to / detach from a VM as a ROM device by path, with `boot.priority` + set so it boots first; **New VM from ISO** makes an empty VM (`incus init --empty --vm`) + with the ISO attached, starts it and opens the console. After install, Detach is one click + and boot order falls back to the disk. +- **Honest limit:** an ISO install is an interactive graphical installer, so it needs the + **VGA console in the browser** (`spice-html5` over Incus's VGA console websocket). + Installers that run on a serial console (Debian with `console=ttyS0`, Alpine, Arch) work + through the text console before that exists. Windows needs the virtio drivers ISO attached + as a second ROM device as well — Incus's documented path is `distrobuilder repack-windows` + to bake them in; the drivers are already in `virtio_drivers/` on `tank`. So **the ISO shelf + and the VGA console ship together, in phase 2**, moved up from phase 3. +- ISO *volumes* (`incus storage volume import --type=iso`) are the + alternative: read-only, attachable to several VMs at once, but they copy the file into the + pool. Not the default here — the directory honours the library that already exists and + keeps 105 GiB out of a 300 GiB pool. Offered as an option only if a need shows up. + +### Images (container templates and VM images) + +- **The catalogue:** browse `images:` filtered to this machine's architecture, by type + (container / VM), with the common ones pinned. **Download** copies one into the local + store (`incus image copy images:debian/13 local: --alias debian-13`) so a later Create is + instant and works without the internet. Images used by Create are cached by Incus anyway; + this is just the explicit version, Proxmox's "Templates → Download". +- **The local store:** every image here with alias, type, arch, size, origin (remote, + published, imported), when it was last used, and **which instances were made from it** + (Incus records the base image on each instance). Alias, delete (refused while an + instance's base — Incus knows), "New instance from this image". +- **Import:** a unified tarball or metadata + rootfs pair (a container template from + anywhere, including the phase-3 Proxmox conversions), or a **qcow2 / raw disk with + metadata Ham Lab writes** for a VM image — Home Assistant OS, OPNsense, a vendor cloud + image — by upload, URL, or a path on the machine. Same three ways in as ISOs. +- **Publish:** a stopped instance becomes an image with an alias — Proxmox's "convert to + template", the one thing the Images section of v1 always had. +- **Where they live:** Incus's image store, in the pool, so the pool's fill on the Storage + view includes them and says so. + ## Not in v1, with reasons | Thing | Why not yet | |---|---| -| **VGA console in the browser** | Incus hands the VM's SPICE socket over a websocket; drawing it needs `spice-html5` in the UI. Doable (the Incus UI does it), but text console + shell cover every Linux guest. Phase 3. | +| **VGA console in the browser** | Incus hands the VM's SPICE socket over a websocket; drawing it needs `spice-html5` in the UI. Doable (the Incus UI does it); text console + shell cover every Linux guest until then. **Phase 2, with the ISO shelf** — an ISO install is useless without it. | | **Windows VMs** | Incus runs them (ISO repacked with virtio drivers by `distrobuilder`), but without a VGA console in the browser they are unusable from the tab. After the above. | | **GPU passthrough to a VM** | Removes the card from the host and from whatever uses it there (Jellyfin on `grid`). Offered only with that warning, later. Sharing a GPU into a *container* (`gpu` device) leaves the host its card and is how `r720-jellyfin` used to run. Phase 3. | | **Clustering / live migration** | Incus clusters, but these machines differ in size and one is arm64, with no shared storage. Not planned. | @@ -178,9 +235,10 @@ confs), 118 GiB of `vzdump` archives, and three raw VM disks. Latest of each: - **LXC:** feasible and scriptable. Unpack the rootfs (`tar --zstd -xpf … --numeric-owner`), read `etc/vzdump/pct.conf` for arch/ostype, drop it, write `metadata.yaml`, pack, `incus - image import`, launch. Unprivileged uid shifting is Incus's job after that. An import - action in the tab (pick an archive on this machine) is plausible once the script works by - hand. x86-64 archives only run on x86-64 machines; the picker says so. + image import`, launch. Unprivileged uid shifting is Incus's job after that. The result is + an image in the Library, so a restored container is launched from there like any other + template. An import action in the tab (pick an archive on this machine) is plausible once + the script works by hand. x86-64 archives only run on x86-64 machines; the picker says so. - **VMs:** the raw disks import directly (`incus-migrate`, or an empty VM with the disk imported into its root volume). The `.vma.zst` archives need Proxmox's `vma` extractor (or the Python port) to become raw disks first. Most of these are the same `powerpanel` box @@ -191,9 +249,9 @@ confs), 118 GiB of `vzdump` archives, and three raw VM disks. Latest of each: | Phase | What | Effort | |---|---|---| -| **1 — detection, Install, the tab** | `internal/incus` (detection, CLI wrapper, JSON types, `incus monitor` for live state, the preseed builder and subnet picker), `internal/api/virt.go` (routes below), `Virtualization.tsx` (the three page states; list, detail, create dialog, snapshot panel), rail entry `virt`, terminal integration, sensors. **Tested by clicking Install on `grid` first, then `core`** — two different pool drivers, both with Docker present. Then the Mac for the arm64 path. `gate` for the unavailable state. | 2–3 sessions | -| **2 — operations** | Snapshot schedules UI, nightly exports with retention and the per-machine export directory, limits editor, bind mounts, the LAN-bridge step, instance alert default, cloud-init presets. | 1–2 sessions | -| **3 — the rest** | Proxmox import, publish-as-image, GPU device for containers, VGA console (`spice-html5`), GPU passthrough to a VM with its warning. | as wanted | +| **1 — detection, Install, the tab** | `internal/incus` (detection, CLI wrapper, JSON types, `incus monitor` for live state, the preseed builder and subnet picker), `internal/api/virt.go` (routes below), `Virtualization.tsx` (the three page states; list, detail, create dialog, snapshot panel), rail entry `virt`, terminal integration, sensors, and the Library's **Images** shelf (browse and download from `images:`, local store, import, publish). **Tested by clicking Install on `grid` first, then `core`** — two different pool drivers, both with Docker present. Then the Mac for the arm64 path. `gate` for the unavailable state. | 2–3 sessions | +| **2 — operations** | The Library's **ISO** shelf (directory, upload/URL/path, attach, New VM from ISO) **with the VGA console** (`spice-html5`), snapshot schedules UI, nightly exports with retention and the per-machine export directory, limits editor, bind mounts, the LAN-bridge step, instance alert default, cloud-init presets. | 1–2 sessions | +| **3 — the rest** | Proxmox import (archives become Library images), GPU device for containers, Windows via `distrobuilder repack-windows`, GPU passthrough to a VM with its warning. | as wanted | ### API sketch @@ -212,6 +270,17 @@ POST /api/virt/instances/{name}/exec → terminal {id} (incus exec - POST /api/virt/instances/{name}/snapshots {name}; POST …/{snap}/restore; DELETE …/{snap} PUT /api/virt/instances/{name}/schedule {cron, expiry} POST /api/virt/import {path} task (export tarball, or phase-3 Proxmox archive) + +GET /api/virt/isos the ISO directory, scanned: name, size, attached-to +PUT /api/virt/isos/dir {path} change this machine's ISO directory +POST /api/virt/isos/fetch {url, sha256?} task; uploads reuse PUT /api/files/upload +DELETE /api/virt/isos/{name} refused while attached +POST /api/virt/instances/{name}/iso {iso, boot_first} attach; DELETE …/iso detach +POST /api/virt/instances/from-iso {name, iso, cpu, memory, disk, network} task → console +GET /api/virt/images/remote?q=&type= the `images:` catalogue for this arch +POST /api/virt/images/download {alias} task (incus image copy images:… local:) +POST /api/virt/images/import {path | url, alias, type} task (tarball, or qcow2/raw + metadata) +GET /api/virt/instances/{name}/vga websocket: Incus VGA console → spice-html5 (phase 2) ``` Everything is per machine and reaches a node through the existing `/api/nodes/{name}/…`