Two-node DB-consumer bed + a scenario disk field

The GREEN multi-node regression bed that proves the DB-consumer gate: substrate/control on
one node, postgres+redis providers and baserow+letta consumers on another, each consumer
getting its own credential and its own mesh-named database across the overlay. Requires the
mesh-control provider-seal-key fix and the mesh-catalog db-name fix.

Includes a general lab capability: a machine 'disk' field sizing the VM root disk (a broad
install exhausts the pool default and the host fails mid-apply with 'no space left on
device'). The bed sets 60GiB.

Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
2026-09-06 13:48:26 +02:00
parent b66b330dba
commit a9ecce25cb
5 changed files with 635 additions and 1 deletions
+1
View File
@@ -40,6 +40,7 @@ function normaliseMachine(raw: unknown): Machine {
if (machine["egress"] === true) result.egress = true;
if (machine["memory"] !== undefined) result.memory = String(machine["memory"]);
if (machine["cpus"] !== undefined) result.cpus = Number(machine["cpus"]);
if (machine["disk"] !== undefined) result.disk = String(machine["disk"]);
return result;
}
+7
View File
@@ -110,6 +110,13 @@ export interface Machine {
*/
memory?: string;
cpus?: number;
/**
* Root disk size, e.g. "60GiB". Left unset, the VM uses the storage pool's default, which is
* enough for a handful of modules. A broad install that stocks many runtime + service images
* (each hundreds of MB, the heavy app images over a GB) exhausts the default and the host fails
* mid-apply with "no space left on device" — a disk fact about the machine, not a mesh defect.
*/
disk?: string;
}
/** Reachability between segments, as a segmented router enforces it. Asymmetric by design. */
+5 -1
View File
@@ -167,6 +167,7 @@ async function createMachine(
egress = false,
memory = "1GiB",
cpus = 2,
disk?: string,
): Promise<string> {
const name = machineName(instanceId, machine);
if (await succeeds(["config", "show", name], 15_000)) return name;
@@ -183,6 +184,9 @@ async function createMachine(
"-c", `user.mesh-lab.instance=${instanceId}`,
"-c", `user.mesh-lab.machine=${machine}`,
];
// A bigger root disk than the pool default, when the scenario asks — a broad install stocks many
// images and exhausts the default, failing the apply with "no space left on device".
if (disk) args.push("-d", `root,size=${disk}`);
await incus(args, 300_000);
// eth0 comes from the profile and points at the wrong network, so every attachment is
@@ -285,7 +289,7 @@ export async function raise(
const attachments = spec.at === "detached" ? [] : spec.at;
const name = await createMachine(
instanceId, machine, attachments, image, pool,
spec.at !== "detached" && spec.egress === true, spec.memory, spec.cpus);
spec.at !== "detached" && spec.egress === true, spec.memory, spec.cpus, spec.disk);
created.push(name);
byMachine.set(machine, name);
log(` machine ${machine}${spec.at === "detached" ? " (detached)" : ""}`);