302 lines
12 KiB
Python
302 lines
12 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Cell Manager for Personal Internet Cell
|
|
Handles overall cell configuration and service orchestration
|
|
"""
|
|
|
|
from network_manager import NetworkManager
|
|
from wireguard_manager import WireGuardManager
|
|
from peer_registry import PeerRegistry
|
|
from email_manager import EmailManager
|
|
from calendar_manager import CalendarManager
|
|
from file_manager import FileManager
|
|
from routing_manager import RoutingManager
|
|
from vault_manager import VaultManager
|
|
from container_manager import ContainerManager
|
|
from datetime import datetime
|
|
import json
|
|
import logging
|
|
from pathlib import Path
|
|
from typing import Dict, List, Any
|
|
from base_service_manager import BaseServiceManager
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
class CellManager(BaseServiceManager):
|
|
"""Manages overall cell configuration and service orchestration"""
|
|
|
|
def __init__(self, config_path=None, data_dir: str = '/app/data', config_dir: str = '/app/config'):
|
|
super().__init__('cell', data_dir, config_dir)
|
|
import os
|
|
self.config_path = Path(config_path or os.environ.get('CELL_CONFIG_PATH', 'cell_config.json'))
|
|
|
|
# Initialize all service managers
|
|
self.network_manager = NetworkManager(data_dir, config_dir)
|
|
self.wireguard_manager = WireGuardManager(data_dir, config_dir)
|
|
self.peer_registry = PeerRegistry()
|
|
self.email_manager = EmailManager(data_dir, config_dir)
|
|
self.calendar_manager = CalendarManager(data_dir, config_dir)
|
|
self.file_manager = FileManager(data_dir, config_dir)
|
|
self.routing_manager = RoutingManager(data_dir, config_dir)
|
|
self.vault_manager = VaultManager(config_dir, data_dir)
|
|
self.container_manager = ContainerManager(data_dir, config_dir)
|
|
|
|
self._peers = []
|
|
self._uptime = 3600
|
|
|
|
# Load config from file if exists
|
|
if self.config_path.exists():
|
|
with open(self.config_path, 'r') as f:
|
|
self.config = json.load(f)
|
|
else:
|
|
self.cell_name = os.environ.get("CELL_NAME", "personal-internet-cell")
|
|
self.domain = os.environ.get("DOMAIN", f"{self.cell_name}.cell")
|
|
self.ip_range = os.environ.get("IP_RANGE", "10.0.0.0/24")
|
|
self.wireguard_port = int(os.environ.get("WIREGUARD_PORT", 51820))
|
|
self.dns_port = int(os.environ.get("DNS_PORT", 53))
|
|
self.dhcp_range = os.environ.get("DHCP_RANGE", "10.0.0.100-10.0.200")
|
|
self.config = {
|
|
"cell_name": self.cell_name,
|
|
"domain": self.domain,
|
|
"ip_range": self.ip_range,
|
|
"wireguard_port": self.wireguard_port,
|
|
"dns_port": self.dns_port,
|
|
"dhcp_range": self.dhcp_range,
|
|
"created_at": datetime.utcnow().isoformat()
|
|
}
|
|
|
|
# Always update attributes from config
|
|
for k, v in self.config.items():
|
|
setattr(self, k, v)
|
|
|
|
def get_status(self) -> Dict[str, Any]:
|
|
"""Get cell service status"""
|
|
try:
|
|
services_status = self.get_services_status()
|
|
|
|
# Count healthy services
|
|
healthy_services = 0
|
|
total_services = len(services_status)
|
|
|
|
for service_name, status in services_status.items():
|
|
if status.get('running', False):
|
|
healthy_services += 1
|
|
|
|
status = {
|
|
'running': healthy_services > 0,
|
|
'status': 'online' if healthy_services > 0 else 'offline',
|
|
'cell_name': self.config["cell_name"],
|
|
'domain': self.config["domain"],
|
|
'ip_range': self.config["ip_range"],
|
|
'wireguard_port': self.config["wireguard_port"],
|
|
'dns_port': self.config["dns_port"],
|
|
'dhcp_range': self.config["dhcp_range"],
|
|
'uptime': self._uptime,
|
|
'peers_count': len(self._peers),
|
|
'healthy_services': healthy_services,
|
|
'total_services': total_services,
|
|
'services': services_status,
|
|
'timestamp': datetime.utcnow().isoformat()
|
|
}
|
|
|
|
return status
|
|
except Exception as e:
|
|
return self.handle_error(e, "get_status")
|
|
|
|
def test_connectivity(self) -> Dict[str, Any]:
|
|
"""Test cell service connectivity"""
|
|
try:
|
|
# Test all service managers connectivity
|
|
network_test = self.network_manager.test_connectivity()
|
|
wireguard_test = self.wireguard_manager.test_connectivity()
|
|
email_test = self.email_manager.test_connectivity()
|
|
calendar_test = self.calendar_manager.test_connectivity()
|
|
files_test = self.file_manager.test_connectivity()
|
|
routing_test = self.routing_manager.test_connectivity()
|
|
vault_test = self.vault_manager.test_connectivity()
|
|
container_test = self.container_manager.test_connectivity()
|
|
|
|
# Calculate overall success
|
|
all_tests = [
|
|
network_test, wireguard_test, email_test, calendar_test,
|
|
files_test, routing_test, vault_test, container_test
|
|
]
|
|
|
|
successful_tests = sum(1 for test in all_tests if test.get('success', False))
|
|
total_tests = len(all_tests)
|
|
|
|
results = {
|
|
'network': network_test,
|
|
'wireguard': wireguard_test,
|
|
'email': email_test,
|
|
'calendar': calendar_test,
|
|
'files': files_test,
|
|
'routing': routing_test,
|
|
'vault': vault_test,
|
|
'container': container_test,
|
|
'success': successful_tests > 0,
|
|
'successful_tests': successful_tests,
|
|
'total_tests': total_tests,
|
|
'timestamp': datetime.utcnow().isoformat()
|
|
}
|
|
|
|
return results
|
|
except Exception as e:
|
|
return self.handle_error(e, "test_connectivity")
|
|
|
|
def save_config(self):
|
|
"""Save cell configuration"""
|
|
try:
|
|
with open(self.config_path, 'w') as f:
|
|
json.dump(self.config, f, indent=2)
|
|
self.logger.info("Cell configuration saved")
|
|
return True
|
|
except Exception as e:
|
|
self.logger.error(f"Error saving cell configuration: {e}")
|
|
return False
|
|
|
|
def get_config(self) -> Dict[str, Any]:
|
|
"""Get cell configuration"""
|
|
return {
|
|
"cell_name": self.cell_name,
|
|
"domain": self.domain,
|
|
"ip_range": self.ip_range,
|
|
"wireguard_port": self.wireguard_port,
|
|
"dns_port": self.dns_port,
|
|
"dhcp_range": self.dhcp_range
|
|
}
|
|
|
|
def update_config(self, config: Dict[str, Any]) -> Dict[str, Any]:
|
|
"""Update cell configuration"""
|
|
try:
|
|
# Update config attributes from dict
|
|
for k, v in config.items():
|
|
if hasattr(self, k):
|
|
setattr(self, k, v)
|
|
self.config[k] = v
|
|
|
|
# Save updated config
|
|
self.save_config()
|
|
|
|
return {"status": "updated", "message": "Configuration updated successfully"}
|
|
except Exception as e:
|
|
return {"status": "error", "message": f"Failed to update configuration: {str(e)}"}
|
|
|
|
def get_peers(self) -> List[Dict[str, Any]]:
|
|
"""Get all peers"""
|
|
return self._peers
|
|
|
|
def add_peer(self, peer: Dict[str, Any]) -> tuple[bool, str]:
|
|
"""Add a new peer"""
|
|
try:
|
|
# Simulate validation: must have name, ip, public_key
|
|
if not all(k in peer for k in ("name", "ip", "public_key")):
|
|
return False, "Missing required fields"
|
|
|
|
# Prevent duplicate peer names
|
|
if any(p['name'] == peer['name'] for p in self._peers):
|
|
return False, "Peer already exists"
|
|
|
|
self._peers.append(peer)
|
|
self.logger.info(f"Added peer: {peer['name']}")
|
|
return True, "Peer added successfully"
|
|
except Exception as e:
|
|
self.logger.error(f"Error adding peer: {e}")
|
|
return False, f"Error adding peer: {str(e)}"
|
|
|
|
def remove_peer(self, name: str) -> tuple[bool, str]:
|
|
"""Remove a peer"""
|
|
try:
|
|
for i, p in enumerate(self._peers):
|
|
if p['name'] == name:
|
|
del self._peers[i]
|
|
self.logger.info(f"Removed peer: {name}")
|
|
return True, "Peer removed successfully"
|
|
return False, "Peer not found"
|
|
except Exception as e:
|
|
self.logger.error(f"Error removing peer {name}: {e}")
|
|
return False, f"Error removing peer: {str(e)}"
|
|
|
|
def get_services_status(self) -> Dict[str, Any]:
|
|
"""Get status of all services"""
|
|
try:
|
|
return {
|
|
"network": self.network_manager.get_status(),
|
|
"wireguard": self.wireguard_manager.get_status(),
|
|
"email": self.email_manager.get_status(),
|
|
"calendar": self.calendar_manager.get_status(),
|
|
"files": self.file_manager.get_status(),
|
|
"routing": self.routing_manager.get_status(),
|
|
"vault": self.vault_manager.get_status(),
|
|
"container": self.container_manager.get_status()
|
|
}
|
|
except Exception as e:
|
|
self.logger.error(f"Error getting services status: {e}")
|
|
return {}
|
|
|
|
def get_uptime(self) -> int:
|
|
"""Get cell uptime"""
|
|
return self._uptime
|
|
|
|
def restart_all_services(self) -> Dict[str, Any]:
|
|
"""Restart all services"""
|
|
try:
|
|
results = {}
|
|
|
|
# Restart each service manager
|
|
services = {
|
|
'network': self.network_manager,
|
|
'wireguard': self.wireguard_manager,
|
|
'email': self.email_manager,
|
|
'calendar': self.calendar_manager,
|
|
'files': self.file_manager,
|
|
'routing': self.routing_manager,
|
|
'vault': self.vault_manager,
|
|
'container': self.container_manager
|
|
}
|
|
|
|
for service_name, service_manager in services.items():
|
|
try:
|
|
success = service_manager.restart_service()
|
|
results[service_name] = {
|
|
'success': success,
|
|
'message': f"Service {'restarted' if success else 'failed to restart'}"
|
|
}
|
|
except Exception as e:
|
|
results[service_name] = {
|
|
'success': False,
|
|
'message': f"Error restarting service: {str(e)}"
|
|
}
|
|
|
|
return {
|
|
'success': any(r.get('success', False) for r in results.values()),
|
|
'results': results,
|
|
'timestamp': datetime.utcnow().isoformat()
|
|
}
|
|
except Exception as e:
|
|
return self.handle_error(e, "restart_all_services")
|
|
|
|
def get_health_summary(self) -> Dict[str, Any]:
|
|
"""Get comprehensive health summary"""
|
|
try:
|
|
services_status = self.get_services_status()
|
|
connectivity = self.test_connectivity()
|
|
|
|
# Calculate health metrics
|
|
healthy_services = sum(1 for status in services_status.values() if status.get('running', False))
|
|
total_services = len(services_status)
|
|
health_percentage = (healthy_services / total_services * 100) if total_services > 0 else 0
|
|
|
|
return {
|
|
'overall_health': 'healthy' if health_percentage >= 80 else 'degraded' if health_percentage >= 50 else 'unhealthy',
|
|
'health_percentage': round(health_percentage, 2),
|
|
'healthy_services': healthy_services,
|
|
'total_services': total_services,
|
|
'services_status': services_status,
|
|
'connectivity': connectivity,
|
|
'uptime': self._uptime,
|
|
'peers_count': len(self._peers),
|
|
'timestamp': datetime.utcnow().isoformat()
|
|
}
|
|
except Exception as e:
|
|
return self.handle_error(e, "get_health_summary") |