Skip to content

feat(zfs): read ZFS pools, datasets and snapshots (read only) - #27

Merged
inkly merged 2 commits into
mainfrom
feat/zfs-read-only
Nov 9, 2026
Merged

inkly merged 2 commits into
mainfrom
feat/zfs-read-only

Conversation

@inkly

@inkly inkly commented Nov 9, 2026 •

Copy link
Copy Markdown
Collaborator

Shows ZFS in the Storage manager, first step, read only (design: docs/superpowers/specs/2026-11-09-zfs-storage-design.md in ReCasaOS/CasaOS; request: ReCasaOS/CasaOS discussion 66). This is the LocalStorage half; the dashboard half is a separate PR in CasaOS-UI.

  • GET /v1/disks/zfs: whether ZFS is usable (available, with a reason: tools_missing, module_missing, failed), the pools (size, allocated, free, fragmentation, capacity, health; from zpool status: state, last scan, data errors, tree of vdevs with their read/write/cksum counters, the disk each one is on) and the datasets (used, available, referenced, space held by snapshots, mount point, mounted, quota, key status).
  • GET /v1/disks/zfs/snapshots?dataset=: the snapshots of one dataset, newest first, 200 at most (truncated). The dataset must be one the box lists, otherwise 404 and nothing is run.
  • GET /v1/disks/zfs/io: the I/O counters of each pool from /proc/spl/kstat/zfs/<pool>/io, no command; the dashboard takes the rate between two readings.
  • No Gateway change (/v1/disks is already routed).

How the commands are run, since ZFS can hang:

  • only zpool list, zpool status and zfs list, as argument lists, no shell, LC_ALL=C, scripted forms (-H -p) except zpool status, which has no -H and is read by its section names; a line it does not understand is skipped;
  • 10 s per command, 30 s per request, output capped at 4 MiB;
  • one command at a time, and the slot is given back when the command really ends, not when its caller gives up: a pool that stops answering leaves zpool status where it cannot be killed, and a dashboard asking every few seconds must not pile such processes up. Meanwhile the last answer is returned marked stale;
  • the list is kept 10 s and shared between clients;
  • a pool whose status cannot be read is returned known: false, never as healthy.

Nothing here changes a pool.

Checked on a real box, partly. A user (OpenZFS 2.4.1, Ubuntu 26.04) pasted the output of zpool list -H -p, zfs list -H -p and zpool status -p -P for a healthy mirror (service/testdata/zfs/real_*); the parsers read them and the column lists are accepted by 2.4. The indentation of the zpool status tree was lost in the paste and put back by hand. Still written from the OpenZFS docs, not captured: a degraded pool, scrubs/resilvers in progress, logs/cache/spares, a volume, a locked dataset, no pools available, and the kstat counters; and nothing was run against OpenZFS 2.1/2.2/2.3 or compared with zpool iostat. See the spec ("À la charge du constructeur").

Tests: go generate ./... && go test ./service/ ./route/... in golang:1.26, all green.

inkly added 2 commits November 9, 2026 11:21
GET /v1/disks/zfs, /v1/disks/zfs/snapshots and /v1/disks/zfs/io.
zpool list, zpool status and zfs list run in their scripted forms, without
a shell, with time-outs and one at a time; a box without ZFS answers
available: false. The test fixtures are written from the OpenZFS
documentation and a pasted healthy pool, not captured from a box.
zpool list, zfs list and zpool status of a healthy mirror, pasted by a user.
@inkly
inkly merged commit feb1efa into main Nov 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant