Feature 57 (config and provisioning): release mesh-controller, the reviewed release branch merged with main, on top of main

This commit is contained in:
2026-10-16 08:28:38 +00:00
parent d70bb1f388
commit d984816844
259 changed files with 34899 additions and 353 deletions
@@ -0,0 +1,46 @@
-- Placement is not config (novox/hq ADR 0348 clause 11, issue 651).
--
-- Where a module's directories are on a machine (`places`), where the operator's data it reads is
-- (`accesses`) and which found networks a taken container keeps (`networks`) were kept as keys of a
-- settings layer. They are facts of an assignment that the controller decides, never config values, and
-- the config values are leaving for the mesh-config module (ADR 0348 clause 9) while placement stays with
-- the controller. So they get a table of their own beside the assignment, and every settings layer's
-- placement keys move into it, unchanged.
--
-- Scoped exactly as the layer they came from: one machine's, or the whole mesh's (node null) for a
-- module's every assignment, which is how a mesh-wide `places` or `accesses` layer composes today. The
-- composer reads placement from here only; the `settings` verb still takes the three keys and routes
-- them here, so nothing a person types changes.
create table placement (
node uuid references node(id) on delete cascade,
module text not null references module(name) on delete cascade,
-- Only `places`, `accesses` and `networks`, as the settings layer held them.
values jsonb not null,
set_at timestamptz not null default now(),
set_by text
);
create unique index placement_for_the_mesh on placement (module) where node is null;
create unique index placement_for_a_node on placement (node, module) where node is not null;
-- Why a layer went into the history, beside how (`replaced_by`): said for a layer this migration moved.
alter table settings_history add column why text;
-- Each layer that held a placement key is kept whole in the history first, as a `settings history` reads it.
insert into settings_history (node, module, values, set_at, replaced_by, set_by, why)
select node, module, values, set_at, 'moved', set_by, 'moved to placement, ADR 0348 clause 11'
from settings
where values ?| array['places', 'accesses', 'networks'];
insert into placement (node, module, values, set_at, set_by)
select node, module,
(select jsonb_object_agg(e.key, e.value) from jsonb_each(values) as e
where e.key in ('places', 'accesses', 'networks')),
set_at, set_by
from settings
where values ?| array['places', 'accesses', 'networks'];
-- The layer keeps its other keys, when it was set and who set it; a layer that held only placement stays,
-- empty, so a layer that existed still exists.
update settings
set values = values - 'places' - 'accesses' - 'networks'
where values ?| array['places', 'accesses', 'networks'];
@@ -0,0 +1,20 @@
-- The list of predefined keys (novox/hq ADR 0348 clause 7, design 57 package K2, issue 661).
--
-- Mesh config and node config hold values only for the keys in the catalogue's `predefined.json`. A build of
-- the catalogue reads the file at the commit it builds and carries it; the controller keeps the newest trunk
-- build's, which every manifest it reads again is judged against, and which mesh-config publishes from here
-- (design 57 package K3). One list for the mesh: one row.
--
-- **The newest trunk build wins**, by the generation of the commit built — how many commits it stands on, which
-- of two commits on one trunk is larger for the later — so a list heard late from an older build never replaces
-- a newer one. Not a config value: a key, its type, description, validation and whether it is trusted, all of it
-- public in the catalogue's repository.
create table predefined_list (
one boolean primary key default true check (one),
keys jsonb not null,
repository text not null,
commit text not null,
generation bigint not null check (generation > 0),
build text not null,
kept_at timestamptz not null default now()
);
@@ -0,0 +1,22 @@
-- The move of the controller's secrets into the vault (novox/hq ADR 0349 clause 7; design 57's V3, issue 676).
--
-- The controller cannot open a value it holds, so each machine's node-engine hands in what was sealed to it, and a
-- machine asleep when the move starts is moved when it is next heard from. These two tables are what lets the
-- controller tell, then and later, what has moved: that the move was started, by whom, and whether the record of
-- asks was copied; and each row the vault took, under the vault's name for it, with the machine whose engine handed
-- it in, the vault's generation, and a digest of the sealed text the row held then — so a row the controller
-- changed after it moved is said, never moved over the vault's value. No value and no sealed value is kept here.
create table secret_move (
one boolean primary key default true check (one),
started_at timestamptz not null default now(),
started_by text not null,
asks_moved_at timestamptz
);
create table secret_moved (
secret text primary key,
node uuid not null references node(id) on delete cascade,
generation integer not null check (generation > 0),
sealed_digest text not null,
moved_at timestamptz not null default now()
);
@@ -0,0 +1,10 @@
-- What a machine was last sent of the provisioner's plans (novox/hq ADR 0349 §4, design 57 P6, issue 672).
--
-- A module marked moved is handed to the provisioner on a machine whose node-engine takes a filled file on the
-- client's word alone: its declaration names the files the client fills, and the client fills them from the
-- module's plan — its templates archive by digest, each file's path and template, and the placement values its
-- templates name. The plans are composed with the declaration and kept with its send, by module, so the
-- assignments mirror carries the plan of the build that machine was sent (inventory.Provisioning) and a walk waits
-- for the client's report on that build's templates. Null for a machine sent nothing handed. No secret: placement
-- is not one.
alter table node add column sent_provisioning jsonb;
@@ -0,0 +1,18 @@
-- The core's own credentials as the vault sealed them to their machine (novox/hq ADR 0349 §16, issue 755).
--
-- The bus's and the provisioner's credentials travel in their machine's declaration sealed by the vault to that
-- machine, which the controller carries and cannot open. The vault seals each answer afresh, so the box the
-- controller last got is kept here and carried again while the vault's generation and the machine's key are the
-- same: a declaration that changed with every answer would be sent for ever. It is also what a send carries when
-- the vault does not answer, so the machine keeps the file it has. Kept as text, byte for byte as it was carried
-- (jsonb would reorder its keys, and the declaration with them). Sealed to the machine's key: no value.
create table core_box (
node uuid not null references node(id) on delete cascade,
module text not null,
name text not null,
generation integer not null check (generation > 0),
sealed_to text not null,
box text not null,
got_at timestamptz not null default now(),
primary key (node, module, name)
);
@@ -0,0 +1,15 @@
-- The settings layers move into mesh-config (novox/hq ADR 0348 §9, design 57 K5, issue 664).
--
-- Every config value a settings layer holds is set in mesh-config by the move of config (`move-config`), one of the
-- moves of data a release runs once after its delivery; the layers it moved keep their rows, emptied, so the
-- placement kept beside each stays where it is, and each is kept whole in the history first. This row is the
-- switch: while it is absent the controller composes from the layers as before; once the move has run and read
-- every value back through mesh-config, it is written, and the controller reads a module in the config form from
-- mesh-config_resolved where it read its layers (ADR 0349 clause 17's old way, an exception to ADR 0348 §9 that
-- design 57's R1 removes). One row at most; never written by a migration, so a delivery alone changes nothing.
create table config_move (
only_one boolean primary key default true check (only_one),
moved_at timestamptz not null default now(),
moved_by text,
why text not null
);