5.8 KiB
Heartbeat Daemon (hbd) ✅
A lightweight daemon that listens for UDP heartbeat messages and acts on them: keeps host state, optionally updates DNS records via nsupdate, forwards messages to WebSocket clients, and sends notifications (email, Pushover, Mattermost, Signal). It is a refactor of a previously monolithic script into a modular Python package (hbd).
📌 Features
- Receive and parse heartbeat datagrams (text or zlib-compressed) ✅
- Maintain host state and detect up/down transitions ✅
- Queue DNS updates via
nsupdateand run them in a background thread ✅ - WebSocket API for live updates (hosts & messages) ✅
- Notification pipeline (email, Pushover, Mattermost, Signal) ✅
- Modular codebase suitable for unit testing and CI ✅
⚙️ Quickstart
Prerequisites:
- Python 3.10+ (project uses language features from recent Python)
nsupdate(for DNS updates) if using dynamic DNS
Install dependencies (recommended into a venv):
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
# for development/testing tools
python -m pip install -r requirements-dev.txt
Run the daemon (example):
# run with default config lookup (~/.hb.yaml)
PYTHONPATH=. hbd -c .hb.yaml -f -v
You can also run it directly via the package entrypoint after installation:
python -m hbd.cli -c /path/to/config.yaml
🐞 Debugging in VS Code
This repository includes a ready-to-use .vscode/launch.json with configurations to run or attach the VS Code debugger to hbd.
- Ensure the Python extension is installed and select the project
.venvas the interpreter (bottom-left of VS Code). - Use F5 and pick one of these configurations from the Run view:
- Python: Run hbd (module) — runs
hbd.clias a module and setsPYTHONPATHto the workspace root (recommended). - Python: Run hbd with debugpy (listen) — launches
debugpyandhbdtogether; useful when you want the process to listen for a debugger. - Python: Attach (localhost:5678) — attach the debugger to a running process started with
debugpy.
- Python: Run hbd (module) — runs
To start hbd manually and wait for the debugger to attach, run:
PYTHONPATH=. python -m debugpy --listen 5678 --wait-for-client -m hbd.cli -c .hb.yaml -f -v
Set breakpoints in modules such as hbd/udp.py, hbd/dns.py, or hbd/server.py, and use the Attach configuration to connect. Use justMyCode: false if you need to step into third-party code.
🛠 Configuration
hbd reads YAML configuration (optional). If PyYAML is not installed, built-in defaults are used. Example configuration keys (see hbd/config.py):
hb_port: UDP port to listen for heartbeats (default: 50003)hbd_port: internal control port (default: 50004)hbd_host: bind address for HTTP/WSSpickfile: path for persisted statelogfile: path to log filelogfmt:textormsgpushsrv: push service (pushover|mattermost|all)interval/grace: heartbeat timing configurationdyndomains: list of dyndomains to update viansupdatensupdate_bin: path to nsupdate binary
Example .hb.yaml (minimal):
hbd_host: 0.0.0.0
hbd_port: 50004
dyndomains:
- example.com
nsupdate_bin: /usr/bin/nsupdate
pushsrv: pushover
Tip:
config.DEFAULTSinhbd/config.pycontains the canonical defaults and accepted configuration keys.
🔧 Architecture & Modules
hbd.proto— serialization/deserialization of heartbeat messages (supports compressed payloads)hbd.udp— UDP parsing andhandle_datagramimplementation (main state machine)hbd.dns—create_nsupdate_payload,nsupdate, and a background DNS thread (start_dns_thread)hbd.notify— email and push notification helpershbd.ws— WebSocket server and thread-safe broadcast helpershbd.http— HTTP handler factory for the status UI/APIhbd.utils— small utility helpers (shortname,dur,initlog)hbd.cli— CLI entrypoint and argument parsinghbd.server— async orchestration to run UDP/HTTP/WSS components
This modular layout makes the code easier to test and maintain.
🧪 Testing & Dev
Tests are implemented using unittest and additional tests rely on pytest if you prefer. To run tests locally without installing anything beyond the dev requirements:
# with project root on PYTHONPATH
PYTHONPATH=. python -m unittest discover -v
# or with pytest if installed
pytest -q
Developer tooling included:
pyproject.toml— project metadata and dependenciesrequirements-dev.txt— dev/test dependenciestox.ini— convenience wrappers for running tests, lint, and mypy
To run linters and type checks locally:
# after installing dev deps
tox -e lint
tox -e mypy
🚀 Running in production
- Use your system service manager (systemd, launchd, etc.) to run
hbdin the background. - Ensure
nsupdateand necessary credentials are available for dynamic DNS updates. - Configure TLS for WSS if you enable secure websockets.
Note: The project contains a small example for obtaining DNS-verified certs (certbot with RFC2136) — see earlier commit history or ask me to re-add the example to this README if you want it documented here.
🤝 Contributing
Contributions welcome! Please:
- Open an issue to discuss larger changes.
- Create a topic branch and a clear PR.
- Add tests for new features and run linters.
- Keep changes focused and documented.
📜 License
This repository is licensed under the MIT license. See LICENSE for details.
If you'd like, I can also:
- add a GitHub Actions workflow that runs tests and lint on push/PR 🔁
- add a
CONTRIBUTING.mdtemplate for PRs and code style 💬
Which one should I do next? ✨