From e090861affc4b143aa8a133274879bc3edf9f960 Mon Sep 17 00:00:00 2001 From: Aldo Ortega Date: Wed, 10 Jul 2024 14:09:36 -0400 Subject: [PATCH 1/5] Moved pop() circuit to after sync() --- main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.py b/main.py index 8e4f4adc..9090fb3f 100755 --- a/main.py +++ b/main.py @@ -425,7 +425,7 @@ def delete_circuit(self, request: Request) -> JSONResponse: circuit_id = request.path_params["circuit_id"] log.debug("delete_circuit /v2/evc/%s", circuit_id) try: - evc = self.circuits.pop(circuit_id) + evc = self.circuits[circuit_id] except KeyError: result = f"circuit_id {circuit_id} not found" log.debug("delete_circuit result %s %s", result, 404) @@ -441,6 +441,7 @@ def delete_circuit(self, request: Request) -> JSONResponse: evc.archive() evc.remove_uni_tags() evc.sync() + self.circuits.pop(circuit_id) log.info("EVC removed. %s", evc) result = {"response": f"Circuit {circuit_id} removed"} status = 200 From 4e38213df9a53b99ae0396997e7d0a5548262ca1 Mon Sep 17 00:00:00 2001 From: Aldo Ortega Date: Thu, 11 Jul 2024 11:58:18 -0400 Subject: [PATCH 2/5] Added lock for EVC deletion --- main.py | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/main.py b/main.py index 9090fb3f..d8ecdeee 100755 --- a/main.py +++ b/main.py @@ -424,24 +424,25 @@ def delete_circuit(self, request: Request) -> JSONResponse: """ circuit_id = request.path_params["circuit_id"] log.debug("delete_circuit /v2/evc/%s", circuit_id) - try: - evc = self.circuits[circuit_id] - except KeyError: - result = f"circuit_id {circuit_id} not found" - log.debug("delete_circuit result %s %s", result, 404) - raise HTTPException(404, detail=result) from KeyError + with self._lock: + try: + evc = self.circuits.pop(circuit_id) + except KeyError: + result = f"circuit_id {circuit_id} not found" + log.debug("delete_circuit result %s %s", result, 404) + raise HTTPException(404, detail=result) from KeyError + + log.info("Removing %s", evc) + with evc.lock: + evc.remove_current_flows() + evc.remove_failover_flows(sync=False) + evc.deactivate() + evc.disable() + self.sched.remove(evc) + evc.archive() + evc.remove_uni_tags() + evc.sync() - log.info("Removing %s", evc) - with evc.lock: - evc.remove_current_flows() - evc.remove_failover_flows(sync=False) - evc.deactivate() - evc.disable() - self.sched.remove(evc) - evc.archive() - evc.remove_uni_tags() - evc.sync() - self.circuits.pop(circuit_id) log.info("EVC removed. %s", evc) result = {"response": f"Circuit {circuit_id} removed"} status = 200 From d5b0a348a7e074ba6a25dfe94b54cd020a97b661 Mon Sep 17 00:00:00 2001 From: Aldo Ortega Date: Fri, 19 Jul 2024 12:08:57 -0400 Subject: [PATCH 3/5] Removed loading process for stored circuits. --- main.py | 21 +++++++++------------ setup.py | 6 ++++-- tests/unit/test_main.py | 13 ++++++------- 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/main.py b/main.py index d8ecdeee..19704a80 100755 --- a/main.py +++ b/main.py @@ -142,9 +142,6 @@ def execute_consistency(self): log.info(f"{circuit} enabled but inactive - redeploy") with circuit.lock: circuit.deploy() - for circuit_id in stored_circuits: - log.info(f"EVC found in mongodb but unloaded {circuit_id}") - self._load_evc(stored_circuits[circuit_id]) def shutdown(self): """Execute when your napp is unloaded. @@ -424,16 +421,16 @@ def delete_circuit(self, request: Request) -> JSONResponse: """ circuit_id = request.path_params["circuit_id"] log.debug("delete_circuit /v2/evc/%s", circuit_id) - with self._lock: - try: - evc = self.circuits.pop(circuit_id) - except KeyError: - result = f"circuit_id {circuit_id} not found" - log.debug("delete_circuit result %s %s", result, 404) - raise HTTPException(404, detail=result) from KeyError + try: + evc = self.circuits.pop(circuit_id) + except KeyError: + result = f"circuit_id {circuit_id} not found" + log.debug("delete_circuit result %s %s", result, 404) + raise HTTPException(404, detail=result) from KeyError + log.info("Removing %s", evc) - log.info("Removing %s", evc) - with evc.lock: + with evc.lock: + if not evc.archived: evc.remove_current_flows() evc.remove_failover_flows(sync=False) evc.deactivate() diff --git a/setup.py b/setup.py index b16e63a6..9d3ca8a7 100644 --- a/setup.py +++ b/setup.py @@ -98,7 +98,8 @@ class Test(TestCommand): def run(self): """Run tests.""" - cmd = f"python3 -m pytest tests/ {self.get_args()}" + cmd = "python3 -m pytest tests/ --cov-report term-missing" + cmd += f" {self.get_args()}" try: check_call(cmd, shell=True) except CalledProcessError as exc: @@ -114,7 +115,8 @@ class TestCoverage(Test): def run(self): """Run tests quietly and display coverage report.""" - cmd = f"python3 -m pytest --cov=. tests/ {self.get_args()}" + cmd = "python3 -m pytest --cov=. tests/ --cov-report term-missing" + cmd += f" {self.get_args()}" try: check_call(cmd, shell=True) except CalledProcessError as exc: diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py index 4a03c19b..7a8136c3 100644 --- a/tests/unit/test_main.py +++ b/tests/unit/test_main.py @@ -106,12 +106,11 @@ def test_execute(self, mock_execute_consistency, mock_log): mock_log.info.assert_not_called() @patch('napps.kytos.mef_eline.main.settings') - @patch('napps.kytos.mef_eline.main.Main._load_evc') @patch("napps.kytos.mef_eline.controllers.ELineController.upsert_evc") @patch("napps.kytos.mef_eline.models.evc.EVCDeploy.check_list_traces") def test_execute_consistency(self, mock_check_list_traces, *args): """Test execute_consistency.""" - (mongo_controller_upsert_mock, mock_load_evc, mock_settings) = args + (mongo_controller_upsert_mock, mock_settings) = args stored_circuits = {'1': {'name': 'circuit_1'}, '2': {'name': 'circuit_2'}, @@ -148,7 +147,6 @@ def test_execute_consistency(self, mock_check_list_traces, *args): assert evc1.activate.call_count == 1 assert evc1.sync.call_count == 1 assert evc2.deploy.call_count == 1 - mock_load_evc.assert_called_with(stored_circuits['3']) @patch('napps.kytos.mef_eline.main.settings') @patch('napps.kytos.mef_eline.main.Main._load_evc') @@ -1776,8 +1774,8 @@ async def test_delete_archived_evc( sched_add_mock, evc_deploy_mock, remove_current_flows_mock, - mock_remove_tags, mock_use_uni, + mock_remove_tags, mock_tags_equal, mock_check_duplicate ): @@ -1787,7 +1785,6 @@ async def test_delete_archived_evc( mongo_controller_upsert_mock.return_value = True sched_add_mock.return_value = True evc_deploy_mock.return_value = True - remove_current_flows_mock.return_value = True mock_use_uni.return_value = True mock_tags_equal.return_value = True mock_check_duplicate.return_value = True @@ -1819,14 +1816,16 @@ async def test_delete_archived_evc( ) assert 201 == response.status_code assert len(self.napp.circuits) == 1 - current_data = response.json() circuit_id = current_data["circuit_id"] + self.napp.circuits[circuit_id].archive() + response = await self.api_client.delete( f"{self.base_endpoint}/v2/evc/{circuit_id}" ) assert 200 == response.status_code - assert mock_remove_tags.call_count == 1 + assert mock_remove_tags.call_count == 0 + assert remove_current_flows_mock.call_count == 0 assert len(self.napp.circuits) == 0 response = await self.api_client.delete( From aba9cb3024bf60e7faeadce0535b6029de5b7e01 Mon Sep 17 00:00:00 2001 From: Aldo Ortega Date: Mon, 22 Jul 2024 09:32:13 -0400 Subject: [PATCH 4/5] Sending one event per EVC --- CHANGELOG.rst | 1 + main.py | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index f5e6fece..8162897e 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -24,6 +24,7 @@ Changed Fixed ===== - Only redeploy when handling ``kytos/topology.link_up`` if a dynamic EVC isn't active +- Fixed possible EVCs duplication when constant delete requests are sent. [2023.2.0] - 2024-02-16 *********************** diff --git a/main.py b/main.py index 19704a80..0395d7e4 100755 --- a/main.py +++ b/main.py @@ -439,14 +439,14 @@ def delete_circuit(self, request: Request) -> JSONResponse: evc.archive() evc.remove_uni_tags() evc.sync() + emit_event(self.controller, "deleted", + content=map_evc_event_content(evc)) log.info("EVC removed. %s", evc) result = {"response": f"Circuit {circuit_id} removed"} status = 200 - log.debug("delete_circuit result %s %s", result, status) - emit_event(self.controller, "deleted", - content=map_evc_event_content(evc)) + return JSONResponse(result, status_code=status) @rest("/v2/evc/{circuit_id}/metadata", methods=["GET"]) From 31bd1e1985f04d9485034a3941eb6513aabb9ba6 Mon Sep 17 00:00:00 2001 From: Aldo Ortega Date: Mon, 22 Jul 2024 09:44:03 -0400 Subject: [PATCH 5/5] Fixed lint --- main.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/main.py b/main.py index 0395d7e4..e30d8baa 100755 --- a/main.py +++ b/main.py @@ -439,8 +439,10 @@ def delete_circuit(self, request: Request) -> JSONResponse: evc.archive() evc.remove_uni_tags() evc.sync() - emit_event(self.controller, "deleted", - content=map_evc_event_content(evc)) + emit_event( + self.controller, "deleted", + content=map_evc_event_content(evc) + ) log.info("EVC removed. %s", evc) result = {"response": f"Circuit {circuit_id} removed"}