Files
hq/02-DECISIONS/0103-what-an-adopted-node-holds-and-what-its-guard-refuses.md
T

5.3 KiB

topic, status, date, deciders, reconstructed, extends
topic status date deciders reconstructed extends
the mesh accepted 2026-09-22 jochen false 02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md

103. What an adopted node holds, and what its guard refuses

Context

ADR 0100 holds a found file or container until its module is taken. It also has the mesh guard the store's port and the broker's management port with a table that only refuses. Two independent reviews of the build found both rules drawn too narrowly and, for the guard, in the wrong place:

  1. Other kinds of resource reach what was found. An untaken module's directory is re-owned and re-moded if a predecessor's directory is already at its path, and a database refuses to start on a data directory whose mode changed. A service of the same name as a predecessor's unit is started, stopped or re-enabled. An action run in a held container runs inside the predecessor's service. A container that is not found under its own name is created, and can mount the predecessor's data beside the predecessor's own container.
  2. The guard's two ports are not the only ones a found firewall misses. A published container port is forwarded, not received, and a firewall that filters only incoming traffic never sees it (ADR 0100's own Context). The broker's plaintext port is published on every interface and admitted by the filter from the private network only. So on an adopted node it is reachable from anywhere. The same holds for any published port a module restricts to the private network.
  3. The guard refuses by port alone. On a machine that routes for others, such as a predecessor's private-network hub, a packet for another machine's database port is refused as well. And a port the guard refuses for a module that is assigned but not taken may still be the predecessor's own, serving the predecessor's other machines.

Decision

Found covers every kind that can reach what the machine already has. On an adopted node, for a module not yet taken:

  • a directory present with no record is held: its mode and owner are left, and nothing in it is touched;
  • a service whose unit is present with no record is held: its state and whether it starts at boot are left. A reload named by the module still happens, since a reload stops nothing (ADR 0102);
  • a container not found by its name is still held if it would mount a path or a volume that is present with no record, because it would share the predecessor's data;
  • an action or one-off step run in a held container is held until the module is taken.

What is held is reported as held and is never removed, as ADR 0100 decides for files and containers.

The guard refuses what the found firewall may miss, for taken modules only. Its ports are derived, not listed. They are every machine port a taken module publishes that the filter would admit from the private network only, together with the store's port and the broker's management port. A port of a module that is assigned but not taken is not guarded: it may still be the predecessor's. The guard matches only packets addressed to this machine. Traffic the machine routes for others is never its business.

An opening already answered by a found rule is not added. If the found firewall already admits what an opening says, the opening is reported as satisfied by the found rule, and the mesh adds nothing and later removes nothing. The found firewall treats two rules differing only in their comment as one rule, so adding the mesh's would take over the operator's.

A machine raised adopted stays adopted if genesis is run again. The installer reads the node's mode from what the machine records, not only from the operator's flag. A run without the flag on an adopted machine is refused.

Consequences

  • An untaken module on an adopted node can come up only beside what was found, never on top of it: whatever would share the predecessor's data waits for the cutover.
  • The guard grows with the modules taken, and a module's published private-network port is protected on an adopted node the way the derived filter protects it on a converged one.
  • Guarding only taken modules means a foundation port on a node joining adopted is guarded once its module is taken, not when it is assigned. Genesis takes the foundation's modules, so the control-node's store is guarded from the first push.

How it is checked

Unit tests hold the host to holding a found directory, a found service and a container that would mount found data, to deferring an action run in a held container, and to adding no opening a found rule answers. They hold the controller to deriving the guard from taken modules' private-network published ports, and the guard's text to matching only this machine's addresses. The installer's tests hold a re-run without the flag on an adopted machine to a refusal. The adoption lab bed asserts that the broker's plaintext port is unreachable from outside the private network, and that an operator's own rule for a port the mesh opens survives the opening being removed.

References