Issue 118 and ADR 0112 (proposed): a module definition names no node, no mesh and no path #112

Closed
jschoubben wants to merge 3 commits from decision/0112-a-module-definition-names-no-path into main
2 changed files with 74 additions and 47 deletions
Showing only changes of commit d169f9d8cd - Show all commits
@@ -55,34 +55,36 @@ unresolved variable and what could answer it. Variables are answered from three
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.** A database, a bucket, a vhost, the
occupant of a seat, another assignment, and **a secret from the vault**: a module's own
password, internal token or external key is a `secret` provision like any other
([ADR 0085](0085-a-secret-is-a-provision.md)). Each comes with the contract the mesh and the
module's specification define. Which node answers one is part of the assignment
([ADR 0084](0084-which-provider-serves-a-consumer.md)), so a module may take its database from
another node.
3. **What the mesh generates or knows.** The credential it mints for each provision a module
takes, which is how every provision is delivered, the vault's included
([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.
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.** A module requires one by name, such as its configuration or its
data, and the host on the node where the assignment runs answers it. Its contract is what the
module needs from it:
**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).
- the owner and mode, including the owner the image expects
([ADR 0107](0107-persistent-data-is-a-directory-bind-never-a-named-volume.md));
- whether it holds data that outlives the module ([ADR 0030](0030-data-outlives-the-mesh-that-declared-it.md))
or is disposable.
*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.
*Where* it 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)). An operator's shared data
([ADR 0051](0051-shared-data-is-the-operators.md)) is the same provision with the operator as owner:
the module says it needs read or read-write access, and the assignment says where the data is. A
directory is always answered 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
@@ -92,44 +94,68 @@ process reads.
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 it instead: directories, container names,
the login a consumer presents, broker accounts, a seat's holder. So **one module may be assigned to
one node more than once.** What must stay singular stays so by a seat, or by the assignment's own
configuration colliding: a public name already taken is refused like any other singular thing.
**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
and needs the design to say how existing modules migrate without their data moving: an adopted
or already-running assignment is placed where its data already is.
- The control plane resolves variables at assignment and refuses unresolved ones. The host answers
directory provisions. The contributions file's format changes, and so does the SDK's reconcile
loop that reads it.
- Identity moves from the module to the assignment, which touches logins, broker accounts and
every resource name.
- **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.
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 fails on any absolute path outside the image side of a mount, with a declared list of exceptions that shrinks to empty as definitions move. |
| 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, no collision. |
| 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 node answers 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):
a module's own secrets come from the vault; the mesh mints only the delivery credential
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
[ADR 0030](0030-data-outlives-the-mesh-that-declared-it.md): what a directory's contract carries, and what it must not
@@ -42,9 +42,10 @@ line, a literal in module code.
- **The mesh's own wire carries host paths into containers.** Each contribution names its
consumer's credential as "the file on this machine holding that consumer's credential", a host
path computed from the provider's grants directory. So every provider has to mount that directory
at the *identical* path, or it cannot read what it was given. Eleven of the twelve providers do.
It is a convention nothing states or checks, and the twelfth is the provider above.
- **The warning that would have caught it is lost in the SDK.** The control plane always writes the
at the *identical* path, or it cannot read what it was given. Ten of the eleven providers with a
grants directory do. It is a convention nothing states or checks, and the eleventh is the
provider above.
- **The warning that would have caught it is lost in the SDK.** The controller always writes the
contributions file, even when empty, so a provider can tell "nothing asked" from "never written".
The SDK's reconcile loop treats an unreadable file as empty, and logs nothing.
- **Code carries copies with nothing checking them.** Several modules default a path in code when an