An assignment is one module on one node, so a new whole-mesh layer is refused and the ones held are laid under each assigned node's layer, every replaced layer kept, so no machine composes differently.
93 lines
4.3 KiB
PL/PgSQL
93 lines
4.3 KiB
PL/PgSQL
-- A config value comes from four sources, the last set winning (novox/hq issue 630): the module's
|
|
-- default, mesh config, node config, and the module's own value on the node. Mesh config and node config
|
|
-- hold values only for the predefined keys, a fixed list kept in the catalogue (`predefined.json`). An
|
|
-- assignment is one module on one node: there is no module layer for the whole mesh any more.
|
|
|
|
-- The list of predefined keys, as the catalogue's predefined.json last said it. Replaced whole when a
|
|
-- build of the catalogue carries the file; `repository` and `commit` say which.
|
|
create table predefined_key (
|
|
key text primary key,
|
|
type text not null check (type in ('number', 'string', 'boolean')),
|
|
why text not null,
|
|
repository text,
|
|
commit text,
|
|
listed_at timestamptz not null default now()
|
|
);
|
|
|
|
-- Mesh config (node null) and node config: one value per predefined key, and per node. Not a foreign key
|
|
-- to predefined_key: a key the list drops keeps its value, said as reaching nothing, rather than losing it.
|
|
create table config (
|
|
key text not null,
|
|
node uuid references node(id) on delete cascade,
|
|
value jsonb not null,
|
|
set_at timestamptz not null default now(),
|
|
set_by text,
|
|
why text not null
|
|
);
|
|
create unique index config_for_the_mesh on config (key) where node is null;
|
|
create unique index config_for_a_node on config (key, node) where node is not null;
|
|
|
|
-- Every value that was replaced or cleared, with who set it and why, and who replaced it and why.
|
|
create table config_history (
|
|
key text not null,
|
|
node uuid references node(id) on delete cascade,
|
|
value jsonb not null,
|
|
set_at timestamptz,
|
|
set_by text,
|
|
why text,
|
|
replaced_at timestamptz not null default now(),
|
|
-- set · clear
|
|
replaced_by text not null,
|
|
replaced_why text
|
|
);
|
|
create index config_history_by_key on config_history (key, node, replaced_at desc);
|
|
|
|
-- The module layer for the whole mesh goes: each one is laid under the layer of every node the module is
|
|
-- assigned to — the mesh's values first, the node's over them, maps merged key by key as composition
|
|
-- merged them — so every machine composes what it did. Every layer replaced, and the mesh-wide layer
|
|
-- itself, is kept in settings_history (ADR 0217) with the reason `moved-to-nodes`. A mesh-wide layer of
|
|
-- a module assigned nowhere is kept in the history only: no machine read it.
|
|
create function pg_temp.config_630_merge(under jsonb, over jsonb) returns jsonb language plpgsql immutable as $$
|
|
declare
|
|
merged jsonb;
|
|
k text;
|
|
begin
|
|
if jsonb_typeof(under) is distinct from 'object' or jsonb_typeof(over) is distinct from 'object' then
|
|
return over;
|
|
end if;
|
|
merged := under;
|
|
for k in select jsonb_object_keys(over) loop
|
|
if merged ? k then
|
|
merged := jsonb_set(merged, array[k], pg_temp.config_630_merge(merged -> k, over -> k));
|
|
else
|
|
merged := merged || jsonb_build_object(k, over -> k);
|
|
end if;
|
|
end loop;
|
|
return merged;
|
|
end
|
|
$$;
|
|
|
|
insert into settings_history (node, module, values, set_at, replaced_by, set_by)
|
|
select t.node, t.module, t.values, t.set_at, 'moved-to-nodes', t.set_by
|
|
from settings t
|
|
join settings s on s.module = t.module and s.node is null
|
|
where t.node is not null
|
|
and exists (select 1 from assignment a where a.node = t.node and a.module = t.module);
|
|
|
|
insert into settings_history (node, module, values, set_at, replaced_by, set_by)
|
|
select null, module, values, set_at, 'moved-to-nodes', set_by from settings where node is null;
|
|
|
|
insert into settings (node, module, values, set_at, set_by)
|
|
select a.node, s.module, s.values, now(),
|
|
coalesce(s.set_by || '; ', '') || 'moved from the whole mesh''s layer to this node''s (novox/hq issue 630)'
|
|
from settings s
|
|
join assignment a on a.module = s.module
|
|
where s.node is null
|
|
on conflict (node, module) where node is not null
|
|
do update set values = pg_temp.config_630_merge(excluded.values, settings.values),
|
|
set_at = now(),
|
|
set_by = coalesce(settings.set_by || '; ', '') ||
|
|
'the whole mesh''s layer laid under it (novox/hq issue 630)';
|
|
|
|
delete from settings where node is null;
|