Rename mesh-control -> mesh-controller, substrate -> foundation
One name per thing, per the HQ glossary: the module/container/image/binary/repo becomes mesh-controller, the seat the-controller, and the store+broker pair the foundation (embedded base bundles, default template and example lock renamed with their go:embed directives). No behaviour change — a pure vocabulary rename. Claude-Session: https://claude.ai/code/session_01D6qtiYU3P9jk3pnAXyAFyx
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
/**
|
||||
* The whole `novox` server's converted service set, installed together on ONE node behind the
|
||||
* substrate — the whole-catalogue install this rebuild has never actually run. First stage of a
|
||||
* foundation — the whole-catalogue install this rebuild has never actually run. First stage of a
|
||||
* whole-mesh rehearsal (novox/hq).
|
||||
*
|
||||
* Topology (proven by assigned-two-node-db.test.ts): the substrate (store, broker, control) rides
|
||||
* Topology (proven by assigned-two-node-db.test.ts): the foundation (store, broker, control) rides
|
||||
* `anchor` and nothing else; ALL of novox's services ride the `novox` node. novox's own postgres
|
||||
* provider owns 5432 there, so it cannot co-locate with the substrate store. An overlay is placed so
|
||||
* provider owns 5432 there, so it cannot co-locate with the foundation store. An overlay is placed so
|
||||
* each consumer's binding `at` resolves to novox's private address and reaches the providers
|
||||
* co-located with it.
|
||||
*
|
||||
@@ -28,7 +28,7 @@
|
||||
* host ports here (container ports unchanged); the provider ports the consumers actually connect to
|
||||
* (postgres 5432, minio 9000, mongodb 27017, mssql 1433) are left as-is. See REMAP below.
|
||||
*
|
||||
* MESH_LAB_HOST_BINARY=.../mesh-host MESH_LAB_BUNDLE=.../examples/substrate-first-node.lock
|
||||
* MESH_LAB_HOST_BINARY=.../mesh-host MESH_LAB_BUNDLE=.../examples/foundation-first-node.lock
|
||||
* scripts/build-module-runtime.sh builds one runtime per module that has code; the route-proxy image
|
||||
* is built by scripts/build-route-proxy-image.sh; scenarios/whole-mesh-novox.yml stocks them all
|
||||
* alongside every server image.
|
||||
@@ -42,7 +42,7 @@ import { loadScenario } from "../../src/declaration/parse.ts";
|
||||
import { raise } from "../../src/lifecycle/raise.ts";
|
||||
import { destroy, exec } from "../../src/lifecycle/operate.ts";
|
||||
import { hostBinaryPath, HOST_PATH } from "../../src/lifecycle/place.ts";
|
||||
import { labIsUsable, destroyAll, substrateBundle, onTheMachine } from "./harness.ts";
|
||||
import { labIsUsable, destroyAll, foundationBundle, onTheMachine } from "./harness.ts";
|
||||
import type { HeldImage } from "../../src/pinning.ts";
|
||||
|
||||
const capability = await labIsUsable();
|
||||
@@ -55,13 +55,13 @@ const skip = !capability.usable
|
||||
: !binary || !existsSync(binary)
|
||||
? "MESH_LAB_HOST_BINARY is not set to a built mesh-host"
|
||||
: !bundle || !existsSync(bundle)
|
||||
? "MESH_LAB_BUNDLE is not set to a substrate bundle (mesh-host examples/)"
|
||||
? "MESH_LAB_BUNDLE is not set to a foundation bundle (mesh-host examples/)"
|
||||
: false;
|
||||
|
||||
const SCENARIO = "whole-mesh-novox";
|
||||
const NODE = "novox";
|
||||
|
||||
/** Where the committed module.json files live: the mesh-catalog beside mesh-control. */
|
||||
/** Where the committed module.json files live: the mesh-catalog beside mesh-controller. */
|
||||
const catalogDir = process.env["MESH_LAB_CATALOG"]
|
||||
?? (modulesEnv ? resolve(dirname(dirname(dirname(modulesEnv))), "mesh-catalog", "modules") : "")
|
||||
?? resolve(process.cwd(), "..", "mesh-catalog", "modules");
|
||||
@@ -103,7 +103,7 @@ const MODULES: { name: string; containers: string[]; node?: boolean }[] = [
|
||||
* fail2ban declares `capabilities: ["intrusion-prevention"]`, but mesh-host advertises no such
|
||||
* capability: profile/detectors.go defines container-runtime, package-manager, service-manager,
|
||||
* firewall, overlay, seat, privileged and graphical-session — nothing for intrusion-prevention. So
|
||||
* NO node can ever host fail2ban. Worse, `mesh-control assign` records the assignment even while
|
||||
* NO node can ever host fail2ban. Worse, `mesh-controller assign` records the assignment even while
|
||||
* reporting it "cannot be applied", and the whole-node `push` then refuses to resolve the ENTIRE node
|
||||
* ("nothing was sent") over that one un-hostable assignment — one bad module blocks every other. It
|
||||
* is therefore left unassigned here so the rest of the set can be proven. (novox/hq — escalated.)
|
||||
@@ -118,8 +118,8 @@ const DROPPED: { name: string; why: string }[] = [
|
||||
|
||||
/**
|
||||
* The provable CORE: modules that converge WHOLE on this node (every container up and stable) once
|
||||
* the substrate resolves and applies the set. This bed gates green on the CORE — a regression in any
|
||||
* of these turns it red. It is the substrate + all five providers + the four consumers that reach
|
||||
* the foundation resolves and applies the set. This bed gates green on the CORE — a regression in any
|
||||
* of these turns it red. It is the foundation + all five providers + the four consumers that reach
|
||||
* their providers and stay up + the four standalone apps.
|
||||
*/
|
||||
const CORE = new Set([
|
||||
@@ -132,7 +132,7 @@ const CORE = new Set([
|
||||
* KNOWN GAPS: modules that RESOLVE and are placed, but whose containers do not stay up because the
|
||||
* committed catalog manifest is incomplete (or, for firewall, a node-service expectation is unmet).
|
||||
* They are reported every run with the exact failure, and escalated (novox/hq) — but they do not gate
|
||||
* green, because the gap is in the catalog/host, not in this bed or the mesh substrate.
|
||||
* green, because the gap is in the catalog/host, not in this bed or the mesh foundation.
|
||||
*
|
||||
* umami — the mesh-umami provisioner needs the umami server URL and admin password in its
|
||||
* provisioner.env; the manifest wires neither, so it dies "UMAMI url or admin password
|
||||
@@ -185,7 +185,7 @@ async function must(machine: string, command: string, timeoutMs?: number): Promi
|
||||
|
||||
/** The control plane, a container on the first node. */
|
||||
async function mesh(command: string, timeoutMs?: number): Promise<string> {
|
||||
return must("anchor", `docker exec mesh-control /mesh-control ${command}`, timeoutMs);
|
||||
return must("anchor", `docker exec mesh-controller /mesh-controller ${command}`, timeoutMs);
|
||||
}
|
||||
|
||||
/** The pinned reference this scenario's registry serves for a repository. */
|
||||
@@ -194,9 +194,9 @@ function pinned(reference: string): string {
|
||||
return onTheMachine(reference, held);
|
||||
}
|
||||
|
||||
/** The substrate bundle: ours by the ID the machine holds, everything else upstream. */
|
||||
/** The foundation bundle: ours by the ID the machine holds, everything else upstream. */
|
||||
function bundleFor(images: HeldImage[]): string {
|
||||
return substrateBundle(bundle, images);
|
||||
return foundationBundle(bundle, images);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,7 +236,7 @@ interface NodeState {
|
||||
|
||||
/** Ask the mesh, in its own terms, what a node has done with what it was sent. Never throws. */
|
||||
async function nodeState(node: string): Promise<NodeState> {
|
||||
const asked = await on("anchor", `docker exec mesh-control /mesh-control status --json`);
|
||||
const asked = await on("anchor", `docker exec mesh-controller /mesh-controller status --json`);
|
||||
if (!asked.ok) return { reached: false, applied: false, current: false, waiting: false, raw: asked.out };
|
||||
let state: {
|
||||
wrong: { node: string; outcome: string; refused?: string; failed?: { id: string; error: string }[] }[];
|
||||
@@ -270,12 +270,12 @@ before(async () => {
|
||||
instanceId = raised.instanceId;
|
||||
held = raised.images;
|
||||
|
||||
// anchor raises the substrate from its bundle, digests rewritten to the scenario registry's.
|
||||
await must("anchor", `cat > /tmp/substrate.lock <<'MESHBUNDLE'\n${bundleFor(raised.images)}\nMESHBUNDLE`);
|
||||
await must("anchor", `${HOST_PATH} apply /tmp/substrate.lock`, 900_000);
|
||||
// anchor raises the foundation from its bundle, digests rewritten to the scenario registry's.
|
||||
await must("anchor", `cat > /tmp/foundation.lock <<'MESHBUNDLE'\n${bundleFor(raised.images)}\nMESHBUNDLE`);
|
||||
await must("anchor", `${HOST_PATH} apply /tmp/foundation.lock`, 900_000);
|
||||
const up = await must("anchor", `docker ps --format '{{.Names}}'`);
|
||||
for (const c of ["mesh-store", "mesh-broker", "mesh-control"]) {
|
||||
assert.match(up, new RegExp(c), `the substrate did not raise ${c}:\n${up}`);
|
||||
for (const c of ["mesh-store", "mesh-broker", "mesh-controller"]) {
|
||||
assert.match(up, new RegExp(c), `the foundation did not raise ${c}:\n${up}`);
|
||||
}
|
||||
|
||||
// Both machines join the one mesh and run a host so they apply what they are pushed.
|
||||
@@ -316,7 +316,7 @@ test("the whole novox service set resolves, installs and converges on one node i
|
||||
for (const { name } of MODULES) {
|
||||
try {
|
||||
const { manifest, broker } = loadManifest(name);
|
||||
await must("anchor", `printf %s ${quote(manifest)} > /tmp/${name}.json && docker cp /tmp/${name}.json mesh-control:/${name}.json`);
|
||||
await must("anchor", `printf %s ${quote(manifest)} > /tmp/${name}.json && docker cp /tmp/${name}.json mesh-controller:/${name}.json`);
|
||||
await mesh(`module add /${name}.json`);
|
||||
if (broker) {
|
||||
await mesh(`module issue ${name} --node ${NODE}`);
|
||||
|
||||
Reference in New Issue
Block a user