diff --git a/02-DECISIONS/0048-the-substrate-is-named.md b/02-DECISIONS/0048-the-substrate-is-named.md index 632a3ba..6f2184b 100644 --- a/02-DECISIONS/0048-the-substrate-is-named.md +++ b/02-DECISIONS/0048-the-substrate-is-named.md @@ -40,7 +40,7 @@ Two costs, both already accrued: | message bus | **LavinMQ** | In use, speaks AMQP, which is what [ADR 0001](0001-nodes-communicate-over-a-broker.md) assumes. Interchangeable with other AMQP brokers at the protocol level, which is what makes it a safe choice rather than a locked-in one. | | object store | **MinIO** | In use, speaks the S3 protocol, which is the closest thing to a portable object-store interface. | | image registry | **the OCI distribution registry** | In use, and the format is the standard rather than a vendor's. | -| container runtime | **Docker** | In use. Podman is the plausible alternative and was not chosen for any deficiency — Docker is what the machines run today and what the current tooling assumes. | +| container runtime | **Docker or Podman** — *detected, not chosen* | See below. The other four rows name one product; this one names two, and the difference is the point. | ### Outside the substrate @@ -58,6 +58,15 @@ correction applies — a role is a legitimate abstraction, but the product belon a route is an ordinary grant. Recorded here because finding it was the point — naming the products is what made the unnamed role visible. +**The container runtime is the one row that is not a choice at all**, and it stopped being one +after this record was written ([ADR 0060](0060-the-host-is-built-per-operating-system.md)). The +host detects what the machine has and uses it, because adoption keeps a machine's existing +configuration rather than replacing it — so naming a single runtime here contradicted a rule +already decided. Both are supported, checked against a real podman: only the version probe +differs, and one behavioural difference (podman has no daemon, so containers do not return after +a reboot unless `podman-restart.service` is enabled) belongs in the declaration rather than the +host. + **Identity is deliberately absent.** Whether an identity provider is substrate at all depends on whether the control plane delegates authentication, which is undecided ([`07-the-substrate.md`](../03-DESIGN/01-to-be/07-the-substrate.md)). Naming a product before diff --git a/02-DECISIONS/0057-the-host-is-a-root-service-installed-as-a-package.md b/02-DECISIONS/0057-the-host-is-a-root-service-installed-as-a-package.md index dde2109..c897138 100644 --- a/02-DECISIONS/0057-the-host-is-a-root-service-installed-as-a-package.md +++ b/02-DECISIONS/0057-the-host-is-a-root-service-installed-as-a-package.md @@ -63,18 +63,29 @@ That split is the tier boundary made concrete rather than an inconsistency. ### What it needs from an init, and why that is not a dependency -The host needs four things from whatever supervises it: start at boot, restart when it exits, -give up after repeated failures, and run something else when it gives up. +> **Overtaken by [ADR 0061](0061-the-host-asks-an-init-for-start-and-restart.md) and +> [ADR 0060](0060-the-host-is-built-per-operating-system.md).** All three claims below were +> true when written and are not now. Kept rather than rewritten, because what changed and why +> is the useful part. -**Every machine the mesh targets already has systemd**, and the host already treats the service -manager as a detected capability rather than an assumption. This is not a dependency in -[ADR 0041](0041-the-host-depends-on-nothing.md)'s sense — 0041 is about what must be *installed -before the host works*, and an init is not installed, it is what the machine already is. +~~The host needs **four** things from whatever supervises it: start at boot, restart when it +exits, give up after repeated failures, and run something else when it gives up.~~ **One**: run +this at boot. The other three moved into a launcher the host ships, where they can be tested — +a unit file's restart policy can only be read and hoped for +([ADR 0061](0061-the-host-asks-an-init-for-start-and-restart.md)). -**Abstracting over init systems is not done**, because there is no second one to abstract over. -The unit file is the only systemd-specific artefact, it belongs to the package rather than the -binary, and a machine with a different supervisor would ship a different package — which is -where that difference belongs. +~~**Every machine the mesh targets already has systemd.**~~ **Alpine does not**, and it is the +intended first node. It runs OpenRC. + +~~**Abstracting over init systems is not done, because there is no second one to abstract +over.**~~ There is now, and the answer is still not an abstraction: the host is built per +operating system ([ADR 0060](0060-the-host-is-built-per-operating-system.md)), so each ships its +own four-line init file. That the file is the *only* system-specific artefact is what survives, +and it is what makes a second one transcription rather than a port. + +The part that stands unchanged: **an init is not a dependency in +[ADR 0041](0041-the-host-depends-on-nothing.md)'s sense.** 0041 is about what must be *installed +before the host works*, and an init is not installed — it is what the machine already is. ### It never manages its own unit diff --git a/02-DECISIONS/0060-the-host-is-built-per-operating-system.md b/02-DECISIONS/0060-the-host-is-built-per-operating-system.md index 40c8d99..14e84bb 100644 --- a/02-DECISIONS/0060-the-host-is-built-per-operating-system.md +++ b/02-DECISIONS/0060-the-host-is-built-per-operating-system.md @@ -54,8 +54,15 @@ arrive together, as one decision somebody made when they installed the operating ### Almost all of it is shared Not a rewrite per operating system. The declaration vocabulary, the store, the apply loop, the -read-back discipline, the refusal model, the bundle and the link are all portable. **What differs -is two appliers**, and the rest is compiled around them. +read-back discipline, the refusal model and the link are all portable. **What differs is two +appliers**, and the rest is compiled around them. + +**The bundle is the exception, and an earlier version of this record wrongly listed it as +portable.** Its *mechanism* is — one embedded declaration, applied with no mesh present. Its +*contents* are not: package names, unit names and service names all differ, so an Arch host +embeds an Arch bundle and an Alpine host an Alpine one. That is the same thing this record says +about package names one section down, and missing it here is what made the distinction hard to +see. ### The control plane names the package, because the host does not decide diff --git a/03-DESIGN/01-to-be/05-the-node-host.md b/03-DESIGN/01-to-be/05-the-node-host.md index 4f0af0f..d4612bc 100644 --- a/03-DESIGN/01-to-be/05-the-node-host.md +++ b/03-DESIGN/01-to-be/05-the-node-host.md @@ -13,6 +13,7 @@ decisions: - 02-DECISIONS/0041-the-host-depends-on-nothing.md - 02-DECISIONS/0043-a-declaration-is-an-ordered-list-of-owned-resources.md - 02-DECISIONS/0057-the-host-is-a-root-service-installed-as-a-package.md + - 02-DECISIONS/0060-the-host-is-built-per-operating-system.md - 02-DECISIONS/0061-the-host-asks-an-init-for-start-and-restart.md --- @@ -131,14 +132,18 @@ manages units and runs containers. Two steps, and there is nothing else: ``` -# 1 — put the host on the machine -pacman -S nox-mesh-host -systemctl enable --now nox-mesh-host +# 1 — put the host on the machine, in that machine's own idiom +apk add nox-mesh-host && rc-update add nox-mesh-host && rc-service nox-mesh-host start +pacman -S nox-mesh-host && systemctl enable --now nox-mesh-host -# 2 — hand it the mesh +# 2 — hand it the mesh. The same on every machine. nox-mesh-host enrol --token ``` +**Step 1 differs per system and step 2 never does**, which is the shape of +[ADR 0060](../../02-DECISIONS/0060-the-host-is-built-per-operating-system.md): the package +manager and the init file are the system's, and everything after them is the mesh's. + The token carries the broker's address, the fingerprint to expect, and the right to join ([ADR 0051](../../02-DECISIONS/0051-the-enrolment-token-carries-the-mesh.md)). After that the node is in the mesh and takes declarations like every other one. diff --git a/03-DESIGN/01-to-be/07-the-substrate.md b/03-DESIGN/01-to-be/07-the-substrate.md index be0ddea..b48310b 100644 --- a/03-DESIGN/01-to-be/07-the-substrate.md +++ b/03-DESIGN/01-to-be/07-the-substrate.md @@ -11,6 +11,7 @@ decisions: - 02-DECISIONS/0047-the-bundle-may-carry-actions-the-link-may-not.md - 02-DECISIONS/0048-the-substrate-is-named.md - 02-DECISIONS/0049-a-route-is-a-grant.md + - 02-DECISIONS/0060-the-host-is-built-per-operating-system.md --- # The substrate @@ -118,7 +119,7 @@ is what keeps the bundle small enough for a person to read and check. The order, from [research 011](../../01-RESEARCH/011-the-module-graph/worked-provider.md): ``` -0 Docker exists detected, or installed as a package +0 a container runtime exists detected — docker or podman — or installed 1 PostgreSQL runs pulled by digest, from the bundle 2 a database is created in it an action, run locally 3 the control plane's schema applied an action, against that database @@ -131,8 +132,13 @@ Only PostgreSQL is raised from the bundle, for the reason in *The pinned bundle* rest of the substrate is wanted only once there is a control plane to provision it. **Step 0 is easy to leave out and it is where several things meet.** A substrate service is a -container, so Docker must be running before anything else happens — and Docker is a *package*, -not a container. It is: +container, so a container runtime must be working before anything else happens — and a runtime +is a *package*, not a container. + +**Which runtime is detected, not chosen** +([ADR 0060](../../02-DECISIONS/0060-the-host-is-built-per-operating-system.md)): a machine that +already has one keeps it. On a machine with none, the control plane names the package, because +what it is called differs per system. It is: - what the host's capability detection already reports, and the first use of that report by something other than a person; diff --git a/03-DESIGN/01-to-be/09-the-node-lifecycle.md b/03-DESIGN/01-to-be/09-the-node-lifecycle.md index e5d1fbe..991bc2f 100644 --- a/03-DESIGN/01-to-be/09-the-node-lifecycle.md +++ b/03-DESIGN/01-to-be/09-the-node-lifecycle.md @@ -12,6 +12,7 @@ decisions: - 02-DECISIONS/0051-the-enrolment-token-carries-the-mesh.md - 02-DECISIONS/0057-the-host-is-a-root-service-installed-as-a-package.md - 02-DECISIONS/0058-delivery-ends-in-a-declaration.md + - 02-DECISIONS/0060-the-host-is-built-per-operating-system.md - 02-DECISIONS/0061-the-host-asks-an-init-for-start-and-restart.md --- @@ -51,17 +52,32 @@ same path, in an unusual order. ## unmanaged → hosted: installing +In the machine's own idiom, because the package manager and the init file are the system's +([ADR 0060](../../02-DECISIONS/0060-the-host-is-built-per-operating-system.md)): + ``` +# Alpine — the intended first node +apk add nox-mesh-host +rc-update add nox-mesh-host && rc-service nox-mesh-host start + +# Arch pacman -S nox-mesh-host systemctl enable --now nox-mesh-host ``` +Two lines each, and the init file behind them is four +([ADR 0061](../../02-DECISIONS/0061-the-host-asks-an-init-for-start-and-restart.md)) — it says +*run the launcher at boot* and nothing else, so a third system is transcription rather than a +port. + Or, where there is no repository to install from: ``` -curl -fsSL https:///mesh-host--x86_64.tar.gz | tar -xz -C /usr/local/bin +curl -fsSL https:///mesh-host---x86_64.tar.gz | tar -xz -C /usr/local/bin ``` +**The binary is per system as well as per architecture**, because two of its appliers are. + **The tarball must never acquire a dependency**, because the mesh's own package repository is hosted on the mesh. Any route that needs the mesh in order to install the thing that joins the mesh is a circle — unusable on a first node, and unusable by whoever is repairing a mesh that is @@ -159,8 +175,8 @@ mesh-control token issue nox-mesh-host enrol --token ``` -Step 1 is the bootstrap from [`07-the-substrate.md`](07-the-substrate.md): Docker, then -PostgreSQL, then the database, then the schema, then the control plane. It needs no identity +Step 1 is the bootstrap from [`07-the-substrate.md`](07-the-substrate.md): a container runtime, +then PostgreSQL, then the database, then the schema, then the control plane. It needs no identity because nothing is being asked of anyone — the host is applying a declaration it already carries, to the machine it is already on. @@ -377,7 +393,9 @@ the test of whether this is really uniform. 2 the host verifies the new binary runs `nox-mesh-host version`, as a subprocess 3 it finishes the apply and reports never mid-way 4 it exits 0 having finished, not having been stopped -5 systemd restarts it on the new binary +5 the launcher starts it again on the new binary — it supervises the host + rather than exec'ing it (ADR 0061), so this + needs nothing from the init 6 the new host reconciles on start trigger 1, confirming the machine still matches ```