Repository navigation
API Reference
All endpoints are served at http://<host>:8080. The API is JSON-over-HTTP; all request and response bodies are application/json.
| Method | Path | Description |
|---|---|---|
| GET | /api/sysinfo |
Host and process info |
| GET | /api/network |
Network interfaces (name, state, MAC, MTU, IPs, speed, RX/TX) |
| GET | /api/version |
OpenZFS version string |
| GET | /api/pools |
List all pools with usage stats |
| GET | /api/poolstatus |
Detailed pool status with vdev tree |
| GET | /api/datasets |
List all datasets and volumes |
| GET | /api/dataset-props/{name} |
Editable properties for a dataset |
| GET | /api/snapshots |
List all snapshots |
| GET | /api/iostat |
Pool I/O statistics (1-second sample) |
| GET | /api/smart |
S.M.A.R.T. health per disk |
| GET | /api/events |
Server-Sent Events stream |
| GET | /metrics |
Prometheus text exposition |
| POST | /api/datasets |
Create a dataset or volume |
| PATCH | /api/datasets/{name} |
Update dataset properties |
| DELETE | /api/datasets/{name} |
Destroy a dataset or volume |
| POST | /api/rewrite/{name} |
Rewrite existing blocks (zfs rewrite, background job) |
| POST | /api/snapshots |
Create a snapshot |
| POST | /api/snapshots/clone |
Clone a snapshot to a new dataset |
| POST | /api/snapshots/send |
Send a snapshot to a target dataset (local or remote SSH) |
| DELETE | /api/snapshots/{name} |
Destroy a snapshot |
| GET | /api/users |
List local users |
| POST | /api/users |
Create a local user |
| PUT | /api/users/{name} |
Edit user (shell, groups, password) |
| DELETE | /api/users/{name} |
Delete user and home directory |
| GET | /api/groups |
List local groups |
| POST | /api/groups |
Create a local group |
| PUT | /api/groups/{name} |
Edit group (name, GID, members) |
| DELETE | /api/groups/{name} |
Delete a local group |
| GET | /api/chown/{dataset} |
Get mountpoint owner and group |
| POST | /api/chown/{dataset} |
Set mountpoint owner and/or group |
| GET | /api/acl-status |
ACL presence map (dataset → bool) |
| GET | /api/acl/{dataset} |
Get ACL entries for a dataset |
| POST | /api/acl/{dataset} |
Add or modify an ACL entry |
| DELETE | /api/acl/{dataset} |
Remove an ACL entry |
| GET | /api/smb-shares |
List active Samba usershares |
| POST | /api/smb-share/{dataset} |
Create or update a Samba usershare |
| DELETE | /api/smb-share/{dataset} |
Remove a Samba usershare |
| GET | /api/smb-users |
List users registered in smbpasswd |
| POST | /api/smb-users/{name} |
Add a user to smbpasswd |
| DELETE | /api/smb-users/{name} |
Remove a user from smbpasswd |
| POST | /api/smb-config/pam |
Run Samba setup playbook |
| GET | /api/smb/homes |
Get current SMB [homes] config |
| POST | /api/smb/homes |
Enable/update SMB [homes] section |
| DELETE | /api/smb/homes |
Disable/remove SMB [homes] section |
| GET | /api/smb/timemachine |
List all Time Machine shares |
| POST | /api/smb/timemachine |
Create/update a Time Machine share |
| DELETE | /api/smb/timemachine/{name} |
Remove a Time Machine share |
| GET | /api/devices |
List physical block devices (vdev candidates, in-use flag) |
| POST | /api/pools/{pool}/replace |
Replace a pool device (starts resilver) |
| POST | /api/pools/{pool}/offline |
Take a pool device offline |
| POST | /api/pools/{pool}/online |
Bring a pool device online |
| POST | /api/scrub/{pool} |
Start a pool scrub |
| DELETE | /api/scrub/{pool} |
Cancel a running pool scrub |
| GET | /api/scrub-schedules |
List periodic scrub schedule config |
| PUT | /api/scrub-schedule/{pool} |
Add pool to periodic scrub schedule |
| DELETE | /api/scrub-schedule/{pool} |
Remove pool from periodic scrub schedule |
| GET | /api/auto-snapshot/{dataset} |
Get auto-snapshot property values for a dataset |
| PUT | /api/auto-snapshot/{dataset} |
Set auto-snapshot properties for a dataset |
| GET | /api/auto-snapshot/status |
Auto-snapshot ownership (OS daemon vs dumpstore) |
| POST | /api/auto-snapshot/takeover |
Disable the OS daemon and run snapshots from dumpstore |
| POST | /api/auto-snapshot/release |
Re-enable the OS daemon and stop dumpstore's scheduler |
| GET | /api/iscsi-targets |
List all iSCSI targets |
| POST | /api/iscsi-targets |
Create an iSCSI target for a zvol |
| DELETE | /api/iscsi-targets |
Remove an iSCSI target |
| GET | /api/services |
List status of all managed services |
| POST | /api/services/{name}/{action} |
Control a service (start/stop/restart/enable/disable) |
| GET | /api/replication |
List scheduled replication tasks |
| POST | /api/replication |
Create a replication task |
| PATCH | /api/replication/{id} |
Update a replication task |
| DELETE | /api/replication/{id} |
Delete a replication task |
| POST | /api/replication/{id}/run |
Fire a replication task immediately (returns 202 + job_id) |
| GET | /api/replication/{id}/history |
Recent run records for a task |
Create a filesystem or volume.
{
"name": "tank/data",
"type": "filesystem",
"compression": "lz4",
"quota": "50G",
"mountpoint": "/mnt/data",
"recordsize": "128K",
"atime": "off",
"exec": "on",
"sync": "standard",
"dedup": "off",
"copies": "1",
"xattr": "sa"
}For volumes, use "type": "volume" and add "volsize": "10G". Optional: "volblocksize", "sparse": true.
Update dataset properties. Any subset of editable properties may be sent. An empty string value resets the property to inherited; a non-empty value sets it explicitly. Unknown properties are ignored.
{
"compression": "zstd",
"quota": "",
"readonly": "on"
}Editable properties: compression, quota, mountpoint, recordsize, atime, exec, sync, dedup, copies, xattr, readonly, acltype, sharenfs, sharesmb.
Rewrite the existing blocks of a mounted filesystem via zfs rewrite so that updated properties (compression, checksum, dedup, copies) apply to already-stored data. Runs as a background job — returns 202 Accepted with a job_id; progress and output appear in the Jobs tab (GET /api/jobs).
{
"recursive": true,
"skip_snapshot_shared": true,
"skip_clone_shared": false
}-
recursive→-r(recurse into directories; crosses into child dataset mountpoints) -
skip_snapshot_shared→-S(don't duplicate blocks shared with snapshots) -
skip_clone_shared→-C(don't duplicate blocks shared via block cloning)
Caveats: recordsize changes are not applied by rewrite; rewriting blocks shared with snapshots/clones duplicates them (pool usage can increase) unless skipped; rewritten blocks appear as modified in incremental send streams. Volumes are rejected with 400 — rewrite operates through the mounted filesystem. Requires OpenZFS with zfs rewrite support (2.3+).
Destroy a dataset or volume. Append ?recursive=true to also destroy all child datasets and snapshots.
Pool roots (e.g. tank) cannot be deleted via this endpoint — use zpool destroy.
{
"dataset": "tank/data",
"snapname": "2024-01-15_backup",
"recursive": false
}Dispatch zfs send | zfs recv as a background job. Returns 202 Accepted immediately with the job metadata; live status is published on the jobs.update SSE topic and visible in the Jobs tab. Local target:
{
"snapshot": "tank/data@2026-05-06",
"target": "backup/data",
"incremental_from": "tank/data@2026-05-05",
"raw": false
}Add "remote": "user@host" to receive over SSH (ssh -o BatchMode=yes); the dumpstore service account must have SSH keys pre-configured for host. incremental_from and raw are optional. Response shape:
{
"job_id": "8f3c…",
"type": "snapshot.send",
"started_at": "2026-05-06T15:21:33Z",
"snapshot": "tank/data@2026-05-06",
"target": "user@host:backup/data"
}Use GET /api/jobs/{id} to poll status, or subscribe to the jobs.update SSE topic.
Long-running data-plane operations (currently snapshot send/receive) run as direct child processes outside Ansible, since they may run for hours. Each job has a status (running, success, failed, cancelled, interrupted), the captured argv, bounded stdout/stderr tails (last 64 KiB each), and timestamps. Records are persisted to disk so status survives a restart; any job left in running at shutdown is rewritten to interrupted on next boot.
Returns the list of known jobs, newest first.
Returns a single job's full record (including stdout/stderr tail).
Sends SIGTERM to the job's process group, escalating to SIGKILL after a 10 s grace. Returns 204 No Content on success, 400 if the job is already terminal.
Removes a terminal job from the manager and deletes its on-disk record. Returns 204 No Content on success, 400 if the job is still running (cancel it first).
Cron-scheduled replication tasks. Each fire creates a dumpstore-repl-<UTC> snapshot on the source, holds it for the duration of the transfer, picks the most recent common dumpstore-repl-* snapshot for an incremental send, dispatches the pipeline through the jobs runner, releases the hold, and prunes destination replication snapshots beyond the retention count.
Returns all replication tasks (without last_runs). Use /history to retrieve run records.
Create a task. enabled and retention_count default to true and 7 respectively.
{
"name": "nightly-backup",
"source": "tank/data",
"target": "backup/data",
"remote": "user@host",
"schedule": "0 3 * * *",
"retention_count": 7,
"raw": false,
"recursive": false,
"enabled": true
}schedule is a standard 5-field cron expression (minute, hour, day-of-month, month, day-of-week) with 1-minute resolution and no catch-up on missed firings. remote is optional; when empty the task replicates between local pools.
Partial update; any subset of the above fields is accepted. Re-registers the task with the scheduler.
Unregister and remove the task. Replicated snapshots on the destination, and dumpstore-repl-* snapshots on the source, are not deleted.
Fire the task immediately, off-schedule. Returns 202 Accepted with the job_id of the dispatched send/recv pipeline. The body of the running task continues asynchronously; subscribe to jobs.update for completion.
Returns the recent RunRecord list (capped at 20):
[
{
"job_id": "8f3c…",
"snapshot": "tank/data@dumpstore-repl-20260524T030000Z",
"started_at": "2026-05-24T03:00:00Z",
"finished_at": "2026-05-24T03:11:42Z",
"status": "success"
}
]Append ?recursive=true to also destroy clones.
Returns the physical block devices on the host (Linux: /sys/block, skipping loop/ram/zvol/dm pseudo-devices; FreeBSD: geom disk list). in_use_by carries the pool name when the device currently backs a vdev (best-effort matching: by-id/by-path symlinks resolved, partition suffixes stripped).
[
{ "name": "sdb", "path": "/dev/sdb", "size_bytes": 4000787030016, "model": "WDC WD40EFRX", "in_use_by": "tank" },
{ "name": "sdc", "path": "/dev/sdc", "size_bytes": 4000787030016, "model": "WDC WD40EFRX", "in_use_by": "" }
]Replace a vdev with a new device via zpool replace. A resilver onto the new device starts automatically; progress is visible in the pool's scan field (GET /api/poolstatus, poolstatus SSE topic).
{ "old_device": "sdb", "new_device": "/dev/sdc" }old_device accepts a device name, path, or the numeric guid zpool status prints for missing devices. Returns Ansible task steps.
Take a device offline for maintenance via zpool offline. Body: { "device": "sdb" }. Returns Ansible task steps.
Bring an offlined device back via zpool online. Body: { "device": "sdb" }. Returns Ansible task steps.
Start a scrub on the named pool. Returns Ansible task steps.
Cancel a running scrub on the named pool. Returns Ansible task steps.
Returns the current periodic scrub configuration for all pools.
{
"mode": "zfsutils",
"schedules": [
{ "pool": "tank" }
]
}mode is "zfsutils" on Linux (managed via ZFS_SCRUB_POOLS in /etc/default/zfs) or "periodic" on FreeBSD (managed via daily_scrub_zfs_pools in /etc/periodic.conf). On FreeBSD, threshold_days is also returned (default 35). An empty schedules array means all pools are scrubbed by the platform default.
Add a pool to the periodic scrub schedule. On FreeBSD, an optional threshold_days body field sets how many days must elapse before a scrub is triggered.
{ "threshold_days": 35 }Returns Ansible task steps.
Remove a pool from the periodic scrub schedule. Returns Ansible task steps.
Manages com.sun:auto-snapshot* ZFS user properties per dataset. These properties are consumed by zfs-auto-snapshot (Linux) or zfstools (FreeBSD) to automatically create and rotate snapshots. dumpstore sets/clears the properties; the external daemon handles snapshot creation.
zfs-auto-snapshot uses an opt-out model: any dataset where com.sun:auto-snapshot is not explicitly set is snapshotted by default. Setting the property to false is how you exclude a dataset.
The recommended pattern for snapshotting only specific datasets:
# 1. Opt the entire pool out
zfs set com.sun:auto-snapshot=false tank
# 2. Opt specific datasets back in
zfs set com.sun:auto-snapshot=true tank/data
zfs set com.sun:auto-snapshot=true tank/home# All datasets, all 6 properties
zfs get com.sun:auto-snapshot,com.sun:auto-snapshot:frequent,com.sun:auto-snapshot:hourly,com.sun:auto-snapshot:daily,com.sun:auto-snapshot:weekly,com.sun:auto-snapshot:monthly -t filesystem,volume
# Recursively from a pool root
zfs get -r com.sun:auto-snapshot tank
# Only locally-set values (excludes inherited/default)
zfs get -r -s local com.sun:auto-snapshot tankReturns the current com.sun:auto-snapshot* property values and their source (local/inherited/default) for the given dataset.
{
"com.sun:auto-snapshot": { "value": "true", "source": "local" },
"com.sun:auto-snapshot:frequent": { "value": "4", "source": "local" },
"com.sun:auto-snapshot:hourly": { "value": "24", "source": "local" },
"com.sun:auto-snapshot:daily": { "value": "7", "source": "local" },
"com.sun:auto-snapshot:weekly": { "value": "4", "source": "local" },
"com.sun:auto-snapshot:monthly": { "value": "-", "source": "default" }
}A value of "-" with source of "default" means the property is not set (inherits system default).
Set or clear com.sun:auto-snapshot* properties on a dataset. Returns Ansible task steps.
Request body — any combination of these keys; omitted keys are left unchanged:
| Key | Values |
|---|---|
com.sun:auto-snapshot |
"true", "false", or "" (inherit) |
com.sun:auto-snapshot:frequent |
integer 1–9999, or "" (inherit) |
com.sun:auto-snapshot:hourly |
integer 1–9999, or "" (inherit) |
com.sun:auto-snapshot:daily |
integer 1–9999, or "" (inherit) |
com.sun:auto-snapshot:weekly |
integer 1–9999, or "" (inherit) |
com.sun:auto-snapshot:monthly |
integer 1–9999, or "" (inherit) |
Empty string ("") triggers zfs inherit on the property (clears the local value).
{
"com.sun:auto-snapshot": "true",
"com.sun:auto-snapshot:daily": "7",
"com.sun:auto-snapshot:monthly": "3"
}Expose ZFS volumes as iSCSI targets. Uses targetcli/LIO on Linux or ctld on FreeBSD. Endpoints return 501 if no backend is detected.
List all iSCSI targets backed by ZFS volumes.
[
{
"iqn": "iqn.2024-03.io.dumpstore:tank-vms-win11",
"zvol_name": "tank/vms/win11",
"zvol_device": "/dev/zvol/tank/vms/win11",
"lun": 0,
"portals": ["0.0.0.0:3260"],
"auth_mode": "none",
"initiators": []
}
]Create an iSCSI target for a ZFS volume.
{
"zvol": "tank/vms/win11",
"iqn": "iqn.2024-03.io.dumpstore:tank-vms-win11",
"portal_ip": "0.0.0.0",
"portal_port": "3260",
"auth_mode": "none",
"chap_user": "",
"chap_password": "",
"initiators": []
}| Field | Required | Description |
|---|---|---|
zvol |
yes | ZFS volume name, must contain /
|
iqn |
yes | RFC 3720 iSCSI Qualified Name (iqn.YYYY-MM.domain:name) |
portal_ip |
no | Listen IP, defaults to 0.0.0.0
|
portal_port |
no | Listen port, defaults to 3260
|
auth_mode |
yes |
"none" or "chap"
|
chap_user |
when chap | CHAP username |
chap_password |
when chap | CHAP password |
initiators |
no | Array of allowed initiator IQNs; empty = allow all |
Returns Ansible task steps.
Remove an iSCSI target and its backstore. Both query parameters are required.
Returns Ansible task steps.
Manage the sharing daemons dumpstore controls (Samba, NFS, iSCSI). Status reads happen directly via systemctl/service — no Ansible overhead. Mutations (start/stop/restart/enable/disable) go through playbooks with op-log.
Logical service names: samba, nfs, iscsi.
Returns the status of all managed services.
[
{
"name": "samba",
"display_name": "Samba (SMB)",
"unit_name": "smbd",
"active": true,
"enabled": true,
"state": "active"
}
]state values: active, inactive, failed, unknown.
Control a service. Valid actions: start, stop, restart, enable, disable.
Returns Ansible task steps.
Returns the ACL type and entries for the dataset's mountpoint.
{
"dataset": "tank/data",
"mountpoint": "/mnt/data",
"acl_type": "posix",
"entries": [
{ "tag": "user", "qualifier": "", "perms": "rwx", "default": false },
{ "tag": "user", "qualifier": "alice", "perms": "r-x", "default": false },
{ "tag": "group", "qualifier": "", "perms": "r-x", "default": false },
{ "tag": "mask", "qualifier": "", "perms": "rwx", "default": false },
{ "tag": "other", "qualifier": "", "perms": "---", "default": false }
]
}acl_type is one of "posix", "nfsv4", or "off".
For NFSv4 datasets each entry has the form:
{ "tag": "A", "flags": "fd", "qualifier": "OWNER@", "perms": "rwaDxtTnNcCoy" }Add or modify an ACL entry. The ace string format depends on the dataset's acltype:
-
POSIX:
setfacl -mspec —"user:alice:rwx","group:storage:r-x","default:user:alice:rwx" -
NFSv4: full ACE string —
"A::alice@localdomain:rwaDxtTnNcCoy"
{ "ace": "user:alice:rwx", "recursive": false }recursive (POSIX only) applies setfacl -R to all files inside the mountpoint.
Remove an ACL entry. The entry query parameter:
-
POSIX:
user:alice,default:group:storage - NFSv4: full ACE string to match
Append &recursive=true (POSIX only) to remove recursively.
Manage the Samba [homes] section in smb.conf. When enabled, each authenticated user automatically gets a personal share mapped to a subdirectory under the configured base path.
Returns the current [homes] configuration. If the section is not present, enabled is false and all fields are empty.
{
"enabled": true,
"path": "/tank/homes/%S",
"browseable": true,
"read_only": false,
"create_mask": "0644",
"directory_mask": "0755"
}Enable or update the [homes] section. Returns Ansible task steps.
{
"path": "/tank/homes/%S",
"dataset": "tank/homes",
"browseable": true,
"read_only": false,
"create_mask": "0644",
"directory_mask": "0755"
}| Field | Required | Description |
|---|---|---|
path |
yes | Base path for home directories (may include %S for username substitution) |
dataset |
no | ZFS dataset to use as base path (alternative to specifying path directly) |
browseable |
no | Whether the share is visible in browse lists (default true) |
read_only |
no | Whether the share is read-only (default false) |
create_mask |
no | File creation mask (default "0644") |
directory_mask |
no | Directory creation mask (default "0755") |
Remove the [homes] section from smb.conf. Returns Ansible task steps.
Manage Samba shares configured as macOS Time Machine backup targets using vfs_fruit with catia and streams_xattr VFS modules.
List all Time Machine shares. Parses smb.conf for sections with fruit:time machine = yes.
[
{
"sharename": "timemachine",
"path": "/tank/backups/timemachine",
"max_size": "1T",
"valid_users": "alice bob"
}
]Create or update a Time Machine share. Returns Ansible task steps.
{
"sharename": "timemachine",
"dataset": "tank/backups",
"path": "/tank/backups/timemachine",
"max_size": "1T",
"valid_users": "alice bob"
}| Field | Required | Description |
|---|---|---|
sharename |
yes | Samba share name |
dataset |
no | ZFS dataset (alternative to specifying path directly) |
path |
yes | Filesystem path for the share |
max_size |
no | Maximum size quota for Time Machine backups |
valid_users |
no | Space-separated list of allowed users |
Remove a Time Machine share from smb.conf. Returns Ansible task steps.
Subscribe to live data updates. The server pushes named events whenever data changes.
Query parameter: topics — comma-separated list of topics to subscribe to.
Available topics:
| Topic | Data | Cadence |
|---|---|---|
pool.query |
Same JSON as GET /api/pools
|
Every 10 s on change |
poolstatus |
Same JSON as GET /api/poolstatus
|
Every 10 s on change |
dataset.query |
Same JSON as GET /api/datasets
|
Every 10 s on change |
snapshot.query |
Same JSON as GET /api/snapshots
|
Every 10 s on change |
iostat |
Same JSON as GET /api/iostat
|
Every 10 s |
user.query |
Same JSON as GET /api/users
|
Every 10 s on change + after writes |
group.query |
Same JSON as GET /api/groups
|
Every 10 s on change + after writes |
ansible.progress |
Single TaskStep object |
Streamed during playbook run |
event: pool.query
data: [{"name":"tank","health":"ONLINE",...}]
event: iostat
data: [{"pool":"tank","read_ops":0,"write_ops":443,...}]
Example — watch pool health and I/O live:
curl -N 'http://localhost:8080/api/events?topics=pool.query,iostat'Non-2xx responses return:
{
"error": "human-readable message",
"tasks": [ ... ]
}tasks is populated for Ansible-backed operations and contains the step results up to the point of failure.