feat: connectivity redesign phase 2 — instance-aware routing + reference connections by id
Unit Tests / test (push) Successful in 12m6s
Unit Tests / test (push) Successful in 12m6s
apply_routes now iterates over connection instances rather than types:
each instance gets its own fwmark, routing table, interface, and
redirect_port via _routing_connections / _resolve_peer_connection /
_apply_connection_for_src; kill-switch is enforced per iface-instance.
Old per-type MARKS/TABLES constants are kept only as migration scaffolding.
peer_registry: exit_via is now stored as a connection id (or 'default');
_migrate_exit_via_to_connection_id runs on _load_peers to upgrade legacy
type-string values; set_peer_exit_via validates against known connection
ids; VALID_EXIT_VIA removed; config_manager wired in from managers.py.
egress_manager: egress_overrides keyed by service_id → connection_id;
local MARKS/TABLES/EXIT_TYPES/_REDIRECT_PORTS/_add_tor_redirect removed;
(mark, table, redirect_port) resolved at apply-time via
connectivity_manager.get_connection; manifest egress.allowed still
enforced by connection type.
api/app.py + api.js: PUT peer/service exit endpoints accept {connection_id};
back-compat shim resolves a legacy type string to its single active instance.
Tests extended: two same-type instances produce distinct marks/tables/ports;
peer exit_via and egress override id migrations round-trip correctly;
single-instance behaviour is equivalent to the old type-keyed path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+20
-10
@@ -907,13 +907,18 @@ def connectivity_apply_routes():
|
||||
|
||||
@app.route('/api/connectivity/peers/<peer_name>/exit', methods=['PUT'])
|
||||
def connectivity_set_peer_exit(peer_name: str):
|
||||
"""Assign a peer to an egress exit type."""
|
||||
"""Assign a peer to a connection by id (or 'default' to clear).
|
||||
|
||||
Body: {"connection_id": "<id>|default"}. The legacy {"exit_via": "<type>"}
|
||||
field is still accepted as a one-release back-compat shim and resolved to
|
||||
the single connection instance of that type.
|
||||
"""
|
||||
try:
|
||||
data = request.get_json(silent=True) or {}
|
||||
exit_via = data.get('exit_via')
|
||||
if not isinstance(exit_via, str):
|
||||
return jsonify({'ok': False, 'error': 'exit_via is required'}), 400
|
||||
result = connectivity_manager.set_peer_exit(peer_name, exit_via)
|
||||
connection_id = data.get('connection_id', data.get('exit_via'))
|
||||
if not isinstance(connection_id, str) or not connection_id:
|
||||
return jsonify({'ok': False, 'error': 'connection_id is required'}), 400
|
||||
result = connectivity_manager.set_peer_exit(peer_name, connection_id)
|
||||
if result.get('ok'):
|
||||
return jsonify(result)
|
||||
return jsonify(result), 400
|
||||
@@ -995,13 +1000,18 @@ def egress_status():
|
||||
|
||||
@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."""
|
||||
"""Persist and immediately apply a per-service egress override.
|
||||
|
||||
Body: {"connection_id": "<id>|default"}. The legacy {"exit_type": "<type>"}
|
||||
field is still accepted as a one-release back-compat shim and resolved to
|
||||
the single connection instance of that type.
|
||||
"""
|
||||
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)
|
||||
connection_id = data.get('connection_id', data.get('exit_type'))
|
||||
if not isinstance(connection_id, str) or not connection_id:
|
||||
return jsonify({'ok': False, 'error': 'connection_id is required'}), 400
|
||||
result = egress_manager.set_service_exit(service_id, connection_id)
|
||||
if result.get('ok'):
|
||||
return jsonify(result)
|
||||
return jsonify(result), 400
|
||||
|
||||
Reference in New Issue
Block a user