Repository navigation
Development
Markus Langer edited this page Mar 12, 2026
·
1 revision
go build ./... # must pass before committing
go vet ./... # must passNo external Go dependencies — standard library only.
.
├── main.go # HTTP server, flag parsing, startup checks
├── go.mod
├── internal/
│ ├── zfs/zfs.go # Direct zpool/zfs command execution (reads)
│ ├── zfs/acl.go # GetDatasetACL — getfacl/nfs4_getfacl parsing
│ ├── ansible/runner.go # Ansible playbook execution + ndjson parsing
│ ├── api/handlers.go # REST API handlers + input validation
│ ├── broker/broker.go # Thread-safe pub/sub broker
│ ├── broker/poller.go # Background ZFS + user/group poller
│ ├── system/system.go # Host info, ListUsers, ListGroups
│ └── smart/smart.go # S.M.A.R.T. data via smartctl
├── playbooks/
│ ├── inventory/localhost # Local connection inventory
│ ├── zfs_dataset_create.yml
│ ├── zfs_dataset_set.yml
│ ├── zfs_dataset_destroy.yml
│ ├── zfs_snapshot_create.yml
│ ├── zfs_snapshot_destroy.yml
│ ├── user_create.yml / user_modify.yml / user_delete.yml
│ ├── group_create.yml / group_modify.yml / group_delete.yml
│ ├── acl_set_posix.yml / acl_remove_posix.yml
│ ├── acl_set_nfs4.yml / acl_remove_nfs4.yml
│ ├── smb_setup.yml
│ ├── smb_usershare_set.yml / smb_usershare_unset.yml
│ └── smb_user_add.yml / smb_user_remove.yml
├── static/
│ ├── index.html # SPA shell + dialogs
│ ├── app.js # Vanilla JS frontend
│ └── style.css # Dark monospace theme
├── contrib/
│ ├── dumpstore.service # systemd unit (Linux)
│ └── dumpstore.rc # rc.d script (FreeBSD)
├── install.sh
└── Makefile
- Add a function to
internal/zfs/zfs.go(orinternal/system/system.go) - Add a handler in
internal/api/handlers.go - Register the route in
handlers.go:RegisterRoutes - Add the UI in
static/app.js(render function + fetch call) andstatic/index.html
- Add a playbook in
playbooks/(assert first, then mutate) - Add a handler in
internal/api/handlers.gousingh.runner.Run(...) - Register the route in
RegisterRoutes - Add the UI in
static/app.jsandstatic/index.html - Call
showOpLog(title, tasks, errorMsg)on the result — never skip the op-log for Ansible-backed actions
-
Reads →
internal/zfspackage (direct exec). No Ansible for reads. -
Writes → Ansible playbooks via
internal/ansible/runner.go. - Do not change this split without a good reason — it exists to avoid Python startup overhead on every API call.
- Target
localhostwithgather_facts: false - Always include an
asserttask before any mutating command - Document required extra vars in a header comment
- Task names must be stable —
RunAndGetStdoutlooks them up by name - Task names must be capitalised (ansible-lint requirement)
- Vanilla JS, no framework, no build step
- All data lives in the
stateobject - Render functions are pure: read from
state, writeinnerHTML - Always escape user-controlled strings through
esc()before inserting into HTML - Use
api(method, path, body)for all fetch calls — throws on non-2xx witherr.taskspopulated - Use
showOpLog(title, tasks, errorMsg)after every write operation (success or failure) - Use
toast(msg, type)only for non-Ansible notifications
- All handler inputs are validated with whitelist regexes before reaching the playbook
- Shell-special characters (`@;|&$``) are rejected on all string inputs
- System accounts (UID/GID <
UID_MIN) are blocked from deletion at both API and playbook level