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:
@@ -65,18 +65,22 @@ class TestConfigApplyRoute(unittest.TestCase):
|
||||
data = json.loads(r.data)
|
||||
self.assertTrue(data.get('restart_in_progress'))
|
||||
|
||||
# ── Pending state cleared after apply ──────────────────────────────────
|
||||
# ── Pending state marked "applying" after apply (not immediately cleared) ─
|
||||
|
||||
@patch('threading.Thread')
|
||||
@patch('docker.from_env')
|
||||
def test_apply_clears_pending_state(self, mock_docker, mock_thread):
|
||||
def test_apply_sets_applying_flag(self, mock_docker, mock_thread):
|
||||
mock_docker.side_effect = Exception('no docker in test')
|
||||
# Don't actually start the thread so we don't need subprocess
|
||||
mock_thread.return_value = MagicMock()
|
||||
_set_pending_restart(['config changed'], ['*'])
|
||||
self.client.post('/api/config/apply')
|
||||
pending = config_manager.configs.get('_pending_restart', {})
|
||||
self.assertFalse(pending.get('needs_restart', False))
|
||||
# The route now marks needs_restart=True + applying=True instead of clearing
|
||||
# immediately. The helper container clears the flag on success; if the helper
|
||||
# fails, needs_restart stays set so the UI continues showing pending changes.
|
||||
self.assertTrue(pending.get('needs_restart', False))
|
||||
self.assertTrue(pending.get('applying', False))
|
||||
|
||||
# ── needs_network_recreate=True → helper script includes 'down' ────────
|
||||
|
||||
|
||||
Reference in New Issue
Block a user