The lab can give a sealed machine a container runtime
ADR 0046's open consequence: "the lab needs a way to place images, and the
machine it places them into needs a container runtime, which a sealed scenario
cannot install either."
The runtime half is done, and it is research 012's reframing applied literally
-- fetch at build time on a machine with a network, apply on a target that
needs nothing. `mesh-lab base build` launches a machine WITH a network,
installs a runtime, verifies it by asking the runtime rather than the package
manager, and publishes the result. Measured: ~30s to install, ~60s to publish,
~700MiB, paid once per lab rather than per scenario.
A scenario that places `runtime` or an image is then raised from that base
image, chosen rather than declared -- a scenario says what it needs, not which
image provides it. If the base does not exist it says so and how to build it.
Verified in a genuinely sealed machine (no route out, confirmed by ping):
package, service including the new `boot: enabled`, and action all applied,
were idempotent on a second run, and read back correctly. Those three had never
run anywhere but a workstation.
The image half is NOT done, and testing found why: a digest-pinned image cannot
be placed from an archive. `docker save alpine@sha256:...` produces an archive
with no repo tag, because a repo digest only exists for an image a registry
served -- so it loads dangling and a container declaring that digest reaches
for a registry the machine cannot see.
That collides with ADR 0046, which has the host REFUSE an unpinned image. Tag
refused by the host, digest unusable in the lab: there is currently no
declaration the lab can raise that exercises the container shape at all. Filed
as 04-ISSUES/009, whose resolution is a registry inside the scenario -- which is
what the real mesh does rather than a workaround for the lab.
Also fixed a weak check of my own, which is the same fault in miniature: the
load was tested with `includes("Loaded image")`, a prefix of both `Loaded
image:` and `Loaded image ID:`. So an unusable dangling load reported success
and the failure surfaced later as a container that would not start.
This commit is contained in:
+43
-1
@@ -1,7 +1,7 @@
|
||||
import { test } from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
import { parseScenario } from "../src/declaration/parse.ts";
|
||||
import { planPlacements, PLACEABLE } from "../src/lifecycle/place.ts";
|
||||
import { planPlacements, PLACEABLE, isPlaceable } from "../src/lifecycle/place.ts";
|
||||
import { assertSupported, UnsupportedError } from "../src/lifecycle/supported.ts";
|
||||
|
||||
/**
|
||||
@@ -87,3 +87,45 @@ test("the refusal says what CAN be placed", () => {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// --- runtime and image placement (novox/hq ADR 0046: the lab places what a sealed scenario
|
||||
// cannot fetch) ---
|
||||
|
||||
test("an image reference is placeable, and a bare 'image:' is not", () => {
|
||||
assert.ok(isPlaceable("image:alpine@sha256:abc"), "a reference should be placeable");
|
||||
assert.ok(isPlaceable("image:postgres:17"), "a tag is the scenario's business, not the lab's");
|
||||
assert.ok(!isPlaceable("image:"), "there is nothing to place");
|
||||
assert.ok(!isPlaceable("image: "), "whitespace is not a reference");
|
||||
});
|
||||
|
||||
test("the placeables are host, runtime and an image", () => {
|
||||
assert.ok(isPlaceable("host"));
|
||||
assert.ok(isPlaceable("runtime"));
|
||||
assert.ok(!isPlaceable("substrate"), "the tiers above tier 0 do not exist yet");
|
||||
assert.ok(!isPlaceable("control-plane"));
|
||||
});
|
||||
|
||||
test("an unplaceable artifact is named, not refused as a whole", () => {
|
||||
// A scenario placing a host and a substrate is told which half the lab cannot do — refusing
|
||||
// wholesale would send somebody looking for the wrong problem.
|
||||
const scenario = {
|
||||
name: "s",
|
||||
segments: {},
|
||||
machines: { a: {} as never },
|
||||
place: { a: ["host", "runtime", "image:alpine@sha256:x", "substrate"] },
|
||||
} as unknown as Parameters<typeof assertSupported>[0];
|
||||
|
||||
assert.throws(
|
||||
() => assertSupported(scenario),
|
||||
(err: Error) => {
|
||||
// Checked as `place: <artifact> —`, which is how an artifact is REPORTED as
|
||||
// unplaceable. Searching for the bare word matched the message's own list of what CAN
|
||||
// be placed, which mentions runtime — so the test failed on a correct message.
|
||||
assert.ok(err.message.includes("place: substrate —"), "the unplaceable one is named");
|
||||
assert.ok(!err.message.includes("place: image:alpine"), "a placeable one is not");
|
||||
assert.ok(!err.message.includes("place: runtime —"), "nor is runtime");
|
||||
assert.ok(!err.message.includes("place: host —"), "nor is host");
|
||||
return true;
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user