Adoption bed: a machine in use raised adopted, held, taken and converged (hq ADR 0100–0103) #51

Merged
jschoubben merged 6 commits from feat/adoption-mode into main 2026-09-22 19:02:12 +00:00
Showing only changes of commit 3f224c2876 - Show all commits
+20 -3
View File
@@ -606,8 +606,19 @@ before(async () => {
// reaches a published port through the runtime's proxy, on the incoming path, not the forwarded.
await step("B4", ["A3"], async () => {
const said: string[] = [];
const fromContainer = await on(CONTROL, `docker run --rm ${ALPINE} nc -z -w 3 ${ANCHOR} ${STORE_PORT}`, 180_000);
assert.ok(fromContainer.ok, `a container on the node cannot reach the store:\n${fromContainer.out}`);
const fromContainer = await on(CONTROL, `docker run --rm ${ALPINE} nc -zv -w 3 ${ANCHOR} ${STORE_PORT} 2>&1`, 180_000);
if (!fromContainer.ok) {
// Evidence, so the cause can be read from this run rather than guessed at the next one.
const evidence = await on(CONTROL, [
`echo '--- published'; docker ps --format '{{.Names}} {{.Ports}}' | grep -i ${STORE_PORT}`,
`echo '--- from the host'; nc -zv -w 3 ${ANCHOR} ${STORE_PORT} 2>&1`,
`echo '--- from the host network'; docker run --rm --network host ${ALPINE} nc -zv -w 3 ${ANCHOR} ${STORE_PORT} 2>&1`,
`echo '--- iptables FORWARD, DOCKER-USER, isolation'; iptables -S FORWARD; iptables -S DOCKER-USER; iptables -S | grep -i isolation`,
`echo '--- the guard'; nft list table inet mesh_guard`,
`echo '--- nat for the port'; iptables -t nat -S | grep ${STORE_PORT}`,
].join("; "), 120_000);
assert.fail(`a container on the node cannot reach the store:\n${fromContainer.out}\n${evidence.out}`);
}
said.push(` container -> ${STORE_PORT} reachable from a container on the node itself`);
return said.join("\n");
});
@@ -753,9 +764,15 @@ before(async () => {
assert.equal(await must(CONTROL, `cat ${SERVICE_FILE}`), catalogue, `the found file was not replaced with the module's`);
assert.equal(await must(CONTROL, `cat ${kept}`), await must(CONTROL, `cat ${BEFORE}/file`), `the original was not kept`);
said.push(` replaced container (spec ${label.slice(0, 12)}…) and ${SERVICE_FILE}; original still at ${kept}`);
// Either the mesh opened the port, or the predecessor's own rule already admits it — then the
// mesh adds nothing and will remove nothing (ADR 0103), and the operator's rule stays theirs.
const opened = (await openings()).filter((r) => new RegExp(`opening-tcp-${SERVED}-`).test(r));
assert.ok(opened.length > 0, `no opening for ${SERVED} once ${SERVICE} was taken:\n${(await openings()).join("\n")}`);
const operators = (await ufwAdded()).filter((r) => !marked(r) && new RegExp(`\\b${SERVED}\\b`).test(r));
assert.ok(opened.length > 0 || operators.length > 0,
`no opening for ${SERVED} once ${SERVICE} was taken, and no rule of the operator's admits it:\n${(await ufwAdded()).join("\n")}`);
assert.ok(operators.length > 0, `the operator's own rule for ${SERVED} is gone:\n${(await ufwAdded()).join("\n")}`);
said.push(...opened.map((r) => ` opened ${r}`));
if (opened.length === 0) said.push(` opening ${SERVED} satisfied by the operator's own rule: ${operators.join(" | ")}`);
const page = await until(`the taken ${SERVICE} answers over the private network`, 120, async () => {
const p = await on(JOINER, `curl -s --max-time 3 http://${anchorOnMesh}:${SERVED}/`);
return p.ok && p.out === catalogue ? p.out : null;