Files
Kao/detectors/network.py
Spencer Grimes dd8bf6005b Bump to v1.5.0: deduplicate detectors, fix aggregator bugs, fix blocking I/O
- Extract shared send_event/clear_event into detectors/base.py, removing
  ~150 lines of duplication across all 6 detectors
- Fix default aggregator URL from port 5000 to 5100 in all detectors
- Standardize cpu.py and memory.py to use active_alerts set pattern
- Fix immediate emote rotation on startup (last_emote_change = time.time())
- Extract magic numbers to named constants in aggregator
- Protect write_status() with try/except OSError
- Fix notify event ID collision with monotonic counter
- Replace blocking stream_output() with background daemon threads in kao.py

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-06 12:17:17 -06:00

89 lines
2.7 KiB
Python

"""
Network/Ping Detector
Monitors if hosts are reachable via ping.
Environment variables:
AGGREGATOR_URL - URL of the aggregator (default: http://localhost:5100)
CHECK_INTERVAL - Seconds between checks (default: 60)
HOSTS - Comma-separated list of hosts to ping (required)
Example: "8.8.8.8,google.com,192.168.1.1"
TIMEOUT - Ping timeout in seconds (default: 5)
"""
import os
import sys
import time
import platform
import subprocess
from detectors.base import DEFAULT_AGGREGATOR_URL, send_event, clear_event
# Configuration from environment
AGGREGATOR_URL = os.environ.get("AGGREGATOR_URL", DEFAULT_AGGREGATOR_URL)
CHECK_INTERVAL = int(os.environ.get("CHECK_INTERVAL", 60))
HOSTS = os.environ.get("HOSTS", "")
TIMEOUT = int(os.environ.get("TIMEOUT", 5))
def ping(host):
"""Ping a host. Returns True if reachable."""
param = "-n" if platform.system().lower() == "windows" else "-c"
timeout_param = "-w" if platform.system().lower() == "windows" else "-W"
timeout_val = str(TIMEOUT * 1000) if platform.system().lower() == "windows" else str(TIMEOUT)
try:
result = subprocess.run(
["ping", param, "1", timeout_param, timeout_val, host],
stdout=subprocess.DEVNULL,
stderr=subprocess.DEVNULL,
timeout=TIMEOUT + 2
)
return result.returncode == 0
except subprocess.TimeoutExpired:
return False
except Exception:
return False
def main():
if not HOSTS:
print("ERROR: HOSTS environment variable is required")
print("Example: HOSTS=8.8.8.8,google.com python detectors/network.py")
sys.exit(1)
hosts = [h.strip() for h in HOSTS.split(",") if h.strip()]
print(f"Network/Ping Detector started")
print(f" Aggregator: {AGGREGATOR_URL}")
print(f" Interval: {CHECK_INTERVAL}s")
print(f" Timeout: {TIMEOUT}s")
print(f" Monitoring: {', '.join(hosts)}")
print()
# Track which hosts have active alerts
active_alerts = set()
while True:
current_alerts = set()
for host in hosts:
event_id = f"ping_{host.replace('.', '_').replace(':', '_')}"
if ping(host):
print(f"[OK] Host '{host}' is reachable")
else:
send_event(AGGREGATOR_URL, event_id, 1, f"Host '{host}' is unreachable", CHECK_INTERVAL)
current_alerts.add(event_id)
# Clear alerts for hosts that are now reachable
for event_id in active_alerts - current_alerts:
clear_event(AGGREGATOR_URL, event_id)
active_alerts = current_alerts
time.sleep(CHECK_INTERVAL)
if __name__ == "__main__":
main()