banger/internal/daemon
Thales Maciel 687fcf0b59
vm state: split transient kernel/process handles off the durable schema
Separates what a VM IS (durable intent + identity + deterministic
derived paths — `VMRuntime`) from what is CURRENTLY TRUE about it
(firecracker PID, tap device, loop devices, dm-snapshot target — new
`VMHandles`). The durable state lives in the SQLite `vms` row; the
transient state lives in an in-memory cache on the daemon plus a
per-VM `handles.json` scratch file inside VMDir, rebuilt at startup
from OS inspection. Nothing kernel-level rides the SQLite schema
anymore.

Why:

  Persisting ephemeral process handles to SQLite forced reconcile to
  treat "running with a stale PID" as a first-class case and mix it
  with real state transitions. The schema described what we last
  observed, not what the VM is. Every time the observation model
  shifted (tap pool, DM naming, pgrep fallback) the reconcile logic
  grew a new branch. Splitting lets each layer own what it's good at:
  durable records describe intent, in-memory cache + scratch file
  describe momentary reality.

Shape:

  - `model.VMHandles` = PID, TapDevice, BaseLoop, COWLoop, DMName,
    DMDev. Never in SQLite.
  - `VMRuntime` keeps: State, GuestIP, APISockPath, VSockPath,
    VSockCID, LogPath, MetricsPath, DNSName, VMDir, SystemOverlay,
    WorkDiskPath, LastError. All durable or deterministic.
  - `handleCache` on `*Daemon` — mutex-guarded map + scratch-file
    plumbing (`writeHandlesFile` / `readHandlesFile` /
    `rediscoverHandles`). See `internal/daemon/vm_handles.go`.
  - `d.vmAlive(vm)` replaces the 20+ inline
    `vm.State==Running && ProcessRunning(vm.Runtime.PID, apiSock)`
    spreads. Single source of truth for liveness.
  - Startup reconcile: per running VM, load the scratch file, pgrep
    the api sock, either keep (cache seeded from scratch) or demote
    to stopped (scratch handles passed to cleanupRuntime first so DM
    / loops / tap actually get torn down).

Verification:

  - `go test ./...` green.
  - Live: `banger vm run --name handles-test -- cat /etc/hostname`
    starts; `handles.json` appears in VMDir with the expected PID,
    tap, loops, DM.
  - `kill -9 $(pgrep bangerd)` while the VM is running, re-invoke the
    CLI, daemon auto-starts, reconcile recognises the VM as alive,
    `banger vm ssh` still connects, `banger vm delete` cleans up.

Tests added:

  - vm_handles_test.go: scratch-file roundtrip, missing/corrupt file
    behaviour, cache concurrency, rediscoverHandles prefers pgrep
    over scratch, returns scratch contents even when process is
    dead (so cleanup can tear down kernel state).
  - vm_test.go: reconcile test rewritten to exercise the new flow
    (write scratch → reconcile reads it → verifies process is gone →
    issues dmsetup/losetup teardown).

