wire: AccountManager HTTP dispatch + EgressManager startup + egress API routes
Unit Tests / test (push) Successful in 11m15s

- add_peer() now calls account_manager.provision() for any installed store
  service whose manifest declares accounts.manager == 'http', enabling
  per-peer credential provisioning to third-party HTTP services
- reapply_on_startup() calls egress_manager.apply_all() so fwmark rules
  survive container restarts without manual intervention
- add GET /api/egress/status and PUT /api/egress/services/<id>/exit routes
  so the UI can read and override per-service egress policy
- tests: HTTP provision wiring (happy path + non-fatal failure), egress
  apply_all at startup (wired/unwired/failure cases)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 10:30:41 -04:00
parent a906c26b5d
commit 41d09c598b
5 changed files with 177 additions and 0 deletions
+27
View File
@@ -854,6 +854,33 @@ def connectivity_get_peer_exits():
return jsonify({'error': str(e)}), 500
@app.route('/api/egress/status', methods=['GET'])
def egress_status():
"""Return egress status for all installed services that have an egress config."""
try:
return jsonify(egress_manager.get_status())
except Exception as e:
logger.error(f"egress_status: {e}")
return jsonify({'error': str(e)}), 500
@app.route('/api/egress/services/<service_id>/exit', methods=['PUT'])
def egress_set_service_exit(service_id: str):
"""Persist and immediately apply a per-service egress override."""
try:
data = request.get_json(silent=True) or {}
exit_type = data.get('exit_type')
if not isinstance(exit_type, str):
return jsonify({'ok': False, 'error': 'exit_type is required'}), 400
result = egress_manager.set_service_exit(service_id, exit_type)
if result.get('ok'):
return jsonify(result)
return jsonify(result), 400
except Exception as e:
logger.error(f"egress_set_service_exit({service_id}): {e}")
return jsonify({'error': str(e)}), 500
if __name__ == '__main__':
debug = os.environ.get('FLASK_DEBUG', '0') == '1'
app.run(host='0.0.0.0', port=3000, debug=debug)
+14
View File
@@ -89,6 +89,20 @@ def add_peer():
except Exception as e:
logger.warning(f"Peer {peer_name}: {step_name} account creation failed (non-fatal): {e}")
# Provision accounts for installed HTTP-backed store services (non-fatal)
try:
from app import account_manager as _am, config_manager as _cfg, service_registry as _sreg
for _svc_id in (_cfg.get_installed_services() or {}):
_svc_info = _sreg.get(_svc_id)
if _svc_info and (_svc_info.get('accounts') or {}).get('manager') == 'http':
try:
_am.provision(_svc_id, peer_name)
except Exception as _he:
logger.warning('Peer %s: HTTP account provision for %s failed (non-fatal): %s',
peer_name, _svc_id, _he)
except Exception as _am_err:
logger.warning('Peer %s: HTTP store provisioning failed (non-fatal): %s', peer_name, _am_err)
peer_info = {
'peer': peer_name,
'ip': assigned_ip,
+7
View File
@@ -436,3 +436,10 @@ class ServiceStoreManager(BaseServiceManager):
self.service_composer.reapply_active_services()
except Exception as e:
logger.warning('reapply_on_startup: reapply_active_services failed: %s', e)
# Re-apply egress fwmark rules
if self.egress_manager is not None:
try:
self.egress_manager.apply_all()
except Exception as e:
logger.warning('reapply_on_startup: egress apply_all failed: %s', e)