Prove a machine joins through the tunnel in a bed of its own
mesh/delivery delivered
mesh/delivery-group group feat/a-machine-joins-through-the-tunnel delivered: every member is delivered
mesh/merge-gate pass: the change touches no module of the mesh's graph
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (typescript), replays/merge-check.sh (go)

Two machines: the anchor raises the foundation, joins over its own
loopback and becomes the hub; the joiner makes its tunnel key, is issued
a token for it and enrols with the bus's port closed to its own address,
so the enrolment can arrive only over the tunnel (novox/hq ADR 0169). The
check that had been added to the two-node walk moves here, closing the
port the bundle publishes the bus on rather than the bus's own.

And the uplink's range may be named: behind a VPN client that routes
every private range, incus had none left to pick and no scenario could
be raised.
This commit is contained in:
jochen
2026-10-08 01:52:58 +02:00
parent 4b7ad9a387
commit e80a4b1642
7 changed files with 241 additions and 35 deletions
+13 -1
View File
@@ -135,6 +135,18 @@ async function createNetwork(
return name;
}
/**
* The uplink's own address and prefix: incus picks a free one, unless `MESH_LAB_UPLINK_V4` names it.
*
* **A workstation behind a VPN client may have no free range left to pick.** A corporate client that
* routes all of 10.0.0.0/8 and 172.16.0.0/12 leaves incus refusing with "failed to automatically find
* an unused IPv4 subnet", and no scenario can be raised at all. Naming one the host does not route —
* `192.168.231.1/24` — is the way past it; it is the host's fact, never the scenario's.
*/
export function uplinkAddress(env: NodeJS.ProcessEnv = process.env): string {
return env["MESH_LAB_UPLINK_V4"]?.trim() || "auto";
}
/**
* The one network the lab supplies rather than the declaration.
*
@@ -153,7 +165,7 @@ async function createUplink(instanceId: string): Promise<string> {
if (await succeeds(["network", "show", name], 15_000)) return name;
await incus([
"network", "create", name,
"ipv4.address=auto",
`ipv4.address=${uplinkAddress()}`,
"ipv4.nat=true",
"ipv6.address=none",
`user.mesh-lab.instance=${instanceId}`,