Adoption bed (in progress): a machine in use raised adopted, held, opened through its firewall, taken and converged (hq ADR 0100-0103)
This commit is contained in:
@@ -26,6 +26,8 @@ export interface GenesisResult {
|
||||
step: string;
|
||||
why: string;
|
||||
report: string[];
|
||||
/** Everything the installer printed on its last attempt — what a bed asserts a refusal names. */
|
||||
said: string;
|
||||
}
|
||||
|
||||
export interface GenesisOptions {
|
||||
@@ -80,6 +82,23 @@ export interface GenesisOptions {
|
||||
hostBinary?: string;
|
||||
/** What of the catalogue to build. A branch under test is the usual reason this is not main. */
|
||||
catalogRef?: string;
|
||||
/**
|
||||
* Raise the machine adopted (novox/hq ADR 0100): what it runs and its firewall are kept. Without
|
||||
* it the installer raises a converged node, and refuses a machine in use.
|
||||
*/
|
||||
adopted?: boolean;
|
||||
/** Further installer flags, as the operator would type them — `--registry-port 5100`, `--dry-run`. */
|
||||
flags?: string[];
|
||||
/**
|
||||
* How many times to run the installer. Three by default, for a pull the internet rate-limited; a
|
||||
* bed that expects a REFUSAL runs it once, because a refusal is the answer, not a flake.
|
||||
*/
|
||||
attempts?: number;
|
||||
/**
|
||||
* Whether to ask the machine if it became a working mesh of one afterwards. Off for a run that is
|
||||
* not meant to raise one — a dry run, or a refusal the bed expects.
|
||||
*/
|
||||
verify?: boolean;
|
||||
log?: (m: string) => void;
|
||||
}
|
||||
|
||||
@@ -98,9 +117,10 @@ export async function genesis(o: GenesisOptions): Promise<GenesisResult> {
|
||||
const log = o.log ?? (() => {});
|
||||
|
||||
const report: string[] = [`================ GENESIS: ${node} becomes a mesh of one ================`];
|
||||
let said = "";
|
||||
const stop = (step: string, why: string): GenesisResult => {
|
||||
report.push(`\nSTOPPED at ${step || "(no step named)"}: ${why}`);
|
||||
return { ok: false, step, why, report };
|
||||
return { ok: false, step, why, report, said };
|
||||
};
|
||||
|
||||
const on = async (command: string, timeoutMs?: number): Promise<{ out: string; ok: boolean }> => {
|
||||
@@ -136,7 +156,9 @@ export async function genesis(o: GenesisOptions): Promise<GenesisResult> {
|
||||
// the lab stands in for that by copying the whole tree once.
|
||||
const bundleTar = join(tmpdir(), `mesh-lab-catalogue-${process.pid}-${node}.tar`);
|
||||
execFileSync("tar", ["-cf", bundleTar, "-C", o.catalogDir, "."]);
|
||||
await must(`mkdir -p ${catalogueOnMachine}/modules`);
|
||||
// Cleared first: a bed that runs genesis more than once (a refusal, then the raise) finds the last
|
||||
// run's staging files, and the machine refuses to open them for the push.
|
||||
await must(`rm -f /tmp/catalogue.tar /tmp/foundation-template.lock && mkdir -p ${catalogueOnMachine}/modules`);
|
||||
await push(o.instanceId, node, bundleTar, "/tmp/catalogue.tar");
|
||||
await must(`tar -xf /tmp/catalogue.tar -C ${catalogueOnMachine}/modules`);
|
||||
// The three genesis itself needs must be present, or the pivot cannot even begin — checked here
|
||||
@@ -184,6 +206,8 @@ export async function genesis(o: GenesisOptions): Promise<GenesisResult> {
|
||||
`--private-network wireguard`,
|
||||
`--packet-filter nftables`,
|
||||
`--host ${HOST_PATH}`,
|
||||
...(o.adopted ? [`--adopted`] : []),
|
||||
...(o.flags ?? []),
|
||||
// A service when the packaging was installed above (survives a reboot); otherwise the
|
||||
// background process, which does not — the installer refuses to invent a unit either way.
|
||||
...(o.hostService ? [] as string[] : [`--host-in-background`]),
|
||||
@@ -193,20 +217,24 @@ export async function genesis(o: GenesisOptions): Promise<GenesisResult> {
|
||||
// but because the installer is idempotent by design and says so, and because the one thing that
|
||||
// fails for a reason which goes away by itself is a pull: the store, broker and registry come
|
||||
// from the internet, and a rate-limited anonymous pull is not this mesh's fault.
|
||||
let said = "";
|
||||
let step = "";
|
||||
for (let attempt = 1; attempt <= 3; attempt++) {
|
||||
const attempts = o.attempts ?? 3;
|
||||
for (let attempt = 1; attempt <= attempts; attempt++) {
|
||||
const ran = await on(command, 2_400_000);
|
||||
said = ran.out;
|
||||
log(`\n---- mesh-bootstrap on ${node} (attempt ${attempt}) ----\n${said}`);
|
||||
if (ran.ok) { step = ""; break; }
|
||||
step = stepIn(said);
|
||||
if (attempt < 3) {
|
||||
step = stepIn(said) || "an unnamed step";
|
||||
if (attempt < attempts) {
|
||||
log(`genesis attempt ${attempt} stopped at ${step || "an unnamed step"}; re-running in 30s`);
|
||||
await new Promise((r) => setTimeout(r, 30_000));
|
||||
}
|
||||
}
|
||||
if (step) return stop(step, said.split("\n").filter(Boolean).slice(-6).join("\n"));
|
||||
if (o.verify === false) {
|
||||
report.push(`\nThe installer finished; not asked whether it raised a mesh (verify: false).`);
|
||||
return { ok: true, step: "", why: "", report, said };
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------------------------
|
||||
// Is it a WORKING MESH OF ONE? Asked of the machine, never inferred from the installer exiting
|
||||
@@ -286,5 +314,5 @@ export async function genesis(o: GenesisOptions): Promise<GenesisResult> {
|
||||
}
|
||||
|
||||
report.push(`\nVERDICT: ${node} is a working mesh of one, bootstrapped through the installer.`);
|
||||
return { ok: true, step: "", why: "", report };
|
||||
return { ok: true, step: "", why: "", report, said };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user