Phase 6d: systemd user unit for persistent FUSE mount
Build with clawstor cache / Cargo build (clawstor-cached) (pull_request) Successful in 15s

Deploy artifact — not built into the binary tree. `deploy/systemd/
clawstor-fuse.service` + README with the install recipe.

Unit shape:
* Type=simple, blocks on the FUSE binary (unmount = SIGTERM).
* ExecStartPre = mkdir -p mount, best-effort lazy unmount of any
  stale prior mount (guards against a hard SIGKILL leaving the
  kernel with a dangling mount).
* Restart=on-failure, RestartSec=5 — recover from transient IO
  errors without operator involvement.
* Environment= for CLAWSTOR_FUSE_BIN / DATA / MOUNT so a
  `systemctl edit` drop-in retargets without editing the unit file.

Dependency chain: clawstor-fuse.service After= + Wants=
clawstor-cluster.service. FUSE reads only the on-disk state so
this is technically not needed for correctness — but keeps the
mount from spinning up on a node where the daemon is broken.
This commit is contained in:
Omar Sobh
2026-07-14 12:29:32 -07:00
parent 2c51f0917e
commit b1fc463655
2 changed files with 72 additions and 0 deletions
+43
View File
@@ -0,0 +1,43 @@
# deploy/systemd
Systemd **user** units for clawstor.
## Units
| Unit | Purpose |
|---|---|
| `clawstor-cluster.service` | daemon (gossip + RPC + Prometheus + build cache). Not shipped here — deployed per-node from the fleet playbook. |
| `clawstor-fuse.service` | Phase 6 read-only FUSE mount at `~/clawstor-mount/`. Depends on `clawstor-cluster.service`. |
## Install `clawstor-fuse.service`
Prereqs: `libfuse3` installed, `claw-fuse` binary built with
`cargo build --release --features fuse --bin claw-fuse`.
```bash
# 1. Copy the binary
cp target/release/claw-fuse ~/clawstor-deploy/claw-fuse
# 2. Install the unit
mkdir -p ~/.config/systemd/user
cp deploy/systemd/clawstor-fuse.service ~/.config/systemd/user/
# 3. Reload + enable
systemctl --user daemon-reload
systemctl --user enable --now clawstor-fuse.service
# 4. Verify
systemctl --user status clawstor-fuse.service
ls ~/clawstor-mount/ # blobs snapshots tags
```
Override the default paths with a drop-in:
```bash
systemctl --user edit clawstor-fuse.service
```
```ini
[Service]
Environment=CLAWSTOR_MOUNT=/mnt/clawstor
```
+29
View File
@@ -0,0 +1,29 @@
[Unit]
Description=Clawstor read-only FUSE mount (blobs / snapshots / tags)
Documentation=https://git.redclaw.dev/clawverse/clawstor
After=clawstor-cluster.service network-online.target
Wants=clawstor-cluster.service
[Service]
Type=simple
# Override via `systemctl --user edit clawstor-fuse.service` when the
# install lives elsewhere.
Environment=CLAWSTOR_FUSE_BIN=%h/clawstor-deploy/claw-fuse
Environment=CLAWSTOR_DATA=%h/clawstor-deploy/data
Environment=CLAWSTOR_MOUNT=%h/clawstor-mount
# Create the mount point if missing (idempotent). ExecStartPre runs
# BEFORE the actual mount; fusermount3 needs an existing dir.
ExecStartPre=/bin/mkdir -p ${CLAWSTOR_MOUNT}
# Best-effort pre-unmount in case a prior instance left a stale
# mount (e.g. daemon SIGKILL). fusermount3's `-u -z` = lazy detach,
# harmless when nothing is mounted.
ExecStartPre=-/usr/bin/fusermount3 -u -z ${CLAWSTOR_MOUNT}
ExecStart=${CLAWSTOR_FUSE_BIN} --data-dir ${CLAWSTOR_DATA} --mount ${CLAWSTOR_MOUNT}
# The FUSE binary blocks until unmounted. On systemd stop, send
# SIGTERM which fuser translates to a clean unmount.
ExecStop=/usr/bin/fusermount3 -u ${CLAWSTOR_MOUNT}
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target