fix(P2): peer add rollback, helper failure recovery, manager extraction (A2/A3/A5)
A3 — Peer add atomicity: track firewall_applied flag and call
clear_peer_rules() during rollback so partial peer-add failures
don't leave stale iptables rules behind. Added test.
A2 — Pending config flag: instead of clearing before spawning the
helper container (fire-and-forget), set applying=True and let the
helper clear it on success by writing to cell_config.json via a
mounted /app/data volume. On API restart after a failed apply,
_recover_pending_apply() resets the applying flag so the UI shows
pending changes and the user can retry. GET /api/config/pending now
includes the applying field.
A5 (foundation) — Extract all manager instantiation into managers.py.
app.py re-exports every name so existing test patches (patch('app.X'))
continue to work unchanged. 1021 unit tests pass.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
"""
|
||||
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
|
||||
|
||||
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')
|
||||
|
||||
network_manager = NetworkManager(data_dir=DATA_DIR, config_dir=CONFIG_DIR)
|
||||
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)
|
||||
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)
|
||||
|
||||
# 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',
|
||||
'firewall_manager', 'EventType',
|
||||
'DATA_DIR', 'CONFIG_DIR',
|
||||
]
|
||||
Reference in New Issue
Block a user