One-node bed: SDK-by-version, rename, and the store/broker upgrade proofs #27
+25
-25
@@ -1,13 +1,13 @@
|
|||||||
{
|
{
|
||||||
"scenario": "one-node-mesh",
|
"scenario": "one-node-mesh",
|
||||||
"established": 11,
|
"established": 16,
|
||||||
"of": 20,
|
"of": 20,
|
||||||
"steps": [
|
"steps": [
|
||||||
{
|
{
|
||||||
"code": "R1",
|
"code": "R1",
|
||||||
"title": "a bare machine becomes a mesh of one, raised by the installer",
|
"title": "a bare machine becomes a mesh of one, raised by the installer",
|
||||||
"status": "pass",
|
"status": "pass",
|
||||||
"seconds": 132,
|
"seconds": 140,
|
||||||
"why": ""
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -56,14 +56,14 @@
|
|||||||
"code": "P1",
|
"code": "P1",
|
||||||
"title": "the mesh builds the shared base from source",
|
"title": "the mesh builds the shared base from source",
|
||||||
"status": "pass",
|
"status": "pass",
|
||||||
"seconds": 78,
|
"seconds": 74,
|
||||||
"why": ""
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "P2",
|
"code": "P2",
|
||||||
"title": "the mesh builds and runs a store of its own",
|
"title": "the mesh builds and runs a store of its own",
|
||||||
"status": "pass",
|
"status": "pass",
|
||||||
"seconds": 50,
|
"seconds": 53,
|
||||||
"why": ""
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -77,57 +77,57 @@
|
|||||||
"code": "P4",
|
"code": "P4",
|
||||||
"title": "the mesh rebuilds its own control plane from source",
|
"title": "the mesh rebuilds its own control plane from source",
|
||||||
"status": "pass",
|
"status": "pass",
|
||||||
"seconds": 37,
|
"seconds": 35,
|
||||||
"why": ""
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "N1",
|
"code": "N1",
|
||||||
"title": "the mesh puts itself on a private network, and its machine has a name",
|
"title": "the mesh puts itself on a private network, and its machine has a name",
|
||||||
"status": "fail",
|
"status": "pass",
|
||||||
"seconds": 125,
|
"seconds": 6,
|
||||||
"why": "networking is assigned and no machine has a name:\n# Generated by the mesh. Do not edit — this file is replaced whenever a node\n# joins or leaves, and an edit would survive until then and vanish.\n\n127.0.0.1\tlocalhost\n::1\t\tlocalhost ip6-localhost ip6-loopback\n127.0.1.1\tanchor\n"
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "U1",
|
"code": "U1",
|
||||||
"title": "the mesh builds a module standing on that base",
|
"title": "the mesh builds a module standing on that base",
|
||||||
"status": "skip",
|
"status": "pass",
|
||||||
"seconds": 0,
|
"seconds": 14,
|
||||||
"why": "not attempted — N1 (the mesh puts itself on a private network, and its machine has a name) did not succeed"
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "U2",
|
"code": "U2",
|
||||||
"title": "the mesh runs a broker for that module to talk to",
|
"title": "the mesh runs a broker for that module to talk to",
|
||||||
"status": "skip",
|
"status": "pass",
|
||||||
"seconds": 0,
|
"seconds": 20,
|
||||||
"why": "not attempted — U1 (the mesh builds a module standing on that base) did not succeed"
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "U3",
|
"code": "U3",
|
||||||
"title": "the anchor runs the module the mesh built",
|
"title": "the anchor runs the module the mesh built",
|
||||||
"status": "skip",
|
"status": "pass",
|
||||||
"seconds": 0,
|
"seconds": 6,
|
||||||
"why": "not attempted — U2 (the mesh runs a broker for that module to talk to) did not succeed"
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "V1",
|
"code": "V1",
|
||||||
"title": "the control plane can describe the mesh, and what it says is true",
|
"title": "the control plane can describe the mesh, and what it says is true",
|
||||||
"status": "skip",
|
"status": "pass",
|
||||||
"seconds": 0,
|
"seconds": 1,
|
||||||
"why": "not attempted — U3 (the anchor runs the module the mesh built) did not succeed"
|
"why": ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "V2",
|
"code": "V2",
|
||||||
"title": "the catalogue holds every module this mesh built",
|
"title": "the catalogue holds every module this mesh built",
|
||||||
"status": "skip",
|
"status": "fail",
|
||||||
"seconds": 0,
|
"seconds": 1,
|
||||||
"why": "not attempted — V1 (the control plane can describe the mesh, and what it says is true) did not succeed"
|
"why": "the catalogue does not hold mesh-tools, postgres — the mesh built them and its own record has no trace of it (novox/hq issue 050):\n{\"modules\":[{\"module\":\"amqp-ping\",\"commit\":\"e0c92195d4240841bfcf4b4a9ef869d5afeca331\",\"repository\":\"https://git.novox.be/novox/mesh-catalog.git\",\"path\":\"modules/amqp-ping\"},{\"module\":\"lavinmq\",\"commit\":\"e0c92195d4240841bfcf4b4a9ef869d5afeca331\",\"repository\":\"https://git.novox.be/novox/mesh-catalog.git\",\"path\":\"modules/lavinmq\"},{\"module\":\"mesh-control\",\"commit\":\"5062c36fc9efe159aa9706c0ca2c873351ef1ce0\",\"repository\":\"https://git.novox.be/novox/mesh-control.git\",\"path\":\"\"}]}\n\n+ actual - expected\n\n+ [\n+ 'mesh-tools',\n+ 'postgres'\n+ ]\n- []\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "V3",
|
"code": "V3",
|
||||||
"title": "the machine's networking is what the modules asked for",
|
"title": "the machine's networking is what the modules asked for",
|
||||||
"status": "skip",
|
"status": "fail",
|
||||||
"seconds": 0,
|
"seconds": 0,
|
||||||
"why": "not attempted — V1 (the control plane can describe the mesh, and what it says is true) did not succeed"
|
"why": "the mesh's own firewall table is not there:\nError: No such file or directory\nlist table inet mesh\n ^^^^\n"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"code": "E1",
|
"code": "E1",
|
||||||
|
|||||||
@@ -85,6 +85,15 @@ const PROVIDER = { module: "lavinmq", repo: "mesh-catalog", path: "modules/lavin
|
|||||||
*/
|
*/
|
||||||
/** The one word that puts a mesh on a private network and gives its machines names. */
|
/** The one word that puts a mesh on a private network and gives its machines names. */
|
||||||
const NETWORK_MODULE = "networking";
|
const NETWORK_MODULE = "networking";
|
||||||
|
/**
|
||||||
|
* The packet filter, which is a module too and was assigned to nothing.
|
||||||
|
*
|
||||||
|
* The rules are generated from what every module declares it listens on, so a mesh with no filter
|
||||||
|
* is not "open by accident" — it is a mesh where the whole of that generation has never run. It
|
||||||
|
* claims a seat (`the-packet-filter`) because a machine has one of these and two things writing
|
||||||
|
* rules is a coin toss about which survives.
|
||||||
|
*/
|
||||||
|
const FILTER_MODULE = "firewall";
|
||||||
const STORE = { module: "postgres", repo: "mesh-catalog", path: "modules/postgres", container: "mesh-postgres" };
|
const STORE = { module: "postgres", repo: "mesh-catalog", path: "modules/postgres", container: "mesh-postgres" };
|
||||||
const CATALOGUE = { module: "mesh-catalog", repo: "mesh-catalog", path: "modules/mesh-catalog", container: "mesh-catalog" };
|
const CATALOGUE = { module: "mesh-catalog", repo: "mesh-catalog", path: "modules/mesh-catalog", container: "mesh-catalog" };
|
||||||
/** The control plane, rebuilt from its own repository — the step that ends the installer's tenure. */
|
/** The control plane, rebuilt from its own repository — the step that ends the installer's tenure. */
|
||||||
@@ -116,6 +125,7 @@ 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";
|
||||||
const CONTROL_REBUILT = "the mesh rebuilds its own control plane from source";
|
const CONTROL_REBUILT = "the mesh rebuilds its own control plane from source";
|
||||||
const NETWORKED = "the mesh puts itself on a private network, and its machine has a name";
|
const NETWORKED = "the mesh puts itself on a private network, and its machine has a name";
|
||||||
|
const FILTERED = "the machine has a packet filter, loaded from what modules declared";
|
||||||
const MODULE_BUILT = "the mesh builds a module standing on that base";
|
const MODULE_BUILT = "the mesh builds a module standing on that base";
|
||||||
const ANCHOR_RUNS = "the anchor runs the module the mesh built";
|
const ANCHOR_RUNS = "the anchor runs the module the mesh built";
|
||||||
const DESCRIBES = "the control plane can describe the mesh, and what it says is true";
|
const DESCRIBES = "the control plane can describe the mesh, and what it says is true";
|
||||||
@@ -376,6 +386,7 @@ const PLAN: { code: string; title: string }[] = [
|
|||||||
{ code: "P3", title: CATALOGUE_RUNS },
|
{ code: "P3", title: CATALOGUE_RUNS },
|
||||||
{ code: "P4", title: CONTROL_REBUILT },
|
{ code: "P4", title: CONTROL_REBUILT },
|
||||||
{ code: "N1", title: NETWORKED },
|
{ code: "N1", title: NETWORKED },
|
||||||
|
{ code: "N2", title: FILTERED },
|
||||||
{ code: "U1", title: MODULE_BUILT },
|
{ code: "U1", title: MODULE_BUILT },
|
||||||
{ code: "U2", title: NEEDS },
|
{ code: "U2", title: NEEDS },
|
||||||
{ code: "U3", title: ANCHOR_RUNS },
|
{ code: "U3", title: ANCHOR_RUNS },
|
||||||
@@ -623,8 +634,29 @@ before(async () => {
|
|||||||
return `${hosts.trim()}\n\n${modules.trim()}`;
|
return `${hosts.trim()}\n\n${modules.trim()}`;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// ---- THE PACKET FILTER -------------------------------------------------------------------------
|
||||||
|
//
|
||||||
|
// Assigned separately from `networking` because they answer different questions: one is how
|
||||||
|
// machines reach each other, the other is what may reach this one. Both were assigned to nothing,
|
||||||
|
// and the second is the more alarming of the two — every rule the mesh generates from module
|
||||||
|
// declarations had never been applied to any machine in this test.
|
||||||
|
await step("N2", FILTERED, NETWORKED, async () => {
|
||||||
|
await mesh(`assign ${CONTROL} ${FILTER_MODULE}`);
|
||||||
|
await mesh(`push ${CONTROL}`, 600_000);
|
||||||
|
const deadline = Date.now() + 180_000;
|
||||||
|
let ruleset = "";
|
||||||
|
while (Date.now() < deadline) {
|
||||||
|
ruleset = (await on(CONTROL, `nft list table inet mesh 2>&1`)).out;
|
||||||
|
if (/chain input/.test(ruleset)) break;
|
||||||
|
await new Promise((r) => setTimeout(r, 5_000));
|
||||||
|
}
|
||||||
|
assert.match(ruleset, /chain input/,
|
||||||
|
`${FILTER_MODULE} is assigned and the machine has no mesh filter:\n${ruleset}`);
|
||||||
|
return ruleset;
|
||||||
|
});
|
||||||
|
|
||||||
// ---- 7..8. SOMETHING TO RUN ---------------------------------------------------------------
|
// ---- 7..8. SOMETHING TO RUN ---------------------------------------------------------------
|
||||||
await step("U1", MODULE_BUILT, NETWORKED, async () => {
|
await step("U1", MODULE_BUILT, FILTERED, async () => {
|
||||||
await registerModule(MODULE.module, resolve(catalogDir, MODULE.module, "module.json"));
|
await registerModule(MODULE.module, resolve(catalogDir, MODULE.module, "module.json"));
|
||||||
const built = await mesh(
|
const built = await mesh(
|
||||||
`build ${forgeUrl(MODULE.repo)} --path ${MODULE.path} --ref ${refFor(MODULE.repo)} --wait 1200s`,
|
`build ${forgeUrl(MODULE.repo)} --path ${MODULE.path} --ref ${refFor(MODULE.repo)} --wait 1200s`,
|
||||||
@@ -863,6 +895,7 @@ for (const name of [
|
|||||||
CATALOGUE_RUNS,
|
CATALOGUE_RUNS,
|
||||||
CONTROL_REBUILT,
|
CONTROL_REBUILT,
|
||||||
NETWORKED,
|
NETWORKED,
|
||||||
|
FILTERED,
|
||||||
MODULE_BUILT,
|
MODULE_BUILT,
|
||||||
NEEDS,
|
NEEDS,
|
||||||
ANCHOR_RUNS,
|
ANCHOR_RUNS,
|
||||||
|
|||||||
Reference in New Issue
Block a user