Files
mesh-catalog/modules/mounts/README.md
T

10 KiB

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, with wants: each share this machine asks of which server and whether read-write or read-only ([{"server", "share", "access"}]). The server exports a share only to the machines that want it and that it grants, and decides the access itself: apply mounts a share at the access the server's answer gives this machine (to[]), read-only when either the share or this machine's grant is, and not at all when the server does not export it here (said as failed, naming the grant that is missing). Every five minutes the bundle also asks the controller's data verb where the mesh keeps data on this machine, and leaves the paths for apply; a failed ask keeps the last paths. No module reads another's files (ADR 0260).

What it refuses

Each refusal is said as the share's state failed, with why, and nothing is written for it:

  • a mount point at, under or above a path where the mesh keeps data on this machine (the controller's data verb: Plex's library and configuration, a backup repository, an agent's home). Until that list has been read once, nothing new is set up; a pair the module already has stays;
  • a mount point the system owns (/, /etc, /usr, /boot, /proc, /sys, /dev, /run and what is under them, and /var, /home, /root, /tmp themselves);
  • a mount point that something else is mounted at, or an automount that is not the module's;
  • a folder that holds files: a mount would hide them. Only a folder not in the kernel's mount table is opened, so a server that is away cannot hold the look;
  • a share that this machine serves itself.

And what it never does:

  • remove a pair while an entry of shares or sources cannot be read: nobody can tell which mount point the mistyped entry meant, so every pair stays until the settings read again;
  • stop or remove a pair whose mount point has a filesystem mounted that is not the pair's own source; the verb unmount refuses the same.

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 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