ARCHITECTURE.md updated; `handles` added to Daemon field docs.
2026-04-19 14:18:13 -03:00
..
dmsnap Extract opstate and dmsnap into subpackages 2026-04-15 16:02:43 -03:00
fcproc Extract fcproc subpackage for firecracker process helpers 2026-04-15 16:11:39 -03:00
imagemgr Remove image build --from-image; doctor treats catalog images as OK 2026-04-18 15:54:29 -03:00
opstate coverage: medium batch — hostnat runner, store guest-sessions, daemon helpers 2026-04-18 18:03:37 -03:00
session coverage: medium batch — hostnat runner, store guest-sessions, daemon helpers 2026-04-18 18:03:37 -03:00
workspace Extract workspace subpackage with pure repo helpers 2026-04-15 16:37:19 -03:00
ARCHITECTURE.md vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
autopull_test.go vm create: auto-pull image and kernel from catalogs if missing 2026-04-18 15:10:26 -03:00
capabilities.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
capabilities_test.go Remove opencode package + vm acp command (dead code) 2026-04-18 16:54:37 -03:00
daemon.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
daemon_test.go Remove image build --from-image; doctor treats catalog images as OK 2026-04-18 15:54:29 -03:00
dashboard.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
dns_routing.go Route .vm DNS through systemd-resolved 2026-03-22 15:07:22 -03:00
dns_routing_test.go Route .vm DNS through systemd-resolved 2026-03-22 15:07:22 -03:00
doc.go Remove opencode package + vm acp command (dead code) 2026-04-18 16:54:37 -03:00
doctor.go vm defaults: host-aware sizing + spec line on spawn + doctor check 2026-04-19 13:06:51 -03:00
fastpath_test.go Manage image artifacts and show VM create progress 2026-03-21 14:48:01 -03:00
guest_sessions.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
guest_sessions_test.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
image_seed.go guest sshd: drop DEBUG3 + StrictModes no; normalise /root perms 2026-04-19 13:40:40 -03:00
images.go Remove image build --from-image; doctor treats catalog images as OK 2026-04-18 15:54:29 -03:00
images_helpers_test.go coverage: medium batch — hostnat runner, store guest-sessions, daemon helpers 2026-04-18 18:03:37 -03:00
images_pull.go vm create: auto-pull image and kernel from catalogs if missing 2026-04-18 15:10:26 -03:00
images_pull_bundle_test.go image pull: dispatch to imagecat bundle path before OCI 2026-04-17 15:43:33 -03:00
images_pull_test.go Phase B-2: pre-inject banger guest agents into pulled rootfs 2026-04-16 18:08:56 -03:00
kernels.go Phase 4: remote catalog + banger kernel pull 2026-04-16 15:05:42 -03:00
kernels_test.go Phase 4: remote catalog + banger kernel pull 2026-04-16 15:05:42 -03:00
logger.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
logger_test.go Remove image build --from-image; doctor treats catalog images as OK 2026-04-18 15:54:29 -03:00
nat.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
nat_test.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
ports.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
preflight.go Remove image build --from-image; doctor treats catalog images as OK 2026-04-18 15:54:29 -03:00
runtime_assets.go Remove runtime-bundle image dependencies 2026-03-21 18:34:53 -03:00
session_attach.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
session_controller.go Extract session subpackage with pure guest-session helpers 2026-04-15 16:33:12 -03:00
session_lifecycle.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
session_stream.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
snapshot.go Extract opstate and dmsnap into subpackages 2026-04-15 16:02:43 -03:00
snapshot_test.go Harden VM stop cleanup for stale snapshots 2026-03-18 12:28:15 -03:00
ssh_client_config.go Configure direct SSH access for .vm hosts 2026-03-22 16:48:42 -03:00
ssh_client_config_test.go Configure direct SSH access for .vm hosts 2026-03-22 16:48:42 -03:00
sshd_config_test.go guest sshd: drop DEBUG3 + StrictModes no; normalise /root perms 2026-04-19 13:40:40 -03:00
tap_pool.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
vm.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
vm_authsync.go guest sshd: drop DEBUG3 + StrictModes no; normalise /root perms 2026-04-19 13:40:40 -03:00
vm_create.go vm create: auto-pull image and kernel from catalogs if missing 2026-04-18 15:10:26 -03:00
vm_create_ops.go Add lint targets, fix gofmt drift, broaden Makefile build inputs 2026-04-16 16:49:17 -03:00
vm_disk.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
vm_handles.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
vm_handles_test.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
vm_lifecycle.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
vm_locks.go Move subsystem state/locks off Daemon into owning types 2026-04-15 15:58:33 -03:00
vm_set.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
vm_stats.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
vm_test.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
web.go Serve a local web UI from bangerd 2026-03-21 16:47:47 -03:00
workspace.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00
workspace_test.go vm state: split transient kernel/process handles off the durable schema 2026-04-19 14:18:13 -03:00