Files
mesh-controller/internal/inventory/migrations/0005-modules-and-assignments.sql
T
jschoubben 409cd16a09 The mesh decides what a node runs
The gap that has been named at the end of every report for a week. Until now a
declaration came from a person handing over a file; now it comes from what was
assigned, resolved against the catalogue, and the control plane is deciding
rather than relaying.

Everything from the module conversation, built and run on real machines:

  assign laptop i3      -> accepted, brings xorg, because nothing else provides
                           it and there was no choice to make
  assign laptop sway    -> refused: xorg and wayland both claim the-seat
  assign laptop editor  -> refused: three modules provide a shell -- bash,
                           fish, zsh -- choose one
  assign laptop zsh     -> accepted, and the editor's requirement is answered
  bash, fish beside it  -> fine, nothing is claimed

Claims rather than pairwise exclusion, so a third display server would say what
it claims and need no edit to xorg or wayland. Scoped to node, site or mesh:
two DHCP servers at one site collide and at two sites do not, and the mesh-wide
one is the hub said as a claim instead of hard-coded.

Some conflicts cost no manifest field at all. The refusal above names the seat
AND the two files, because the mesh already holds every resource of every
module -- neither i3 nor sway knows the other exists.

Resource identities carry their module, so two modules may both call something
"config" without the second silently replacing the first. What a service
reflects is qualified the same way, or it would name a resource that no longer
exists and stop being restarted when its own configuration changes.

Nothing is sent until every node resolves. A push that configured three and
refused on the fourth would leave the mesh in a state nobody asked for, and the
fourth is exactly where a claim collision appears.

One real flaw found by using it rather than by testing it: assigning zsh did
not satisfy a requirement for a shell. Requirements were counted against the
catalogue without first asking what the set already offers, so "choose one and
assign it" named three modules and then ignored the one you chose. The remedy
was useless and every test passed.
2026-08-29 22:00:06 +02:00

37 lines
1.6 KiB
SQL

-- What modules exist, and which nodes run them.
--
-- novox/hq ADR 0006 gives inventory nodes, modules, assignments and versions. Nodes were built
-- first because everything needs to name one; these are the rest, and they are what lets the
-- control plane decide what a node runs rather than relay what a person wrote.
create table module (
name text primary key,
-- The manifest exactly as given: what it provides, requires, claims, needs of the machine,
-- and the resources it puts on a node.
--
-- Held whole rather than shredded into columns. Every field of it is read together when a
-- node is resolved, nothing here queries one part of it, and a manifest that gains a field
-- should not need a migration before it can be stored -- the module system is the thing most
-- likely to grow (ADR 0009).
manifest jsonb not null,
version text,
registered timestamptz not null default now()
);
create table assignment (
node uuid not null references node(id) on delete cascade,
module text not null references module(name) on delete restrict,
assigned timestamptz not null default now(),
primary key (node, module)
);
-- Removing a node takes its assignments; removing a module does NOT, and that asymmetry is
-- deliberate. A node that is gone cannot be running anything. A module that is still assigned
-- somewhere is being run by a machine right now, and deleting the record would leave that machine
-- holding something the mesh can no longer describe -- so it is refused until it is unassigned.
create index assignment_module on assignment (module);