Initial import: nasmon health monitor, split out of home_nas
Go service (nasmon/) plus nfpm packaging (packaging/), carried over from the home_nas monorepo. Adds rpm packaging alongside the existing deb build (Fedora/RHEL/Rocky dependency names via nfpm overrides, per-format systemd unit path, dpkg+rpm-compatible maintainer scripts) and a Gitea Actions workflow that builds both formats on every push. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
# nasmon
|
||||
|
||||
Lightweight NAS health monitor: web dashboard on port 8090 with CPU, memory
|
||||
(incl. ZFS ARC), temperatures, physical disks with SMART, ZFS pools and datasets;
|
||||
periodic SMART/ZFS checks with e-mail alerts.
|
||||
|
||||
* Web UI: http://<host>:8090
|
||||
* Settings: http://<host>:8090/settings (also /etc/nasmon/config.json)
|
||||
* State: /var/lib/nasmon/nasmon.db (SMART history, alert log)
|
||||
* Service: systemctl status nasmon ; journalctl -u nasmon -f
|
||||
* JSON API: /api/status, /api/history?hours=24, /api/disks/<serial>/history?days=30
|
||||
|
||||
## ZFS datasets from the UI
|
||||
|
||||
The ZFS page (http://<host>:8090/zfs) can create datasets in a pool — name (nested
|
||||
names like media/video are fine), owner uid:gid for the mountpoint, compression,
|
||||
optional quota — and destroy datasets that are empty (no data, no children, no
|
||||
snapshots; the check is repeated against the live system before "zfs destroy").
|
||||
|
||||
nasmon runs sandboxed (ProtectSystem=strict → own mount namespace), so these
|
||||
commands are executed on the host through transient units:
|
||||
`systemd-run --wait --pipe --collect zfs create …`. Every action is logged
|
||||
(journalctl -u nasmon).
|
||||
|
||||
nasmon has no authentication: keep port 8090 on the LAN only.
|
||||
|
||||
## SMB / NFS shares from the UI
|
||||
|
||||
http://<host>:8090/shares manages Samba shares (guest or per-user, files always
|
||||
written as the data owner uid 1000), SMB users (smbpasswd; a login-less Unix
|
||||
account is created when needed) and NFS exports (host/IP/CIDR clients, rw/ro,
|
||||
squash). Definitions are stored in /etc/nasmon/shares.json; nasmon regenerates
|
||||
/etc/samba/smb.conf (whole file, header "Managed by nasmon") and
|
||||
/etc/exports.d/nasmon.exports, validates with testparm, then reloads smbd /
|
||||
exportfs -ra. A rejected config is rolled back to the .bak copy. Daemons are
|
||||
enabled while at least one share exists and disabled otherwise.
|
||||
|
||||
Alerts: the × on an open alert acknowledges it (hidden and not mailed until the
|
||||
problem changes or clears); the × on a resolved alert removes it from the log.
|
||||
Resolved alerts older than 7 days are hidden by default, older than 90 days
|
||||
deleted.
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"smtp": {
|
||||
"host": "",
|
||||
"port": 587,
|
||||
"security": "starttls",
|
||||
"user": "",
|
||||
"pass": "",
|
||||
"from": "",
|
||||
"to": [],
|
||||
"subject_prefix": "[nasmon]"
|
||||
},
|
||||
"alerts_enabled": true,
|
||||
"notify_resolved": true,
|
||||
"remind_hours": 24,
|
||||
"smart_interval_min": 30,
|
||||
"smart_skip_standby": true,
|
||||
"thresholds": {
|
||||
"disk_temp_c": 50,
|
||||
"cpu_temp_c": 80,
|
||||
"pool_capacity_pct": 85,
|
||||
"scrub_max_age_days": 45,
|
||||
"rootfs_free_pct": 10,
|
||||
"nvme_used_pct": 90,
|
||||
"nvme_spare_pct": 10
|
||||
},
|
||||
"self_tests": {
|
||||
"enabled": false,
|
||||
"short_days": 7,
|
||||
"long_days": 30,
|
||||
"hour": 3
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
[Unit]
|
||||
Description=nasmon - NAS health monitor (SMART/ZFS dashboard and alerts)
|
||||
Documentation=file:///usr/share/doc/nasmon/README.md
|
||||
After=network-online.target zfs.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
# smartctl and zpool need root
|
||||
User=root
|
||||
ExecStart=/usr/bin/nasmon -listen :8090 -config /etc/nasmon/config.json -data /var/lib/nasmon
|
||||
Restart=on-failure
|
||||
RestartSec=5s
|
||||
|
||||
# hardening
|
||||
NoNewPrivileges=yes
|
||||
PrivateTmp=yes
|
||||
ProtectSystem=strict
|
||||
ProtectHome=yes
|
||||
ReadWritePaths=/var/lib/nasmon /etc/nasmon
|
||||
ProtectKernelTunables=yes
|
||||
ProtectControlGroups=yes
|
||||
RestrictSUIDSGID=yes
|
||||
LockPersonality=yes
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,78 @@
|
||||
# nfpm packaging config — build with build.ps1/build.sh
|
||||
# (or directly: nfpm package -f packaging/nfpm.yaml -p deb|rpm)
|
||||
name: nasmon
|
||||
arch: amd64
|
||||
platform: linux
|
||||
version: ${NASMON_VERSION}
|
||||
section: admin
|
||||
priority: optional
|
||||
maintainer: home_nas <nas@localhost>
|
||||
description: |
|
||||
Lightweight NAS health monitor.
|
||||
Web dashboard (CPU, memory, temperatures, disks with SMART, ZFS pools)
|
||||
and periodic SMART/ZFS checks with e-mail alerts.
|
||||
homepage: https://gitea.virtlab.space/a.gritsenko/nasmon
|
||||
license: MIT
|
||||
|
||||
# Debian/Ubuntu package names by default; overrides.rpm below swaps in the
|
||||
# Fedora/RHEL/Rocky names. ZFS has no native package on RHEL-family distros
|
||||
# (needs the OpenZFS third-party repo), so it's intentionally left out of the
|
||||
# rpm depends — see packaging/README.md.
|
||||
depends:
|
||||
- smartmontools
|
||||
- zfsutils-linux
|
||||
- util-linux
|
||||
# file sharing is optional: the /shares page works once these are present
|
||||
recommends:
|
||||
- samba
|
||||
- nfs-kernel-server
|
||||
- wsdd
|
||||
|
||||
overrides:
|
||||
rpm:
|
||||
depends:
|
||||
- smartmontools
|
||||
- util-linux
|
||||
recommends:
|
||||
- samba
|
||||
- nfs-utils
|
||||
- wsdd
|
||||
|
||||
contents:
|
||||
- src: ../dist/nasmon
|
||||
dst: /usr/bin/nasmon
|
||||
file_info:
|
||||
mode: 0755
|
||||
- src: ./nasmon.service
|
||||
dst: /lib/systemd/system/nasmon.service
|
||||
packager: deb
|
||||
file_info:
|
||||
mode: 0644
|
||||
- src: ./nasmon.service
|
||||
dst: /usr/lib/systemd/system/nasmon.service
|
||||
packager: rpm
|
||||
file_info:
|
||||
mode: 0644
|
||||
- src: ./wsdd.service
|
||||
dst: /etc/systemd/system/wsdd.service
|
||||
type: config
|
||||
file_info:
|
||||
mode: 0644
|
||||
- src: ./config.json
|
||||
dst: /etc/nasmon/config.json
|
||||
type: config|noreplace
|
||||
file_info:
|
||||
mode: 0600
|
||||
- dst: /var/lib/nasmon
|
||||
type: dir
|
||||
file_info:
|
||||
mode: 0750
|
||||
- src: ./README.md
|
||||
dst: /usr/share/doc/nasmon/README.md
|
||||
file_info:
|
||||
mode: 0644
|
||||
|
||||
scripts:
|
||||
postinstall: ./postinst.sh
|
||||
preremove: ./prerm.sh
|
||||
postremove: ./postrm.sh
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
# config holds the SMTP password: root only
|
||||
chmod 0600 /etc/nasmon/config.json 2>/dev/null || true
|
||||
chmod 0750 /var/lib/nasmon
|
||||
if [ -d /run/systemd/system ]; then
|
||||
systemctl daemon-reload
|
||||
systemctl enable nasmon.service >/dev/null 2>&1 || true
|
||||
# restart on upgrade, start on fresh install
|
||||
systemctl restart nasmon.service || true
|
||||
# Windows network discovery, only when the wsdd package is present
|
||||
if [ -x /usr/bin/wsdd ]; then
|
||||
systemctl enable --now wsdd.service >/dev/null 2>&1 || true
|
||||
fi
|
||||
fi
|
||||
exit 0
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
if [ -d /run/systemd/system ]; then
|
||||
systemctl daemon-reload || true
|
||||
fi
|
||||
if [ "$1" = "purge" ]; then
|
||||
rm -rf /var/lib/nasmon /etc/nasmon
|
||||
fi
|
||||
exit 0
|
||||
@@ -0,0 +1,9 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
# dpkg passes "remove" here; rpm passes a numeric $1 (0 = last uninstall) - cover both.
|
||||
if { [ "$1" = "remove" ] || [ "$1" = "0" ]; } && [ -d /run/systemd/system ]; then
|
||||
systemctl stop nasmon.service >/dev/null 2>&1 || true
|
||||
systemctl disable nasmon.service >/dev/null 2>&1 || true
|
||||
systemctl disable --now wsdd.service >/dev/null 2>&1 || true
|
||||
fi
|
||||
exit 0
|
||||
@@ -0,0 +1,16 @@
|
||||
# Installed by nasmon: the Ubuntu wsdd package ships no unit file.
|
||||
# wsdd answers WS-Discovery so the NAS shows up under "Network" in Windows Explorer.
|
||||
[Unit]
|
||||
Description=Web Services Dynamic Discovery host daemon
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
ConditionPathExists=/usr/bin/wsdd
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/bin/wsdd --shortlog
|
||||
DynamicUser=yes
|
||||
Restart=on-failure
|
||||
RestartSec=10s
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user