Files
mesh-catalog/modules/mounts/README.md
T
jochen 2b1b9b0235 Let mounts write each share's mount and automount, so no node depends on a hand-written fstab line (hq ADR 0263)
A machine mounts what its assignment names: a node's share from the
provision nfs-share, whose path it reads from nfs-server's state on the
bus, and occasional sources (an SMB device, a disk) whose absence is a
state, not a fault. apply writes and arms the unit pairs as root; watch
tries each source and judges the health; the operator's fstab lines are
taken over only through adopt, on their word, once the replacement is
armed. SMB logins are an outside party's secret, given with secret accept.
2026-10-08 18:36:01 +02:00

143 lines
8.6 KiB
Markdown

# mounts
The shares and the occasional sources a machine mounts, and what it mounts and shares, read as tools
(novox/hq ADR 0263, to-be design 52 "Shares and mounts", from research 038). It holds the node seat
`node-mounts`, one holder per machine.
A machine mounts only what its assignment names (ADR 0263 rule 5): nothing by default, and "every
machine" is the same setting given once at the mesh-wide layer. A share of another machine comes from the
provision `nfs-share`, which `nfs-server` provides on the machine that shares.
## What it owns
- The packages `nfs-utils` and `cifs-utils`.
- `/etc/mesh-mounts/mounts.conf`, placed by the mesh from the assignment: the settings `shares` and
`sources`, the binding of `nfs-share` (`from`, the sharing machine, and `at`, where it is reached on
the private network), the operator account, and where the module's secret is.
- One `.mount` and one `.automount` unit per share or source, in `/etc/systemd/system`, named as
`systemd-escape --path` names the mount point and opened by the marker
`# Written by the mesh (module mounts, novox/hq ADR 0263).` A unit file without that marker is not the
module's: it is never written over, stopped or removed, and the share whose mount point it holds is
said as not set up.
- The SMB logins, one file per source in the module's state directory, readable by root only.
- `/var/lib/mesh-mounts/from-bus` (the bundle's: what the sharing machine exports) and `/run/mesh-mounts`
(the processes': what was applied and what was found).
What it never does: chown or chmod a mount point (it makes one that is missing, and nothing else), touch a
mounted filesystem to look at it, or remove a pair because the sharing machine did not answer. A pair is
removed only when the settings stop naming its mount point. The files a share serves are the operator's
(ADR 0051): the module mounts them and owns nothing in them.
## The unit pair
Only the automount is enabled (under `remote-fs.target`; a disk's under `local-fs.target`). The mount
is never enabled: it is made at the first use of its mount point and released after ten idle minutes
(`TimeoutIdleSec=600`). So nothing mounts at boot and nothing can fail a boot, and a mount point is always
an autofs mount, so nothing writes into the empty directory under it.
| kind | What | Options | TimeoutSec |
|---|---|---|---|
| a node's share, read-write | `<at>:<path>`, `Type=nfs4` | `vers=4.2,hard,timeo=150,retrans=3,_netdev` | 30 |
| a node's share, read-only | `<at>:<path>`, `Type=nfs4` | `ro,vers=4.2,soft,timeo=150,retrans=3,_netdev` | 30 |
| an SMB source | `//<host>/<share>`, `Type=cifs` | `credentials=<file>,iocharset=utf8,_netdev,nofail,uid=…,gid=…` | 10 |
| a disk | `/dev/disk/by-uuid/<uuid>`; the mount `BindsTo=` the disk's device | `nofail` | 10 |
A share is read-only when the setting says `:ro` or the sharing machine exports it read-only. A
read-write share is mounted hard, so a write is never dropped while the server is away.
## Settings
Both are preferences whose default, `none`, mounts nothing (ADR 0262 allows no empty default).
- `shares`: space-separated `name=mountpoint`, each optionally `:ro`. The name is the share's on the
sharing machine; its path there comes from that machine over the bus, never from this setting.
For example `library=/srv/library downloads=/srv/downloads:ro`.
- `sources`: space-separated occasional sources, each optionally `:ro`:
`name=smb://<host>/<share>@<mountpoint>` or `name=disk:<filesystem uuid>@<mountpoint>`.
For example `games=smb://192.0.2.76/Share@/mnt/games`.
A mount point is an absolute, plainly written path, not a directory of the system's own (`/etc`, `/usr`,
`/run`, …). An entry that cannot be read is said, and only that entry is left out.
## The secret
`smb-credentials` is the module's own secret, issued by an outside party (the device's owner), so the mesh
never makes one in its place. The operator gives it with
`secret accept <node> mounts smb-credentials --from <file>`; the file holds one section per SMB source:
```
[games]
username=…
password=…
domain=… (optional)
```
A source whose section is missing is not mounted, and is said with that remedy. No tool answers a
password: the options, fstab lines and mountinfo the tools read are redacted.
## The processes and the bus
- `apply` (root, judged by its unit) writes and removes the unit pairs and the logins, makes a missing
mount point, reloads the service manager when anything changed and arms every automount, every 30 s.
- `watch` (root, judged by `mounts_health`) tries each source without touching its mount point — TCP 2049
for a node's share, 445 for an SMB source, the device for a disk — and says each one's state.
- The bundle (the operator account) reads what the sharing machine exports from `nfs-server`'s state
`exports`, keyed by that machine, and leaves it for `apply`; a failed read keeps the last answer. It puts
what `watch` found in the module's state `shares`, keyed by this machine. No module reads another's
files (ADR 0260).
The states: `armed` (the automount waits), `mounted`, `absent` (an occasional source that is not there —
a state, not a fault), `unreachable` (should be there and is not), `failed` (tried and refused, or not
set up; `why` says which).
## Health
Unhealthy when a share that should always be there has been unreachable or failed for five minutes ("The
share library of <machine> is not reachable from this machine since 19:21."), when an automount is not
armed, when something the settings name cannot be set up (a missing login, a unit file that is not the
module's), or when `watch` has not looked for two minutes. An occasional source that is absent is
healthy, and said as not present since when.
## Taking over a hand-written line
The operator's own fstab lines for a share are taken over only through `adopt`, on their word, and only
once the module's own pair for the same mount point is written and its automount armed: the replacement
works first, then the line goes. Without `confirm` it is a dry run. With it (and `why`), the line is
commented out as `# adopted by the mesh (module mounts) on <date>: <the line, any password redacted>`,
the file as it was is kept as `/etc/fstab.mesh-adopted-<date-time>` readable by root only, and the
service manager reloads. The module never takes a line over on its own.
## What it reads
- `/etc/fstab`, every line but swap. A credential in the options (`password=`, `pass=`, `passwd=`) is
answered as `(redacted)`; a `credentials=` file is named and never opened.
- The service manager's mount and automount units, with `systemctl list-units` and `systemctl show`:
state, result, timeout, and whether each was generated from fstab or comes from a unit file. The
kernel's own filesystems (proc, tmpfs, mqueue and the like) are left out.
- `/proc/self/mountinfo`, for what is mounted now. A mount point is never opened or statted, so a
network filesystem whose server is away cannot hang a call.
- `/etc/exports`, `/etc/exports.d/*.exports` and the kernel's live export table `/var/lib/nfs/etab`.
- The ZFS `sharenfs` and `sharesmb` properties, where `zfs` is installed.
- The share sections of `/etc/samba/smb.conf`: path, valid users, read only or writable, force user and
the like. The `[global]` section and every other setting are left out, so no password or password
backend is answered.
A file that cannot be read, and a command that does not answer, is said under `notes`, never answered
as empty.
## Tools
What only root may do (`mount`, `unmount`, `adopt`) goes through `sudo -n`, as the packet filter's and the
service manager's tools do; a refusal by sudo is said as one.
| tool | | answers |
|---|---|---|
| `mounts_list` | r | every mount point, its fstab line, its mount and automount units and whether it is mounted now; network filesystems marked; a network mount without automount or nofail said. Narrowed with `network` and `match` |
| `mounts_exports` | r | the NFS exports declared and live, the ZFS share properties, the Samba shares, and whether nfs-server and smb are active; an export declared and not live, or live and declared nowhere, said |
| `mounts_health` | r | the health check: healthy or not, with why, one sentence per finding |
| `node-mounts.list` | r | the machine's mount points, and every share and source the module is asked to mount with its state, since when and why |
| `node-mounts.test` | r | whether one share's or source's server answers now, tried without touching its mount point |
| `node-mounts.mount` | a | mount one share or source now |
| `node-mounts.unmount` | a | release one now; its automount stays armed |
| `node-mounts.adopt` | a | take over one hand-written fstab line, as above |