One-node bed: SDK-by-version, rename, and the store/broker upgrade proofs #27
@@ -103,6 +103,12 @@ const MUST_RUN = ["mesh-control", "mesh-registry", "mesh-broker", "mesh-store",
|
|||||||
/** Named once, because the step title is also how later steps say what they waited on. */
|
/** Named once, because the step title is also how later steps say what they waited on. */
|
||||||
const NEEDS = "the mesh runs a broker for that module to talk to";
|
const NEEDS = "the mesh runs a broker for that module to talk to";
|
||||||
const GENESIS = "a bare machine becomes a mesh of one, raised by the installer";
|
const GENESIS = "a bare machine becomes a mesh of one, raised by the installer";
|
||||||
|
const SUBSTRATE = "the substrate is up — a store and a broker of the mesh's own";
|
||||||
|
const BUILT_CP = "the control plane is one this mesh built, not one it was handed";
|
||||||
|
const PIVOTED = "the pivot finished — what raised the mesh is gone";
|
||||||
|
const HAS_REGISTRY = "the registry serves this mesh its own images";
|
||||||
|
const ENROLLED = "the machine is enrolled, and an agent is running on it";
|
||||||
|
const HAS_BUILDER = "the builder is installed as a module, with an account";
|
||||||
const BASE_BUILT = "the mesh builds the shared base from source";
|
const BASE_BUILT = "the mesh builds the shared base from source";
|
||||||
const STORE_RUNS = "the mesh builds and runs a store of its own";
|
const STORE_RUNS = "the mesh builds and runs a store of its own";
|
||||||
const CATALOGUE_RUNS = "the mesh builds and runs its own catalogue";
|
const CATALOGUE_RUNS = "the mesh builds and runs its own catalogue";
|
||||||
@@ -365,6 +371,69 @@ before(async () => {
|
|||||||
return raised.report.join("\n");
|
return raised.report.join("\n");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ---- WHAT GENESIS CLAIMED, ASKED OF THE MACHINE ----------------------------------------------
|
||||||
|
//
|
||||||
|
// **Genesis is twelve steps and was reported as one line.** All the work of raising a mesh
|
||||||
|
// happens inside it, so "genesis failed" said nothing about which of its claims broke, and
|
||||||
|
// "genesis passed" was one tick standing in for six separate things being true.
|
||||||
|
//
|
||||||
|
// Each is asked of the machine rather than read from the installer's own output — the installer
|
||||||
|
// saying it published an image and the registry serving one are different facts, and it is the
|
||||||
|
// second that matters.
|
||||||
|
|
||||||
|
await step(SUBSTRATE, GENESIS, async () => {
|
||||||
|
await waitForContainer(CONTROL, "mesh-store", 120);
|
||||||
|
await waitForContainer(CONTROL, "mesh-broker", 120);
|
||||||
|
return (await on(CONTROL, `docker ps --format '{{.Names}}\t{{.Status}}'`)).out;
|
||||||
|
});
|
||||||
|
|
||||||
|
// **The whole reason the installer carries a builder.** A carried control-plane image would
|
||||||
|
// satisfy "a control plane is running" equally well, which is what makes this worth asserting:
|
||||||
|
// the image has to be one this mesh's own registry serves.
|
||||||
|
await step(BUILT_CP, GENESIS, async () => {
|
||||||
|
const image = (await on(CONTROL,
|
||||||
|
`docker inspect -f '{{.Config.Image}}' mesh-control 2>&1`)).out.trim();
|
||||||
|
assert.match(image, /@sha256:[0-9a-f]{64}/,
|
||||||
|
`the control plane names its image by tag, not by digest: ${image}`);
|
||||||
|
assert.ok(image.includes(":5000/"),
|
||||||
|
`the control plane runs an image no registry of this mesh served: ${image}`);
|
||||||
|
return image;
|
||||||
|
});
|
||||||
|
|
||||||
|
await step(PIVOTED, BUILT_CP, async () => {
|
||||||
|
const ps = (await on(CONTROL, `docker ps -a --format '{{.Names}}'`)).out;
|
||||||
|
assert.doesNotMatch(ps, /^temp-mesh-control$/m,
|
||||||
|
`the temporary control plane is still here, so the pivot did not finish:\n${ps}`);
|
||||||
|
return ps;
|
||||||
|
});
|
||||||
|
|
||||||
|
await step(HAS_REGISTRY, SUBSTRATE, async () => {
|
||||||
|
await waitForContainer(CONTROL, "mesh-registry", 120);
|
||||||
|
const held = (await on(CONTROL,
|
||||||
|
`curl -sS --max-time 15 http://127.0.0.1:5000/v2/_catalog`)).out;
|
||||||
|
assert.match(held, /mesh-control/,
|
||||||
|
`the registry serves no mesh-control, so nothing was published into it:\n${held}`);
|
||||||
|
return held.trim();
|
||||||
|
});
|
||||||
|
|
||||||
|
await step(ENROLLED, GENESIS, async () => {
|
||||||
|
const nodes = await mesh("node list");
|
||||||
|
assert.match(nodes, new RegExp(`^${CONTROL}\\b`, "m"),
|
||||||
|
`the mesh has not heard from the machine it is running on:\n${nodes}`);
|
||||||
|
// Heard from once is not an agent running, and the difference is the whole of joining.
|
||||||
|
const agent = (await on(CONTROL, `pgrep -af '[m]esh-host run' | head -3`)).out.trim();
|
||||||
|
assert.ok(agent, `no host agent is running, so nothing would apply what the mesh sends`);
|
||||||
|
return `${nodes.trim()}\n${agent}`;
|
||||||
|
});
|
||||||
|
|
||||||
|
await step(HAS_BUILDER, HAS_REGISTRY, async () => {
|
||||||
|
await waitForContainer(CONTROL, "mesh-builder", 120);
|
||||||
|
const modules = await mesh("module list");
|
||||||
|
assert.match(modules, /^builder\b/m,
|
||||||
|
`the builder is running but the mesh holds no record of it as a module:\n${modules}`);
|
||||||
|
return modules;
|
||||||
|
});
|
||||||
|
|
||||||
// ---- 2..6. THE MESH BECOMES ONE --------------------------------------------------------------
|
// ---- 2..6. THE MESH BECOMES ONE --------------------------------------------------------------
|
||||||
//
|
//
|
||||||
// **Joining used to be here, second, and that was the wrong order.** Three machines were enrolled
|
// **Joining used to be here, second, and that was the wrong order.** Three machines were enrolled
|
||||||
@@ -380,7 +449,7 @@ before(async () => {
|
|||||||
// The toolchain and runtime every module with code of its own stands on. It is a module, and it
|
// The toolchain and runtime every module with code of its own stands on. It is a module, and it
|
||||||
// is built like one — cloned from the forge by the builder installing put here, compiled on the
|
// is built like one — cloned from the forge by the builder installing put here, compiled on the
|
||||||
// machine, published into the mesh's own registry.
|
// machine, published into the mesh's own registry.
|
||||||
await step(BASE_BUILT, GENESIS, async () => {
|
await step(BASE_BUILT, HAS_BUILDER, async () => {
|
||||||
// Registered from the manifest the builder will also read, so what the mesh holds and what it
|
// Registered from the manifest the builder will also read, so what the mesh holds and what it
|
||||||
// builds are the same description of the same module.
|
// builds are the same description of the same module.
|
||||||
//
|
//
|
||||||
@@ -507,7 +576,8 @@ before(async () => {
|
|||||||
|
|
||||||
// And the catalogue, ASKED rather than observed. These five questions are what it exists for.
|
// And the catalogue, ASKED rather than observed. These five questions are what it exists for.
|
||||||
const ask = async (tool: string, args = "{}") =>
|
const ask = async (tool: string, args = "{}") =>
|
||||||
must(CONTROL, `docker exec mesh-catalog mesh-tools invoke mesh-catalog ${tool} ${quote(args)}`,
|
must(CONTROL, `docker exec mesh-catalog node /app/dist/main.js invoke mesh-catalog ` +
|
||||||
|
`${tool} ${quote(args)}`,
|
||||||
120_000);
|
120_000);
|
||||||
|
|
||||||
const held = await ask("catalog_modules");
|
const held = await ask("catalog_modules");
|
||||||
@@ -631,6 +701,12 @@ after(async () => {
|
|||||||
|
|
||||||
for (const name of [
|
for (const name of [
|
||||||
GENESIS,
|
GENESIS,
|
||||||
|
SUBSTRATE,
|
||||||
|
BUILT_CP,
|
||||||
|
PIVOTED,
|
||||||
|
HAS_REGISTRY,
|
||||||
|
ENROLLED,
|
||||||
|
HAS_BUILDER,
|
||||||
BASE_BUILT,
|
BASE_BUILT,
|
||||||
STORE_RUNS,
|
STORE_RUNS,
|
||||||
CATALOGUE_RUNS,
|
CATALOGUE_RUNS,
|
||||||
|
|||||||
Reference in New Issue
Block a user