From f4b79ba7c2a853982883ca28deddc106bf04a438 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 8 Oct 2026 18:37:15 +0200 Subject: [PATCH] Design 52 says how the modules were built: the server's bucket carries each share's path, two root processes, settings default to none --- ...n-demand-and-only-nodes-that-ask-get-it.md | 11 ++--- 03-DESIGN/01-to-be/52-shares-and-mounts.md | 41 +++++++++++-------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md b/02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md index e4d9298f..3f351c5f 100644 --- a/02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md +++ b/02-DECISIONS/0263-a-share-is-a-provision-a-node-mounts-it-on-demand-and-only-nodes-that-ask-get-it.md @@ -62,7 +62,8 @@ Rejected: so the backups are never exported. 9. **A provider's paths written into its binding.** A binding carries what the provider's manifest `serves`, which is the same for every machine; a share's path is a setting of one assignment. The - consumer asks the server for it over the bus instead, so no controller change is needed for it. + consumer reads it from the server's bucket on the bus instead, so no controller change is needed for + it. ## Decision @@ -107,10 +108,10 @@ Rejected: is absent raises nothing. The server's health is its service and its export table holding every declared export. 9. **Over the bus.** The controller wires the two through the provision: the binding gives the consumer - the server's name. The consumer then asks the server's seat, `node-nfs-server.exports`, by request and - reply for each share's path and access, so a share's path is said once, on the server. `nfs-server` - keeps its exports, and `mounts` keeps each share's state, in their own key-value buckets (ADR 0201). - Neither reads the other's files (ADR 0260). + the server's name. `nfs-server` keeps its exports in its key-value bucket (ADR 0201), and `mounts` + reads it (`reads`) for each share's path and access, so a share's path is said once, on the server. + `mounts` keeps each share's state in its own bucket. The seat's `exports` verb answers the same by + request and reply. Neither reads the other's files (ADR 0260). 10. **Taking over a hand-written line is an act.** The `mounts` module's `adopt` comments out one fstab line, keeping a copy, only after its own unit pair for that mount point is armed, and only on a person's word. The ZFS `sharenfs` property is cleared the same way, by `nfs-server`, once its own diff --git a/03-DESIGN/01-to-be/52-shares-and-mounts.md b/03-DESIGN/01-to-be/52-shares-and-mounts.md index 6251e2a3..1fd51752 100644 --- a/03-DESIGN/01-to-be/52-shares-and-mounts.md +++ b/03-DESIGN/01-to-be/52-shares-and-mounts.md @@ -64,17 +64,21 @@ The glossary holds the three words. - **What it refuses.** A path that does not exist or is not a directory, `/`, and a path that holds a backup repository at its root or one level below. A refused share is said by the tools and makes the module unhealthy; the others are exported. -- **Its file.** `/etc/exports.d/mesh.exports`, written by the module's own process, which runs as root. - One line per share: the path, to `${machine:mesh-range}` and nothing else, with `rw` or `ro`, `sync`, - `secure`, `no_subtree_check`, `all_squash`, a stable `fsid`, and `anonuid` and `anongid` read from the - path's owner. `exportfs -ra` runs when the file changes. -- **The service.** `nfs-server.service`, running and enabled. NFS version 3 is turned off in the - module's drop-in for `nfs.conf`, so only 2049/tcp is needed, declared in `listens` with `from: mesh`. +- **Its file.** `/etc/exports.d/mesh.exports`, written by the module's own process, which runs as root + and looks every 30 s. One line per share: the path, to `${machine:mesh-range}` and nothing else, with + `rw` or `ro`, `sync`, `secure`, `no_subtree_check`, `all_squash`, and `anonuid` and `anongid` read from + the path's owner. `exportfs -ra` runs when the file changes or a share is missing from the kernel's + table. The filesystem's own id is kept; none is forced. +- **The service.** `nfs-server.service`, running and enabled. NFS versions 2, 3 and 4.0 are turned off + in the module's drop-in in `/etc/nfs.conf.d`, so only 2049/tcp is needed, declared in `listens` with + `from: mesh`. - **The provision.** `nfs-share`, at the mesh's scope, with no identity: the binding gives the - consumer the server's name, and the consumer asks for the rest. + consumer the server's name, and the consumer reads the rest from the server's bucket. Its consumers' + data class is `none`: the folders are the operator's, and the mesh backs up nothing through it. - **Health.** Its tool `nfs_health`: the service is active, every share is in the kernel's export table, and no share was refused. -- **Its bucket.** `exports`, one entry per machine: the shares as the kernel holds them. +- **Its bucket.** `exports`, one entry per machine, keyed by the node's name: the answer of `exports`, + put by the module's tools every 30 s. The root process does not reach the bus; its tools do. - **Its seat's verbs.** `exports` (r), `clients` (r), `test` (r), `reload` (a) and `adopt` (a). `adopt` clears a ZFS dataset's `sharenfs` property for a path the module now exports, only once the mesh's export of it is in the kernel's table, and only with a person's confirmation and reason. @@ -82,18 +86,22 @@ The glossary holds the three words. ## 2. The client: `mounts` - **Its setting `shares`.** A list of `name=mountpoint`, each optionally `:ro`: the `nfs-share` shares - this node mounts, by the server's name for them. + this node mounts, by the server's name for them. `none` (the default) mounts none. - **Its setting `sources`.** Occasional sources: `name=smb:///@` or - `name=disk:@`, each optionally `:ro`. + `name=disk:@`, each optionally `:ro`. `none` (the default) is none. - **Its secret `smb-credentials`.** One section per SMB source, `[name]` with `username=` and `password=`, issued outside the mesh and given with `secret accept mounts smb-credentials --from `. The process writes one credentials file per source, readable by root only. A source with no section is said with that remedy and is not mounted. -- **Asking the server.** The process asks `node-nfs-server.exports` on the server named by the binding, - over the bus, for each share's path and access. A share the server does not export is said, not - guessed. +- **Reading the server.** The module reads the server's bucket `exports` (its manifest's `reads`) for + each share's path and access: its tools, which reach the bus, write what they read to a file of the + module's, and the root process takes only a name, an absolute path and the access from it. A share + the server does not export is said, not guessed, and a silent server removes nothing. +- **Two processes, both root.** `apply` writes the unit pairs and the SMB credentials files and arms + the automounts; `watch` probes each source and keeps the states. The tools act as root through + `sudo -n` for `mount`, `unmount` and `adopt`, and say so when it is refused. - **The unit pair.** For each share and source, a `.mount` and an `.automount`, named by the escaped - mount point, written in `/etc/systemd/system` by the module's own process with a marker line. It never + mount point, written in `/etc/systemd/system` by `apply` with a marker line. It never touches a unit without its marker, and it removes its own pairs that are no longer asked for: - the `.automount` is enabled under `remote-fs.target`, with an idle time of 10 minutes; - the `.mount` is not enabled; its mount timeout is 30 s, 10 s for an occasional source; it starts @@ -106,8 +114,9 @@ The glossary holds the three words. `failed` (the mount was tried and refused, with the error). - **Its probes.** Every 30 s, a connection to the server's port (2049, or 445 for SMB) with a short timeout, and the device for a disk. It never touches a mount point, so a hung server cannot hang it. -- **Health.** Its tool `mounts_health`: every automount is armed, and no share that is not occasional - has been `unreachable` or `failed` for 5 minutes. An absent occasional source is healthy and said as +- **Health.** `apply` by its unit; `watch` by the tool `mounts_health`: every automount is armed, every + share the settings name could be set up, `watch` looked in the last 2 minutes, and no share that is not + occasional has been `unreachable` or `failed` for 5 minutes. An absent occasional source is healthy and said as *not present since 18:02*. - **Its seat's verbs.** `list` (r), `test` (r), `mount` (a), `unmount` (a), `adopt` (a); its tools `mounts_list` and `mounts_exports` (r) stay.