Files
clawmates/migrations/0065_microvm_placement.sql
T
Omar SobhandClaude Opus 5 0f7fa31f86 feat(fleet): B1 — microvm runtime kind and KVM placement predicate
Phase B step 1, on top of the B0 spike that proved microVMs boot here.

KVM is a HARD predicate, not a preference. gw-04 — where every mission
runs today — is itself a VM without nested virtualisation and has no
/dev/kvm, so a microvm mission landing there cannot start at all. The
scheduler therefore has to be able to tell nodes apart, which means the
node has to report what it can host.

Nodes gain a `capabilities` jsonb, populated from a probe on the node
rather than from configuration: /dev/kvm either exists there or it does
not, and nothing on the server can make it appear. The probe OPENS the
device rather than stat-ing it, because it can exist while being
unopenable (wrong group, or a container without the device passed
through) — which is precisely how firecracker will fail.

`microvm` requires BOTH kvm and a firecracker binary. A node with KVM
but no binary looks capable by the obvious test and fails at launch; a
node with the binary but no KVM is gw-04.

Placement fails the launch when no capable node exists, rather than
letting a mission sit in 'running' with nowhere to run. An explicit
target_node_id is treated as a request, not a guarantee — it is honoured
only if that node actually reports the capability.

`capabilities` defaults to '{}' NOT NULL so a node that has never
reported fails every predicate: an unqueried node and an incapable node
must be indistinguishable to the scheduler, because scheduling onto a
node whose abilities are unknown is how you get a mission that cannot
start and does not say why. The report replaces rather than merges, so a
capability the node has LOST disappears instead of leaving a stale true.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-08-04 21:54:18 -07:00

28 lines
1.5 KiB
SQL

-- Phase B1: make 'microvm' a runtime a mission can ask for, and give nodes a
-- place to declare what they can actually host.
--
-- Placement for microVMs is a HARD predicate, not a preference. gw-04 — where
-- every mission runs today — is itself a VM without nested virtualisation, so
-- it has no /dev/kvm and never will. tank / morpheus / architect do. A microvm
-- mission scheduled onto a node without KVM cannot start, so the scheduler has
-- to be able to tell the difference, which means the node has to report it.
--
-- `capabilities` is deliberately a jsonb blob rather than a `has_kvm boolean`:
-- the next predicate (a baked rootfs present, a particular CLI image, a GPU)
-- should not need a migration, and the node is the only honest source for any
-- of them.
ALTER TABLE missions DROP CONSTRAINT IF EXISTS missions_runtime_kind_check;
ALTER TABLE missions ADD CONSTRAINT missions_runtime_kind_check
CHECK (runtime_kind IN ('zeroclaw', 'local_herdr', 'microvm'));
-- Default '{}' and not null: a node that has never reported is "capable of
-- nothing known", which is the safe reading. An absent capability must never
-- be mistaken for an unqueried one — a node with no entry and a node that
-- reported `kvm: false` should both fail a KVM predicate, and with this
-- default they do.
ALTER TABLE nodes ADD COLUMN IF NOT EXISTS capabilities jsonb NOT NULL DEFAULT '{}'::jsonb;
-- Placement asks "which online nodes have KVM", so index the lookup.
CREATE INDEX IF NOT EXISTS nodes_capabilities_idx ON nodes USING gin (capabilities);