94 lines
5.1 KiB
Markdown
94 lines
5.1 KiB
Markdown
---
|
|
topic: the mesh
|
|
status: accepted
|
|
date: 2026-09-22
|
|
deciders: jochen
|
|
reconstructed: false
|
|
extends: 02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md
|
|
---
|
|
|
|
# 104. A provision may be answered by an adapter to the predecessor
|
|
|
|
## Context
|
|
|
|
[Issue 093](../04-ISSUES/093-the-successor-proxy-cannot-serve-what-the-predecessor-still-serves/00-report.md),
|
|
found on the first adopted node hours after it was raised. Every module reachable by name requires
|
|
a **route**. The mesh has one provider of it, its own proxy, which binds the two public ports on
|
|
the machine's own network. The predecessor's proxy holds those ports and serves every public name
|
|
there. So:
|
|
|
|
- a web module cannot be taken until the mesh's proxy runs;
|
|
- the mesh's proxy cannot run until the predecessor's stops;
|
|
- and when it stops, every name the predecessor served goes dark, because the mesh's proxy serves
|
|
only what mesh modules have contributed.
|
|
|
|
Adoption ([ADR 0100](0100-a-node-in-use-is-adopted-before-it-is-converged.md)) keeps a *file* as it
|
|
was and a *container* as it was. It has nothing for a service whose successor is **different
|
|
software**: nothing shares a name to hold, so there is only replacement, of every name at once.
|
|
|
|
The certificates decide the rest. The predecessor's proxy holds them and renews them. A successor
|
|
taking over first would have to obtain a certificate for every public name in the same window in
|
|
which it took the ports — with nothing else migrated yet, and the only way back being to start the
|
|
predecessor again.
|
|
|
|
## Considered Options
|
|
|
|
1. **The successor proxy serves routes it did not derive**, given as the operator's configuration,
|
|
each disappearing as the module owning that name contributes its own. Rejected for the
|
|
migration: it puts the riskiest step first, and it puts configuration the mesh does not own
|
|
into the one component whose design is that the mesh derives its configuration.
|
|
2. **Take the proxy first and accept the window.** Rejected: every public name at once, before
|
|
anything else has moved, with certificates to obtain in the same window.
|
|
3. **Make the requirement optional**, so a module can be taken while nothing provides route.
|
|
Rejected: it is not optional. A module that says it must be reachable and is not is a module
|
|
reporting success while serving nobody.
|
|
4. **An adapter module provides the provision by writing into the predecessor's service.** Adopted.
|
|
|
|
## Decision
|
|
|
|
**A provision whose only provider owns a scarce machine-wide resource may be answered, during a
|
|
migration, by an adapter module that writes into the predecessor's own configuration.**
|
|
|
|
For the route: a module that **provides `route`**, receives every contribution as the proxy does,
|
|
and writes each one as a route file where the predecessor's proxy reads its configuration —
|
|
pointing at the machine port the contributing module now publishes. The predecessor's proxy keeps
|
|
serving every name it already serves, keeps its certificates and keeps renewing them; a name whose
|
|
module has migrated is served by the same proxy, pointing at the mesh's container instead of the
|
|
predecessor's.
|
|
|
|
**It is migration scaffolding and says so.** It is assigned only on an adopted node, it writes only
|
|
files it can name as its own, and it is removed when the predecessor's proxy retires — at which
|
|
point the mesh's own proxy takes the ports and already knows every route, because by then every
|
|
name belongs to a module that contributes it.
|
|
|
|
**This does not make the mesh the predecessor's manager.** The adapter writes route files and
|
|
nothing else, and only because the predecessor's control has been stopped by the operator, which
|
|
ADR 0100 requires before a node is adopted.
|
|
|
|
## Consequences
|
|
|
|
- The migration keeps its shape: one service at a time, each reversible on its own. The proxy is
|
|
the **last** cutover again, not the first.
|
|
- There is no certificate event until the end, and at the end there is one, for a proxy that
|
|
already has every route from the mesh.
|
|
- The mesh writes into a directory the predecessor owns. That is safe only while the predecessor's
|
|
control is stopped, and it is why the adapter is refused on a converged node.
|
|
- The adapter is throwaway code with a stated end. Something has to delete it; that something is
|
|
the operator, and the flip is the moment.
|
|
- A second provision with this shape — a resolver on 53, a mail relay on 25 — now has a pattern to
|
|
follow rather than a new argument to have.
|
|
|
|
## How it is checked
|
|
|
|
Unit tests hold the adapter to writing one route file per contribution, naming each file as its
|
|
own, removing a file when its contribution goes, and leaving every file it did not write. The
|
|
controller is held to resolving `route` from it exactly as from the proxy. The adoption lab bed
|
|
gains a step: with the predecessor's proxy serving a name, a module taken behind the adapter is
|
|
reachable under that name, and the predecessor's own names keep answering. Assigning the adapter
|
|
to a converged node is refused.
|
|
|
|
## References
|
|
|
|
- [Issue 093](../04-ISSUES/093-the-successor-proxy-cannot-serve-what-the-predecessor-still-serves/00-report.md)
|
|
- [ADR 0100](0100-a-node-in-use-is-adopted-before-it-is-converged.md), [ADR 0007](0007-connectivity.md)
|