""" Manager singletons for the PIC API. All service managers are instantiated here and imported by app.py. Routes in app.py reference these by name from app's own namespace (so test patches via `patch('app.email_manager', mock)` continue to work as before). Directory/path env vars: DATA_DIR — host-mapped persistent data directory (default: /app/data) CONFIG_DIR — host-mapped config directory (default: /app/config) """ import os 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 config_manager import ConfigManager from service_bus import ServiceBus, EventType from log_manager import LogManager from cell_link_manager import CellLinkManager import firewall_manager from auth_manager import AuthManager from setup_manager import SetupManager from caddy_manager import CaddyManager from ddns_manager import DDNSManager from connectivity_manager import ConnectivityManager from service_registry import ServiceRegistry from service_composer import ServiceComposer from account_manager import AccountManager from audit_manager import AuditManager DATA_DIR = os.environ.get('DATA_DIR', '/app/data') CONFIG_DIR = os.environ.get('CONFIG_DIR', '/app/config') config_manager = ConfigManager( config_file=os.path.join(CONFIG_DIR, 'cell_config.json'), data_dir=DATA_DIR, ) service_bus = ServiceBus() log_manager = LogManager(log_dir='./data/logs') # Attach per-service file loggers BEFORE any manager is instantiated. Managers # log during __init__ via self.logger ('picell.'); without the handlers in # place first, those early records would be lost from the per-service log files. _service_log_configs = { 'network': {'level': 'INFO', 'formatter': 'json', 'console': False}, 'wireguard': {'level': 'INFO', 'formatter': 'json', 'console': False}, 'email': {'level': 'INFO', 'formatter': 'json', 'console': False}, 'calendar': {'level': 'INFO', 'formatter': 'json', 'console': False}, 'files': {'level': 'INFO', 'formatter': 'json', 'console': False}, 'routing': {'level': 'INFO', 'formatter': 'json', 'console': False}, 'vault': {'level': 'INFO', 'formatter': 'json', 'console': False}, 'api': {'level': 'INFO', 'formatter': 'json', 'console': True}, } for _svc, _cfg in _service_log_configs.items(): log_manager.add_service_logger(_svc, _cfg) # ServiceRegistry depends only on config_manager; create it early so # NetworkManager and CaddyManager can derive subdomains from manifests # instead of hardcoding service names. service_registry = ServiceRegistry(config_manager=config_manager) network_manager = NetworkManager(data_dir=DATA_DIR, config_dir=CONFIG_DIR, service_registry=service_registry) wireguard_manager = WireGuardManager(data_dir=DATA_DIR, config_dir=CONFIG_DIR) peer_registry = PeerRegistry(data_dir=DATA_DIR, config_dir=CONFIG_DIR, config_manager=config_manager) email_manager = EmailManager(data_dir=DATA_DIR, config_dir=CONFIG_DIR, service_bus=service_bus) calendar_manager = CalendarManager(data_dir=DATA_DIR, config_dir=CONFIG_DIR) file_manager = FileManager(data_dir=DATA_DIR, config_dir=CONFIG_DIR) routing_manager = RoutingManager(data_dir=DATA_DIR, config_dir=CONFIG_DIR) vault_manager = VaultManager(data_dir=DATA_DIR, config_dir=CONFIG_DIR) container_manager = ContainerManager(data_dir=DATA_DIR, config_dir=CONFIG_DIR) cell_link_manager = CellLinkManager( data_dir=DATA_DIR, config_dir=CONFIG_DIR, wireguard_manager=wireguard_manager, network_manager=network_manager, ) auth_manager = AuthManager(data_dir=DATA_DIR, config_dir=CONFIG_DIR) caddy_manager = CaddyManager(config_manager=config_manager, data_dir=DATA_DIR, config_dir=CONFIG_DIR, service_bus=service_bus, service_registry=service_registry) ddns_manager = DDNSManager(config_manager=config_manager, data_dir=DATA_DIR, config_dir=CONFIG_DIR, service_bus=service_bus, service_registry=service_registry) connectivity_manager = ConnectivityManager( config_manager=config_manager, peer_registry=peer_registry, vault_manager=vault_manager, data_dir=DATA_DIR, config_dir=CONFIG_DIR, ) service_composer = ServiceComposer(config_manager=config_manager, data_dir=DATA_DIR) # Connectivity brings one container up per connection instance via the composer; # wire it now that the composer exists (composer is built after connectivity). connectivity_manager.service_composer = service_composer account_manager = AccountManager( service_registry=service_registry, data_dir=DATA_DIR, config_manager=config_manager, email_manager=email_manager, calendar_manager=calendar_manager, file_manager=file_manager, ) from service_store_manager import ServiceStoreManager service_store_manager = ServiceStoreManager( config_manager=config_manager, caddy_manager=caddy_manager, container_manager=container_manager, data_dir=DATA_DIR, config_dir=CONFIG_DIR, service_composer=service_composer, ) from egress_manager import EgressManager egress_manager = EgressManager( config_manager=config_manager, service_store_manager=service_store_manager, connectivity_manager=connectivity_manager, data_dir=DATA_DIR, config_dir=CONFIG_DIR, ) service_store_manager.egress_manager = egress_manager audit_manager = AuditManager(data_dir=DATA_DIR, config_dir=CONFIG_DIR) setup_manager = SetupManager(config_manager=config_manager, auth_manager=auth_manager, network_manager=network_manager) # Apply persisted per-service log levels from ConfigManager (single source of # truth — the logging section of cell_config). This runs AFTER managers are # instantiated so it overrides their default INFO and reaches the module loggers. try: _logging_cfg = config_manager.get_logging_config() for _svc, _lvl in _logging_cfg['python']['services'].items(): log_manager.set_service_level(_svc, _lvl) except Exception: pass # Let generate_corefile keep the configured CoreDNS log level sticky across all # regenerations, not just verbosity-triggered ones. firewall_manager.set_coredns_level_resolver( lambda: config_manager.get_logging_config()['containers'].get('coredns', 'INFO') ) service_bus.start() __all__ = [ 'config_manager', 'service_bus', 'log_manager', 'network_manager', 'wireguard_manager', 'peer_registry', 'email_manager', 'calendar_manager', 'file_manager', 'routing_manager', 'vault_manager', 'container_manager', 'cell_link_manager', 'auth_manager', 'setup_manager', 'caddy_manager', 'ddns_manager', 'service_store_manager', 'connectivity_manager', 'service_registry', 'service_composer', 'account_manager', 'egress_manager', 'audit_manager', 'firewall_manager', 'EventType', 'DATA_DIR', 'CONFIG_DIR', ]