The beds name images the way a machine would find them
Twenty-eight integration tests each carried their own copy of the same two helpers, which pointed a manifest and the substrate bundle at whatever the lab's registry had assigned. They now share two in the harness, and the difference is the point: ours is rewritten to the ID the machine holds it under, and everything else is left exactly as written so the machine pulls it. **The substrate bundle is where the fiction was most load-bearing.** mesh-host's `examples/substrate-first-node.lock` pins all three of its images at `192.0.2.250:5000/…`, which is the address the lab's registry served from — it was written for a target, and the target was the lab. Two of those are ordinary third-party images and become the digests mesh-catalog's own postgres and lavinmq modules pin, so the substrate's store and broker are literally the images the mesh runs. mesh-control exists in no registry at all and becomes the ID the machine was handed. **The bundle itself should be fixed in mesh-host and this substitution deleted with it.** Beds that wrote a manifest by hand named an image by repository and let the rewrite supply a digest. There is nothing to supply one now, so `onTheMachine` refuses an unpinned reference and hands back the digest the catalogue pins — a bed runs the image the mesh ships, and a bed that drifts from the catalogue is testing a different postgres. Three beds took a third-party image out of the raised list, which no longer contains one: certificates (pebble), objectstore (minio and its client) and provisioner (postgres) now name theirs and pull it. builds and mesh publish into the MESH's own artifact store — the `registry` module's image, on the node, on 5000 — rather than into scenery the lab raised. That is a different claim, and only one of them exists in production. New unit tests cover what a full raise would otherwise be the only way to check: the routes an egress machine gets (that its gateway is still the path to the rest of the scenario, that a range with no path is unreachable rather than leaked to the uplink, that each family gets its own next hop), which machine is handed which of our images, and the `images:` rule that refuses a third-party entry. The "shipped scenarios are valid" test now loads every scenario rather than two of them. Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF
This commit is contained in:
+59
-2
@@ -1,5 +1,6 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { readdirSync } from "node:fs";
|
||||
import { parseScenario } from "../src/declaration/parse.ts";
|
||||
import { loadScenario } from "../src/declaration/parse.ts";
|
||||
import { planRouters } from "../src/lifecycle/router.ts";
|
||||
@@ -13,8 +14,13 @@ function refuses(yaml: string, pattern: RegExp): void {
|
||||
}
|
||||
|
||||
test("the shipped scenarios are valid", () => {
|
||||
for (const file of ["scenarios/bootstrap-single.yml", "scenarios/the-ordinary-shape.yml"]) {
|
||||
assert.doesNotThrow(() => loadScenario(file));
|
||||
// **Every one of them**, not a chosen two. Thirty-odd scenarios were rewritten in one pass when
|
||||
// the lab's registry was removed, and a scenario nobody loads is a scenario nobody validates —
|
||||
// which is how a bed goes unraisable for weeks and is only found when somebody wants it.
|
||||
const files = readdirSync("scenarios").filter((f) => f.endsWith(".yml"));
|
||||
assert.ok(files.length > 20, `only ${files.length} scenarios found — is the path right?`);
|
||||
for (const file of files) {
|
||||
assert.doesNotThrow(() => loadScenario(`scenarios/${file}`), `scenarios/${file}`);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -251,6 +257,57 @@ machines: { a: { at: detached, egress: true } }`,
|
||||
/detached but declares egress/);
|
||||
});
|
||||
|
||||
/**
|
||||
* `images:` is the mesh's own images and nothing else.
|
||||
*
|
||||
* **The rule that replaced the lab's registry.** Anything with somewhere to be fetched from is
|
||||
* fetched from there, by the machine, over its uplink. Serving it from inside the scenario instead
|
||||
* is what hid the bootstrap faults this lab exists to find — so it is refused rather than quietly
|
||||
* done, or the fiction comes back one convenient line at a time.
|
||||
*/
|
||||
test("a third-party image in images: is refused, because nothing loads it", () => {
|
||||
for (const image of ["postgres:17-alpine", "gitea/gitea:1.22", "ghcr.io/mailu/admin:1.9"]) {
|
||||
refuses(`scenario: x
|
||||
segments: { net: { kind: public, cidr: [192.0.2.0/24] } }
|
||||
machines: { a: { at: { segment: net, address: [192.0.2.1] }, egress: true } }
|
||||
images: ["${image}"]
|
||||
place: { all: [runtime] }`,
|
||||
/is not one of the mesh's own images/);
|
||||
}
|
||||
});
|
||||
|
||||
test("one of ours in images: is accepted", () => {
|
||||
assert.doesNotThrow(() => parseScenario(`scenario: x
|
||||
segments: { net: { kind: public, cidr: [192.0.2.0/24] } }
|
||||
machines: { a: { at: { segment: net, address: [192.0.2.1] }, egress: true } }
|
||||
images: [mesh-control:development, mesh-route-proxy:development]
|
||||
place: { all: [runtime] }`));
|
||||
});
|
||||
|
||||
test("images: is named by tag — an image ID is not knowable until the image is built", () => {
|
||||
refuses(`scenario: x
|
||||
segments: { net: { kind: public, cidr: [192.0.2.0/24] } }
|
||||
machines: { a: { at: { segment: net, address: [192.0.2.1] }, egress: true } }
|
||||
images: ["mesh-control@sha256:${"0".repeat(64)}"]
|
||||
place: { all: [runtime] }`,
|
||||
/is pinned by digest/);
|
||||
});
|
||||
|
||||
test("a machine cannot be handed an image the scenario does not have", () => {
|
||||
// Ignoring it silently would be a machine missing a runtime, failing several minutes later
|
||||
// inside an apply, as a container that will not start.
|
||||
refuses(`scenario: x
|
||||
segments: { net: { kind: public, cidr: [192.0.2.0/24] } }
|
||||
machines:
|
||||
a:
|
||||
at: { segment: net, address: [192.0.2.1] }
|
||||
egress: true
|
||||
images: [mesh-runtime-redis:development]
|
||||
images: [mesh-control:development]
|
||||
place: { all: [runtime] }`,
|
||||
/is not in this scenario's images/);
|
||||
});
|
||||
|
||||
test("a segment may not be named 'uplink' — the lab claims that name for egress", () => {
|
||||
refuses(`scenario: x
|
||||
segments: { uplink: { kind: public, cidr: [192.0.2.0/24] } }
|
||||
|
||||
Reference in New Issue
Block a user