74 lines
3.7 KiB
Markdown
74 lines
3.7 KiB
Markdown
---
|
|
status: located
|
|
opened: 2026-09-22
|
|
located-in: [mesh-catalog, mesh-controller internal/catalogue]
|
|
fixed-by:
|
|
amended-design:
|
|
---
|
|
|
|
# 093 — The successor proxy cannot serve what the predecessor still serves
|
|
|
|
## What was observed
|
|
|
|
On the control-node, hours after it was adopted, 2026-09-22.
|
|
|
|
Assigning the first web module to the adopted node was refused:
|
|
|
|
```
|
|
nothing provides "route", wanted by <module>
|
|
```
|
|
|
|
Every module that must be reachable by name requires a **route**, and the mesh has one provider of
|
|
it: its own proxy. That proxy runs on the machine's own network and binds the two public ports
|
|
directly. It declares no port mapping, so a node's `ports` setting cannot move it
|
|
([ADR 0100](../../02-DECISIONS/0100-a-node-in-use-is-adopted-before-it-is-converged.md) moves a
|
|
*published mapping*). The predecessor's proxy holds those ports and serves every public name on
|
|
the machine. The two cannot run at once.
|
|
|
|
So there is a circle:
|
|
|
|
- a web module cannot be taken until the mesh's proxy runs;
|
|
- the mesh's proxy cannot run until the predecessor's stops;
|
|
- when the predecessor's stops, **every name it serves goes dark** — because the mesh's proxy
|
|
serves only what mesh modules contributed, and the predecessor's services are not modules yet.
|
|
|
|
Adoption was built for exactly this shape and does not cover it. It keeps a **file** as it was and
|
|
a **container** as it was, holding each until its module is taken. It has nothing to say about a
|
|
service whose successor is *different software*: the predecessor's proxy and the mesh's read
|
|
different configuration and share no container name, so there is nothing to hold — only something
|
|
to replace, all at once, for every name at the same moment.
|
|
|
|
## Why it matters beyond this instance
|
|
|
|
The proxy is the first case, not the only one. Any provision with exactly one provider that owns a
|
|
scarce machine-wide resource has this shape: a resolver on port 53, a mail relay on 25, a
|
|
certificate authority. The migration's rule — one service at a time, each when its data has moved
|
|
— holds only while the successor can stand beside the predecessor. Where it cannot, the mesh
|
|
currently offers no way to take one step at a time.
|
|
|
|
It also decides the migration's order. The runbook had the proxy last, as the tidy final cutover.
|
|
It has to be first, because everything reachable by name waits on it.
|
|
|
|
## Open questions
|
|
|
|
- Should the mesh's proxy be able to serve routes it did not derive — a predecessor's names, given
|
|
to it as the operator's own configuration, each disappearing when the module that owns that name
|
|
contributes its route? That keeps the predecessor's configuration alive under the mesh's proxy,
|
|
which is what adoption promises everywhere else.
|
|
- Or should a provision be satisfiable by an **adapter**: a module that provides `route` by writing
|
|
into the predecessor's proxy, so modules migrate one at a time while the predecessor still
|
|
serves, and the proxy itself is taken last?
|
|
- What becomes of the certificates in either case? The predecessor holds them; the successor would
|
|
otherwise ask a public authority for every name at the moment of the cutover.
|
|
- Is there a general rule here for "a requirement whose only provider owns a scarce port", or is
|
|
each such provision its own decision?
|
|
|
|
## Decided
|
|
|
|
*2026-09-22.* [ADR 0104](../../02-DECISIONS/0104-a-provision-may-be-answered-by-an-adapter-to-the-predecessor.md):
|
|
during a migration, a provision whose only provider owns a scarce machine-wide resource may be
|
|
answered by an **adapter** that writes into the predecessor's own configuration. For the route,
|
|
the predecessor's proxy keeps serving every name and keeps its certificates, while each migrated
|
|
module's name is pointed at the mesh's container. The proxy is the last cutover again, and by then
|
|
every route is one the mesh contributed.
|