|
|
|
@@ -0,0 +1,161 @@
|
|
|
|
|
---
|
|
|
|
|
topic: what runs on it
|
|
|
|
|
status: proposed
|
|
|
|
|
date: 2026-09-25
|
|
|
|
|
deciders: jochen
|
|
|
|
|
reconstructed: false
|
|
|
|
|
extends: 0046-a-module-configuration-is-its-assignments-not-its-manifest.md
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
# 112. A module definition names no node, no mesh and no path: everything it needs is resolved at assignment
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
[Issue 118](../04-ISSUES/118-a-module-definition-decides-where-its-files-live/00-report.md) found
|
|
|
|
|
**789 host-path strings in 70 of the catalogue's 71 module definitions.** Each definition chooses
|
|
|
|
|
where on the machine its directories, mounts, bindings, secrets, env-files and received files live,
|
|
|
|
|
and often repeats that path in an environment variable or in code. Mounts are checked against what
|
|
|
|
|
the definition declares ([ADR 0091](0091-a-mount-is-declared-three-ways.md)); nothing checks the
|
|
|
|
|
copies. The issue records what that has already allowed:
|
|
|
|
|
|
|
|
|
|
- a provider that would provision nobody without a word;
|
|
|
|
|
- a contributions file that carries host paths into containers, so every provider must mount its
|
|
|
|
|
grants directory at the identical path;
|
|
|
|
|
- defaults in code that disagree with their own manifests;
|
|
|
|
|
- no way to assign one module to one node twice, because every identity is keyed by the module's name.
|
|
|
|
|
|
|
|
|
|
**The mesh has already decided this once, for ports.** [ADR 0038](0038-the-mesh-assigns-the-port.md):
|
|
|
|
|
the mesh assigns the machine-side port and the module says only what it needs, and three copies
|
|
|
|
|
became one fact. [ADR 0046](0046-a-module-configuration-is-its-assignments-not-its-manifest.md)
|
|
|
|
|
made the manifest identity and defaults, and the assignment's settings the configuration.
|
|
|
|
|
[ADR 0084](0084-which-provider-serves-a-consumer.md) made which provider serves a consumer part of
|
|
|
|
|
the assignment. Paths are the largest thing still left in the definition.
|
|
|
|
|
|
|
|
|
|
## Considered Options
|
|
|
|
|
|
|
|
|
|
**1. Keep host paths in definitions, and check that every copy agrees.** Rejected. It checks the
|
|
|
|
|
agreement of something that should not be there. A definition still could not follow its data to
|
|
|
|
|
another disk, be adopted onto a machine whose data is already somewhere, or run twice on one node.
|
|
|
|
|
|
|
|
|
|
**2. Keep host paths in definitions, and have the mesh rewrite them per assignment.** Rejected. It is
|
|
|
|
|
string surgery on paths: deciding which strings are machine paths by their shape, which is the
|
|
|
|
|
inference this repository has refused elsewhere. And the definition would still read as though it
|
|
|
|
|
decided where things live.
|
|
|
|
|
|
|
|
|
|
**3. A definition names variables, and the assignment resolves them.** Chosen.
|
|
|
|
|
|
|
|
|
|
## Decision
|
|
|
|
|
|
|
|
|
|
**A module definition is node-agnostic and mesh-agnostic.** It names no node, no mesh and no host
|
|
|
|
|
path. Everything that makes a running instance *this* instance is a variable.
|
|
|
|
|
|
|
|
|
|
**Installing a module on a node resolves every variable, or refuses.** A refusal names each
|
|
|
|
|
unresolved variable and what could answer it. Variables are answered from three sources:
|
|
|
|
|
|
|
|
|
|
1. **The assignment's own configuration.** Values chosen for this module on this node, carried as
|
|
|
|
|
settings ([ADR 0046](0046-a-module-configuration-is-its-assignments-not-its-manifest.md)). An
|
|
|
|
|
endpoint binding a public name to a port is one.
|
|
|
|
|
2. **Provisions, resolved by the mesh against a contract.** What other modules provide: a database,
|
|
|
|
|
a bucket, a vhost, a secret. Each comes with the contract the mesh and the module's
|
|
|
|
|
specification define. Where a provision has several providers, which one answers is part of the
|
|
|
|
|
assignment ([ADR 0084](0084-which-provider-serves-a-consumer.md)), so a module may take its
|
|
|
|
|
database from another node. Some have one provider per mesh by decision: a module's own secret
|
|
|
|
|
is a `secret` provision the controller mints and the vault records
|
|
|
|
|
([ADR 0085](0085-a-secret-is-a-provision.md), as amended). Whether the vault should instead
|
|
|
|
|
generate a secret against its contract is an open question, raised while reviewing this, and not
|
|
|
|
|
decided here.
|
|
|
|
|
3. **What the mesh generates or knows.** The credential the controller mints for each provision a
|
|
|
|
|
module takes ([ADR 0048](0048-a-provider-creates-the-credential-the-mesh-minted.md)), the ports it
|
|
|
|
|
assigns ([ADR 0038](0038-the-mesh-assigns-the-port.md)), facts about the machine.
|
|
|
|
|
|
|
|
|
|
**A directory is a provision, provided by the node's host.** A module requires one by name, such as
|
|
|
|
|
its configuration or its data. Its contract is the owner and mode it needs, including the owner its
|
|
|
|
|
image expects ([ADR 0107](0107-persistent-data-is-a-directory-bind-never-a-named-volume.md)). It
|
|
|
|
|
carries no persistence flag. A directory is kept while it holds anything
|
|
|
|
|
([ADR 0030](0030-data-outlives-the-mesh-that-declared-it.md), which refused a `keep` flag for good
|
|
|
|
|
reason), and data that is disposable is not a directory at all but a named volume (0107).
|
|
|
|
|
|
|
|
|
|
*Where* a directory is on the machine is the assignment's. A node has a default layout, and an
|
|
|
|
|
assignment may place one directory elsewhere: on a second disk, or where an adopted machine's data
|
|
|
|
|
already is ([ADR 0100](0100-a-node-in-use-is-adopted-before-it-is-converged.md)). A directory is
|
|
|
|
|
always provided on the module's own node, because a host path means nothing on any other.
|
|
|
|
|
|
|
|
|
|
**An operator's shared data stays an `access`** ([ADR 0051](0051-shared-data-is-the-operators.md)),
|
|
|
|
|
not a directory provision. 0051 rejected giving a directory an operator owner, because the mesh
|
|
|
|
|
must never create, chown or remove such data, and that stands. What changes is only where its
|
|
|
|
|
location is written: the module says it needs read or read-write access, and the assignment says
|
|
|
|
|
where the data is.
|
|
|
|
|
|
|
|
|
|
**Inside a container, a module sees its own paths.** The definition says where the image expects
|
|
|
|
|
each directory. The mesh mounts the assignment's location there. No host path is ever a value a
|
|
|
|
|
process reads.
|
|
|
|
|
|
|
|
|
|
**The mesh's own files carry no host path.** Bindings, secrets and contributions are named relative
|
|
|
|
|
to where the module receives them, so a provider reads what it was given without mounting anything
|
|
|
|
|
at a machine-identical path.
|
|
|
|
|
|
|
|
|
|
**An assignment has an identity of its own: an instance name**, defaulting to the module's name.
|
|
|
|
|
Everything keyed by the module's name today is keyed by the instance instead: directories,
|
|
|
|
|
container names, the login a consumer presents, broker accounts, a claim's holder, the settings
|
|
|
|
|
an assignment carries, and a provider's identity. So **one module may be assigned to one node more
|
|
|
|
|
than once.** What must stay singular stays so by a claim, or by the assignment's own configuration
|
|
|
|
|
colliding: a public name already taken is refused like any other singular thing.
|
|
|
|
|
|
|
|
|
|
## What this changes in earlier records
|
|
|
|
|
|
|
|
|
|
On acceptance, each of these is amended by a record of its own, not edited:
|
|
|
|
|
|
|
|
|
|
- [ADR 0051](0051-shared-data-is-the-operators.md): an access keeps its shape and its semantics; its
|
|
|
|
|
path moves from the definition to the assignment.
|
|
|
|
|
- [ADR 0091](0091-a-mount-is-declared-three-ways.md): a mount's host side is a resolved variable,
|
|
|
|
|
checked as resolved rather than as a path the definition declares.
|
|
|
|
|
- [ADR 0046](0046-a-module-configuration-is-its-assignments-not-its-manifest.md): settings are
|
|
|
|
|
addressed to an instance, not to a module on a node.
|
|
|
|
|
- [ADR 0084](0084-which-provider-serves-a-consumer.md): a provider is a (node, instance) pair, not a
|
|
|
|
|
(node, module) pair, so a consumer can name one of two instances on one node.
|
|
|
|
|
- The [glossary](../00-META/glossary.md): *provision* widens from "a service one module provides" to
|
|
|
|
|
include a directory the node's host provides, and *instance* is added. Neither lands while this
|
|
|
|
|
record is only proposed, because the glossary is the authority on the words in use, not on words
|
|
|
|
|
under review.
|
|
|
|
|
|
|
|
|
|
## Consequences
|
|
|
|
|
|
|
|
|
|
- **Every definition changes.** 70 of 71 name host paths today. The change is mechanical for most.
|
|
|
|
|
The design has to say how existing modules migrate without their data moving: an adopted or
|
|
|
|
|
already-running assignment is placed where its data already is.
|
|
|
|
|
- The controller resolves variables at assignment and refuses unresolved ones. The host provides
|
|
|
|
|
directories. The contributions file's format changes, and so does the SDK's reconcile loop that
|
|
|
|
|
reads it.
|
|
|
|
|
- Identity moves from the module to the instance, which touches logins, broker accounts, settings,
|
|
|
|
|
provider selection and every resource name.
|
|
|
|
|
- **What got harder:** a definition no longer says where a module's data is on a machine. The
|
|
|
|
|
assignment does, and `plan` shows it. That is the point, and it is also a real loss of
|
|
|
|
|
at-a-glance legibility, which the overview has to give back.
|
|
|
|
|
- **Not decided here:** the variable syntax; a node's default layout; whether a second instance of a
|
|
|
|
|
module is supported from the first step or after the definitions have moved; whether the vault
|
|
|
|
|
generates secrets.
|
|
|
|
|
|
|
|
|
|
## How it is checked
|
|
|
|
|
|
|
|
|
|
| Rule | Checked by |
|
|
|
|
|
|---|---|
|
|
|
|
|
| A definition names no host path | A catalogue test: the host side of every mount, and every resource location, binding, secret, receives and grants entry, is a variable rather than an absolute path. A declared list of exceptions shrinks to empty as definitions move. |
|
|
|
|
|
| No host path is a value a process reads | A catalogue test: every absolute path in a container's environment or env-files lies on the container side of one of its mounts, or is declared the image's own. A second test finds literal paths in module code used as fallbacks for an environment variable. |
|
|
|
|
|
| A definition names no node and no mesh | The parser has no field that names a node; a node is named only in an assignment. A catalogue test finds no domain name in any definition value. |
|
|
|
|
|
| Installation resolves every variable | A resolution test with one variable unanswered: refused, naming the variable and its possible sources. |
|
|
|
|
|
| A directory is provided on its module's own node | A resolution test: an assignment placing a directory on another node is refused. |
|
|
|
|
|
| A provider reads what it was given without an identical mount | A provisioner test reading a contributions file whose credentials are named relative to where it is mounted. |
|
|
|
|
|
| A module can run twice on one node | A resolution test assigning one module twice under two instance names: two directories, two logins, two containers, separate settings, no collision. |
|
|
|
|
|
| A public name already taken is refused | A resolution test: a second instance asking for a public name the first holds is refused, naming the first. |
|
|
|
|
|
| An adopted assignment is placed where its data is | An adoption test: the directory resolves to the data's existing location, and nothing is moved. |
|
|
|
|
|
|
|
|
|
|
## References
|
|
|
|
|
|
|
|
|
|
- [Issue 118](../04-ISSUES/118-a-module-definition-decides-where-its-files-live/00-report.md): the evidence
|
|
|
|
|
- [ADR 0038](0038-the-mesh-assigns-the-port.md): the same decision, for ports
|
|
|
|
|
- [ADR 0046](0046-a-module-configuration-is-its-assignments-not-its-manifest.md): configuration is the assignment's
|
|
|
|
|
- [ADR 0084](0084-which-provider-serves-a-consumer.md): which provider answers is the assignment's
|
|
|
|
|
- [ADR 0085](0085-a-secret-is-a-provision.md), [ADR 0048](0048-a-provider-creates-the-credential-the-mesh-minted.md):
|
|
|
|
|
secrets as a provision, and who mints what
|
|
|
|
|
- [ADR 0051](0051-shared-data-is-the-operators.md), [ADR 0107](0107-persistent-data-is-a-directory-bind-never-a-named-volume.md),
|
|
|
|
|
[ADR 0030](0030-data-outlives-the-mesh-that-declared-it.md): what a directory's contract carries, and what it must not
|