Add new Ansible roles and configuration for the edge proxy and private network architecture: ## New Roles: - **edge-traefik**: Edge reverse proxy that routes to private clients - Dynamic routing configuration for multiple clients - SSL termination at the edge - Routes traffic to private IPs (10.0.0.x) - **nat-gateway**: NAT/gateway configuration for edge server - IP forwarding and masquerading - Allows private network clients to access internet - iptables rules for Docker integration - **diun**: Docker Image Update Notifier - Monitors containers for available updates - Email notifications via Mailgun - Per-client configuration - **kuma**: Uptime monitoring integration - Registers HTTP monitors for client services - Automated monitor creation via API - Checks Authentik, Nextcloud, Collabora endpoints ## New Playbooks: - **setup-edge.yml**: Configure edge server with proxy and NAT ## Configuration: - **host_vars**: Per-client Ansible configuration (valk, white) - SSH bastion configuration for private IPs - Client-specific secrets file references This enables the scalable multi-tenant architecture where: - Edge server has public IP and routes traffic - Client servers use private IPs only (cost savings) - All traffic flows through edge proxy with SSL termination 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
128 lines
4.6 KiB
Django/Jinja
128 lines
4.6 KiB
Django/Jinja
#!/usr/bin/env python3
|
||
"""
|
||
Uptime Kuma Monitor Registration Script
|
||
Auto-generated for client: {{ client_name }}
|
||
"""
|
||
|
||
import sys
|
||
from uptime_kuma_api import UptimeKumaApi, MonitorType
|
||
|
||
# Configuration
|
||
KUMA_URL = "{{ kuma_url }}"
|
||
KUMA_USERNAME = "{{ kuma_username | default('') }}"
|
||
KUMA_PASSWORD = "{{ kuma_password | default('') }}"
|
||
CLIENT_NAME = "{{ client_name }}"
|
||
CLIENT_DOMAIN = "{{ client_domain }}"
|
||
|
||
# Monitor definitions
|
||
MONITORS = {{ kuma_monitors | to_json }}
|
||
|
||
# Monitor type mapping
|
||
TYPE_MAP = {
|
||
"http": MonitorType.HTTP,
|
||
"https": MonitorType.HTTP,
|
||
"ping": MonitorType.PING,
|
||
"tcp": MonitorType.PORT,
|
||
"dns": MonitorType.DNS,
|
||
}
|
||
|
||
|
||
def main():
|
||
"""Register monitors with Uptime Kuma"""
|
||
|
||
# Check if credentials are provided
|
||
if not KUMA_USERNAME or not KUMA_PASSWORD:
|
||
print("⚠️ Kuma registration skipped: No credentials provided")
|
||
print("")
|
||
print("To enable automated monitor registration, add to your secrets:")
|
||
print(" kuma_username: your_username")
|
||
print(" kuma_password: your_password")
|
||
print("")
|
||
print("Note: API keys (uk1_*) are only for REST endpoints, not monitor management")
|
||
print("Manual registration required at: https://status.vrije.cloud")
|
||
sys.exit(0) # Exit with success (not a failure, just skipped)
|
||
|
||
try:
|
||
# Connect to Uptime Kuma (Socket.io connection)
|
||
print(f"🔌 Connecting to Uptime Kuma at {KUMA_URL}...")
|
||
api = UptimeKumaApi(KUMA_URL)
|
||
|
||
# Login with username/password
|
||
print(f"🔐 Authenticating as {KUMA_USERNAME}...")
|
||
api.login(KUMA_USERNAME, KUMA_PASSWORD)
|
||
|
||
# Get existing monitors
|
||
print("📋 Fetching existing monitors...")
|
||
existing_monitors = api.get_monitors()
|
||
existing_names = {m['name']: m['id'] for m in existing_monitors}
|
||
|
||
# Register each monitor
|
||
added_count = 0
|
||
updated_count = 0
|
||
skipped_count = 0
|
||
|
||
for monitor_config in MONITORS:
|
||
monitor_name = monitor_config['name']
|
||
monitor_type_str = monitor_config.get('type', 'http').lower()
|
||
monitor_type = TYPE_MAP.get(monitor_type_str, MonitorType.HTTP)
|
||
|
||
# Build monitor parameters
|
||
params = {
|
||
'type': monitor_type,
|
||
'name': monitor_name,
|
||
'interval': monitor_config.get('interval', 60),
|
||
'maxretries': monitor_config.get('maxretries', 3),
|
||
'retryInterval': monitor_config.get('retry_interval', 60),
|
||
}
|
||
|
||
# Add type-specific parameters
|
||
if monitor_type == MonitorType.HTTP:
|
||
params['url'] = monitor_config['url']
|
||
params['method'] = monitor_config.get('method', 'GET')
|
||
if 'expected_status' in monitor_config:
|
||
params['accepted_statuscodes'] = monitor_config['expected_status'].split(',')
|
||
elif monitor_type == MonitorType.PING:
|
||
params['hostname'] = monitor_config.get('hostname', monitor_config.get('url', ''))
|
||
|
||
# Check if monitor already exists
|
||
if monitor_name in existing_names:
|
||
print(f"⚠️ Monitor '{monitor_name}' already exists (ID: {existing_monitors[monitor_name]})")
|
||
print(f" Skipping (update not implemented)")
|
||
skipped_count += 1
|
||
else:
|
||
print(f"➕ Adding monitor: {monitor_name}")
|
||
try:
|
||
result = api.add_monitor(**params)
|
||
print(f" ✓ Added (ID: {result.get('monitorID', 'unknown')})")
|
||
added_count += 1
|
||
except Exception as e:
|
||
print(f" ✗ Failed: {e}")
|
||
|
||
# Disconnect
|
||
api.disconnect()
|
||
|
||
# Summary
|
||
print("")
|
||
print("=" * 60)
|
||
print(f"📊 Registration Summary for {CLIENT_NAME}:")
|
||
print(f" Added: {added_count}")
|
||
print(f" Skipped (already exist): {skipped_count}")
|
||
print(f" Total monitors: {len(MONITORS)}")
|
||
print("=" * 60)
|
||
|
||
if added_count > 0:
|
||
print(f"✅ Successfully registered {added_count} new monitor(s)")
|
||
|
||
except Exception as e:
|
||
print(f"❌ ERROR: Failed to register monitors: {e}")
|
||
print("")
|
||
print("Troubleshooting:")
|
||
print(f" 1. Verify Kuma is accessible: {KUMA_URL}")
|
||
print(" 2. Check username/password are correct")
|
||
print(" 3. Ensure uptime-kuma-api Python package is installed")
|
||
print(" 4. Check network connectivity from deployment machine")
|
||
sys.exit(1)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|