87c321c1c9
Unit Tests / test (push) Successful in 11m21s
ServiceStoreManager.install() now delegates container lifecycle to ServiceComposer (per-service docker-compose.yml) instead of appending to a shared compose override. This eliminates IP pool allocation, compose override rendering, and the single-stack docker exec approach. Changes: - service_composer.py: add _resolve_requires(), _resolve_dependents(), reapply_active_services() — dependency graph and startup reapply - service_store_manager.py: rewrite install() and remove() to use ServiceComposer; add _fetch_template(); delete _allocate_service_ip(), _render_compose_override(), _write_compose_override(); remove() now guards against removing services that others depend on - managers.py: pass service_composer= to ServiceStoreManager - Tests: 13 new composer dep tests; TestInstall/TestRemove rewritten for the new composer-driven path; test_optional_services_feature.py updated Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
137 lines
5.6 KiB
Python
137 lines
5.6 KiB
Python
"""
|
|
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
|
|
|
|
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')
|
|
|
|
# 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)
|
|
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)
|
|
setup_manager = SetupManager(config_manager=config_manager, auth_manager=auth_manager)
|
|
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)
|
|
connectivity_manager = ConnectivityManager(
|
|
config_manager=config_manager,
|
|
peer_registry=peer_registry,
|
|
data_dir=DATA_DIR,
|
|
config_dir=CONFIG_DIR,
|
|
)
|
|
|
|
service_composer = ServiceComposer(config_manager=config_manager, data_dir=DATA_DIR)
|
|
account_manager = AccountManager(
|
|
service_registry=service_registry,
|
|
data_dir=DATA_DIR,
|
|
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,
|
|
)
|
|
|
|
# Service logger configuration
|
|
_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)
|
|
|
|
# Apply any persisted log level overrides
|
|
import json as _json
|
|
_levels_file = os.path.join(os.path.dirname(__file__), 'config', 'log_levels.json')
|
|
if os.path.exists(_levels_file):
|
|
try:
|
|
with open(_levels_file) as _lf:
|
|
for _s, _l in _json.load(_lf).items():
|
|
log_manager.set_service_level(_s, _l)
|
|
except Exception:
|
|
pass
|
|
|
|
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',
|
|
'firewall_manager', 'EventType',
|
|
'DATA_DIR', 'CONFIG_DIR',
|
|
]
|