Files
wevads-platform/scripts/server-manager.py
2026-02-26 04:53:11 +01:00

282 lines
8.1 KiB
Python
Executable File

#!/usr/bin/env python3
"""
SERVER MANAGER
Gestion automatique des serveurs PMTA
- Création sur providers cloud
- Destruction si blacklisté
- Rotation d'IPs
"""
import psycopg2
import requests
import json
import sys
from datetime import datetime, timedelta
DB_CONFIG = {
'host': 'localhost',
'database': 'adx_system',
'user': 'admin',
'password': 'admin123'
}
def get_db():
return psycopg2.connect(**DB_CONFIG)
def get_provider_api(provider_name):
"""Get provider API config"""
conn = get_db()
cur = conn.cursor()
cur.execute("""
SELECT api_url, api_key, api_secret, default_region
FROM admin.cloud_providers
WHERE name = %s AND is_active = true
""", (provider_name,))
result = cur.fetchone()
conn.close()
return result
def create_server_hetzner(name, server_type='cx11'):
"""Create server on Hetzner"""
api = get_provider_api('hetzner')
if not api or not api[1]:
return {'error': 'Hetzner API not configured'}
api_url, api_key, _, region = api
headers = {
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
}
data = {
'name': name,
'server_type': server_type,
'location': region or 'hel1',
'image': 'ubuntu-22.04',
'start_after_create': True
}
try:
response = requests.post(
'https://api.hetzner.cloud/v1/servers',
headers=headers,
json=data,
timeout=60
)
if response.status_code == 201:
result = response.json()
return {
'success': True,
'server_id': result['server']['id'],
'ip': result['server']['public_net']['ipv4']['ip'],
'status': result['server']['status']
}
else:
return {'error': response.text}
except Exception as e:
return {'error': str(e)}
def create_server_scaleway(name, server_type='DEV1-S'):
"""Create server on Scaleway"""
api = get_provider_api('scaleway')
if not api or not api[1]:
return {'error': 'Scaleway API not configured'}
# Similar implementation...
return {'error': 'Not implemented yet'}
def destroy_server(server_id, provider_name):
"""Destroy a server"""
conn = get_db()
cur = conn.cursor()
# Get server info
cur.execute("SELECT server_id FROM admin.servers WHERE id = %s", (server_id,))
result = cur.fetchone()
if not result:
return {'error': 'Server not found'}
provider_server_id = result[0]
if provider_name == 'hetzner':
api = get_provider_api('hetzner')
if api and api[1]:
headers = {'Authorization': f'Bearer {api[1]}'}
try:
response = requests.delete(
f'https://api.hetzner.cloud/v1/servers/{provider_server_id}',
headers=headers,
timeout=30
)
success = response.status_code in [200, 204]
except Exception as e:
return {'error': str(e)}
else:
success = True # Manual for other providers
if success:
cur.execute("""
UPDATE admin.servers
SET status = 'destroyed', destroyed_at = NOW()
WHERE id = %s
""", (server_id,))
cur.execute("""
INSERT INTO admin.server_actions (server_id, action, triggered_by, success)
VALUES (%s, 'destroy', 'server_manager', true)
""", (server_id,))
conn.commit()
conn.close()
return {'success': success}
def register_server(name, ip, provider_name, server_type='pmta', specs=None):
"""Register existing server in database"""
conn = get_db()
cur = conn.cursor()
cur.execute("""
INSERT INTO admin.servers
(name, ip_address, provider_name, server_type, specs, status, started_at)
VALUES (%s, %s, %s, %s, %s, 'running', NOW())
RETURNING id
""", (name, ip, provider_name, server_type, json.dumps(specs or {})))
server_id = cur.fetchone()[0]
cur.execute("""
INSERT INTO admin.server_actions (server_id, action, triggered_by, success)
VALUES (%s, 'register', 'manual', true)
""", (server_id,))
conn.commit()
conn.close()
return {'success': True, 'server_id': server_id}
def list_servers(status=None):
"""List all servers"""
conn = get_db()
cur = conn.cursor()
query = """
SELECT id, name, ip_address, provider_name, status,
started_at, total_sent, ip_reputation_score, is_blacklisted
FROM admin.servers
"""
if status:
query += f" WHERE status = '{status}'"
query += " ORDER BY started_at DESC"
cur.execute(query)
servers = cur.fetchall()
conn.close()
return servers
def auto_cleanup_burned():
"""Destroy all burned servers"""
conn = get_db()
cur = conn.cursor()
cur.execute("""
SELECT id, name, provider_name, ip_address
FROM admin.servers
WHERE status = 'burned' AND destroyed_at IS NULL
""")
burned = cur.fetchall()
conn.close()
print(f"Found {len(burned)} burned servers to destroy")
for server_id, name, provider, ip in burned:
print(f" Destroying {name} ({ip})...")
result = destroy_server(server_id, provider)
if result.get('success'):
print(f" ✅ Destroyed")
else:
print(f" ❌ Error: {result.get('error')}")
return len(burned)
def show_status():
"""Show server fleet status"""
servers = list_servers()
print("=" * 80)
print("SERVER FLEET STATUS")
print("=" * 80)
by_status = {}
by_provider = {}
total_sent = 0
for s in servers:
sid, name, ip, provider, status, started, sent, rep, blacklisted = s
by_status[status] = by_status.get(status, 0) + 1
by_provider[provider] = by_provider.get(provider, 0) + 1
total_sent += sent or 0
print(f"\nTotal servers: {len(servers)}")
print(f"Total emails sent: {total_sent:,}")
print("\nBy Status:")
for status, count in sorted(by_status.items()):
emoji = {'running': '🟢', 'burned': '🔴', 'stopped': '🟡', 'destroyed': ''}.get(status, '')
print(f" {emoji} {status}: {count}")
print("\nBy Provider:")
for provider, count in sorted(by_provider.items()):
print(f" {provider}: {count}")
print("\n" + "-" * 80)
print(f"{'ID':<4} {'Name':<20} {'IP':<16} {'Provider':<10} {'Status':<10} {'Sent':<8} {'Rep':<4} {'BL'}")
print("-" * 80)
for s in servers[:20]: # Show top 20
sid, name, ip, provider, status, started, sent, rep, blacklisted = s
bl_mark = "🚨" if blacklisted else ""
print(f"{sid:<4} {name[:20]:<20} {str(ip):<16} {provider or '-':<10} {status:<10} {sent or 0:<8} {rep or 0:<4} {bl_mark}")
def main():
if len(sys.argv) < 2:
show_status()
return
cmd = sys.argv[1]
if cmd == 'status':
show_status()
elif cmd == 'list':
status = sys.argv[2] if len(sys.argv) > 2 else None
servers = list_servers(status)
for s in servers:
print(s)
elif cmd == 'register':
if len(sys.argv) < 5:
print("Usage: server-manager.py register <name> <ip> <provider>")
return
name, ip, provider = sys.argv[2], sys.argv[3], sys.argv[4]
result = register_server(name, ip, provider)
print(result)
elif cmd == 'destroy':
if len(sys.argv) < 3:
print("Usage: server-manager.py destroy <server_id>")
return
server_id = int(sys.argv[2])
result = destroy_server(server_id, 'manual')
print(result)
elif cmd == 'cleanup':
auto_cleanup_burned()
else:
print(f"Unknown command: {cmd}")
print("Commands: status, list, register, destroy, cleanup")
if __name__ == '__main__':
main()