#!/usr/bin/env python3 """ Automated Uptime Kuma Monitor Setup for tower-of-joy Infrastructure This script automatically creates monitors for all infrastructure services in Uptime Kuma. It is idempotent - safe to run multiple times without creating duplicates. Usage: source .venv/bin/activate python3 scripts/setup-kuma-monitors.py Environment Variables: KUMA_URL: Uptime Kuma URL (default: http://192.168.86.149:3001) KUMA_USERNAME: Uptime Kuma admin username (will prompt if not set) KUMA_PASSWORD: Uptime Kuma admin password (will prompt if not set) """ import os import sys from getpass import getpass try: from uptime_kuma_api import UptimeKumaApi, MonitorType except ImportError: print("\033[0;31mError: uptime-kuma-api package not installed\033[0m") print("\nInstall dependencies:") print(" source .venv/bin/activate") print(" pip install -r requirements.txt") sys.exit(1) # Configuration KUMA_URL = os.getenv("KUMA_URL", "http://192.168.86.149:3001") # Service definitions MONITORS = [ { "name": "Portainer", "url": "http://192.168.86.149:8001", "interval": 60, "type": MonitorType.HTTP, "description": "Container management interface" }, { "name": "Nginx Proxy Manager", "url": "http://192.168.86.149:81", "interval": 60, "type": MonitorType.HTTP, "description": "Reverse proxy admin interface" }, { "name": "Ollama API", "url": "http://192.168.86.149:11434", "interval": 60, "type": MonitorType.HTTP, "description": "ML model API endpoint" }, { "name": "Headscale", "url": "http://192.168.86.149:8085/health", "interval": 60, "type": MonitorType.HTTP, "description": "Mesh VPN control server" }, { "name": "Uptime Kuma", "url": "http://192.168.86.149:3001", "interval": 120, "type": MonitorType.HTTP, "description": "Service monitoring (self-check)" }, { "name": "Netdata", "url": "http://192.168.86.149:19999", "interval": 60, "type": MonitorType.HTTP, "description": "System metrics dashboard" }, { "name": "Heimdall", "url": "http://192.168.86.149:8888", "interval": 60, "type": MonitorType.HTTP, "description": "Application dashboard" }, { "name": "Organizr", "url": "http://192.168.86.149:9999", "interval": 60, "type": MonitorType.HTTP, "description": "Unified dashboard" }, { "name": "Jellyfin", "url": "http://192.168.86.149:8096", "interval": 60, "type": MonitorType.HTTP, "description": "Media streaming server" }, ] def print_color(text, color="reset"): """Print colored text""" colors = { "red": "\033[0;31m", "green": "\033[0;32m", "yellow": "\033[1;33m", "blue": "\033[0;34m", "cyan": "\033[0;36m", "reset": "\033[0m" } print(f"{colors.get(color, '')}{text}{colors['reset']}") def get_credentials(): """Get credentials from environment or prompt user""" username = os.getenv("KUMA_USERNAME") password = os.getenv("KUMA_PASSWORD") if not username: print_color("\nUptime Kuma credentials required", "yellow") username = input("Username: ").strip() if not password: password = getpass("Password: ").strip() return username, password def setup_monitors(): """Configure all monitors in Uptime Kuma""" print_color("╔════════════════════════════════════════════╗", "blue") print_color("║ Uptime Kuma Automated Monitor Setup ║", "blue") print_color("╚════════════════════════════════════════════╝", "blue") print() print(f"Target: {KUMA_URL}") print(f"Monitors to configure: {len(MONITORS)}") print() # Get credentials username, password = get_credentials() # Connect to Uptime Kuma print_color("\nConnecting to Uptime Kuma...", "blue") try: api = UptimeKumaApi(KUMA_URL) api.login(username, password) print_color("✓ Connected successfully", "green") except Exception as e: print_color(f"✗ Connection failed: {e}", "red") print() print("Troubleshooting:") print(" 1. Verify Uptime Kuma is running: docker ps | grep uptime-kuma") print(f" 2. Check URL is correct: {KUMA_URL}") print(" 3. Verify credentials are correct") sys.exit(1) print() # Get existing monitors print_color("Fetching existing monitors...", "blue") existing_monitors = api.get_monitors() existing_names = {m["name"] for m in existing_monitors} print(f"Found {len(existing_monitors)} existing monitor(s)") print() # Configure each monitor print_color("Configuring monitors...", "blue") print() created = 0 skipped = 0 failed = 0 for monitor_def in MONITORS: name = monitor_def["name"] if name in existing_names: print(f"⊙ {name} - Already exists (skipping)") skipped += 1 continue try: # Create the monitor api.add_monitor( type=monitor_def["type"], name=name, url=monitor_def["url"], interval=monitor_def["interval"], description=monitor_def.get("description", ""), retryInterval=60, resendInterval=0, maxretries=1, upsideDown=False, notificationIDList=[], httpBodyEncoding="utf8", method="GET", maxredirects=10, accepted_statuscodes=["200-299"] ) print_color(f"✓ {name} - Created", "green") print(f" URL: {monitor_def['url']}") print(f" Interval: {monitor_def['interval']}s") created += 1 except Exception as e: print_color(f"✗ {name} - Failed: {e}", "red") failed += 1 print() # Disconnect api.disconnect() # Summary print_color("═══════════════════════════════════════════", "blue") print_color("Summary:", "green") print_color("═══════════════════════════════════════════", "blue") print(f"Created: {created}") print(f"Skipped (already exist): {skipped}") print(f"Failed: {failed}") print() if created > 0: print_color("✓ Setup complete! Monitors are now active.", "green") print() print("View monitors at:", KUMA_URL) print("Refresh Organizr to see status widgets update") elif skipped == len(MONITORS): print_color("✓ All monitors already configured", "green") else: print_color("⚠ Some monitors could not be created", "yellow") sys.exit(1) if __name__ == "__main__": try: setup_monitors() except KeyboardInterrupt: print() print_color("Setup cancelled by user", "yellow") sys.exit(130) except Exception as e: print() print_color(f"Unexpected error: {e}", "red") import traceback traceback.print_exc() sys.exit(1)