Initial commit: server-monitor v1 (Python)

Kompletter Neustart als Python-Projekt.
Portiert von zfs-monitor Bash v3, saubere Architektur:
- config.py: TOML-Config mit dataclasses
- state.py: zentrales State-Management (JSON statt Einzeldateien)
- notify.py: Telegram + Persistent Alerting als wiederverwendbare Klasse
- checks/zfs.py: ZFS Pool-Health, I/O-Fehler, Kapazität
- checks/smart.py: SATA + NVMe SMART-Monitoring
- checks/nut.py: NUT/USV-Monitoring (APC Back-UPS RS 1500G)
This commit is contained in:
2026-04-12 04:15:02 +02:00
commit c756195530
14 changed files with 1096 additions and 0 deletions
+65
View File
@@ -0,0 +1,65 @@
#!/usr/bin/env python3
"""server-monitor Erweitertes Server-Monitoring mit Telegram-Alerts."""
from __future__ import annotations
import logging
import sys
from pathlib import Path
from config import load_config
from notify import Alerter
from state import State
from checks.zfs import ZFSCheck
from checks.smart import SmartCheck
from checks.nut import NutCheck
CONFIG_FILE = "/etc/server-monitor.toml"
def setup_logging(log_file: str) -> None:
Path(log_file).parent.mkdir(parents=True, exist_ok=True)
logging.basicConfig(
level=logging.INFO,
format="[%(asctime)s] %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
handlers=[
logging.FileHandler(log_file),
logging.StreamHandler(sys.stdout),
],
)
def main() -> None:
try:
config = load_config(CONFIG_FILE)
except (FileNotFoundError, ValueError) as e:
print(f"FEHLER: {e}", file=sys.stderr)
sys.exit(1)
setup_logging(config.log_file)
log = logging.getLogger("main")
state = State(config.state_file)
alerter = Alerter(config, state)
log.info("====== server-monitor Start ======")
checks = [
ZFSCheck(config, state, alerter),
SmartCheck(config, state, alerter),
]
if config.nut.enabled:
checks.append(NutCheck(config, state, alerter))
for check in checks:
try:
check.run()
except Exception as e:
log.error("Check %s fehlgeschlagen: %s", check.__class__.__name__, e)
log.info("====== server-monitor Ende ======")
if __name__ == "__main__":
main()