From 5eb043b747c8a7808092498b001bdf1b39e705ae Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Thu, 24 Oct 2024 16:08:38 -0400 Subject: [PATCH 1/8] Update success code --- sdx_controller/controllers/l2vpn_controller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdx_controller/controllers/l2vpn_controller.py b/sdx_controller/controllers/l2vpn_controller.py index dfefc9b..3a29c87 100644 --- a/sdx_controller/controllers/l2vpn_controller.py +++ b/sdx_controller/controllers/l2vpn_controller.py @@ -151,7 +151,7 @@ def place_connection(body): response = { "service_id": service_id, - "status": "OK" if code == 200 else "Failure", + "status": "OK" if code == 201 else "Failure", "reason": reason, } @@ -212,7 +212,7 @@ def patch_connection(service_id, body=None): # noqa: E501 ) response = { "service_id": service_id, - "status": "OK" if code == 200 else "Failure", + "status": "OK" if code == 201 else "Failure", "reason": reason, } except Exception as e: From baa1440f6357960d731595ad5703f60928b5870a Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Thu, 24 Oct 2024 17:12:35 -0400 Subject: [PATCH 2/8] Update PCE --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a689bb9..22b22be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,7 +29,7 @@ dependencies = [ "pika >= 1.2.0", "dataset", "pymongo > 3.0", - "sdx-pce @ git+https://github.com/atlanticwave-sdx/pce@3.0.0.dev2", + "sdx-pce @ git+https://github.com/atlanticwave-sdx/pce@3.0.0.dev3", ] [project.optional-dependencies] From f526486340dd5e34961448dd32910658405522ea Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 25 Oct 2024 10:02:12 -0400 Subject: [PATCH 3/8] Update unit tests --- .../controllers/l2vpn_controller.py | 6 +-- sdx_controller/test/test_l2vpn_controller.py | 38 +++++++++---------- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/sdx_controller/controllers/l2vpn_controller.py b/sdx_controller/controllers/l2vpn_controller.py index 3a29c87..541454e 100644 --- a/sdx_controller/controllers/l2vpn_controller.py +++ b/sdx_controller/controllers/l2vpn_controller.py @@ -140,7 +140,7 @@ def place_connection(body): reason, code = connection_handler.place_connection(current_app.te_manager, body) - if code == 200: + if code // 100 == 2: db_instance.add_key_value_pair_to_db( "connections", service_id, json.dumps(body) ) @@ -151,7 +151,7 @@ def place_connection(body): response = { "service_id": service_id, - "status": "OK" if code == 201 else "Failure", + "status": "OK" if code // 100 == 2 else "Failure", "reason": reason, } @@ -163,7 +163,7 @@ def place_connection(body): # response = body # response["id"] = service_id - # response["status"] = "success" if code == 200 else "failure" + # response["status"] = "success" if code == 2xx else "failure" # response["reason"] = reason # `reason` is not present in schema though. return response, code diff --git a/sdx_controller/test/test_l2vpn_controller.py b/sdx_controller/test/test_l2vpn_controller.py index f9f54f9..6c557ec 100644 --- a/sdx_controller/test/test_l2vpn_controller.py +++ b/sdx_controller/test/test_l2vpn_controller.py @@ -69,7 +69,7 @@ def test_delete_connection_with_setup(self): print(f"Response body: {connection_response.data.decode('utf-8')}") - self.assertStatus(connection_response, 200) + assert connection_response // 100 == 2 service_id = connection_response.get_json().get("service_id") print(f"Deleting request_id: {service_id}") @@ -99,7 +99,7 @@ def test_getconnection_by_id(self): # The service_id we've supplied above should not exist. # TODO: test for existing service_id. See # https://github.com/atlanticwave-sdx/sdx-controller/issues/34. - self.assertStatus(response, 404) + assert response // 100 == 4 def test_place_connection_no_topology(self): """ @@ -120,7 +120,7 @@ def test_place_connection_no_topology(self): # Expect 400 failure because the request is incomplete: the # bare minimum connection request we sent does not have # ingress port data, etc., for example. - self.assertStatus(response, 400) + assert response // 100 == 4 def test_place_connection_v2_no_topology(self): """ @@ -141,7 +141,7 @@ def test_place_connection_v2_no_topology(self): # Expect 400 failure because the request is incomplete: the # bare minimum connection request we sent does not have # ingress port data, etc., for example. - self.assertStatus(response, 400) + assert response // 100 == 4 def __test_with_one_topology(self, topology_file): """ @@ -163,7 +163,7 @@ def __test_with_one_topology(self, topology_file): # Expect 400 failure, because TEManager do not have enough # topology data. - self.assertStatus(response, 400) + assert response // 100 == 4 def test_place_connection_with_amlight(self): """ @@ -206,7 +206,7 @@ def test_place_connection_no_id(self): # Expect a 400 response because the required ID field is # missing from the request. - self.assertStatus(response, 400) + assert response // 100 == 4 # JSON response should have a body like: # @@ -218,7 +218,7 @@ def test_place_connection_no_id(self): # } response = response.get_json() - self.assertEqual(response["status"], 400) + assert response["status"] // 100 == 4 self.assertIn("is not valid under any of the given schemas", response["detail"]) def test_place_connection_with_three_topologies(self): @@ -242,7 +242,7 @@ def test_place_connection_with_three_topologies(self): # Expect 200 success because TEManager now should be properly # set up with all the expected topology data. - self.assertStatus(response, 200) + assert response // 100 == 2 def test_place_connection_with_three_topologies_added_in_sequence(self): """ @@ -276,11 +276,11 @@ def test_place_connection_with_three_topologies_added_in_sequence(self): if idx in [0, 1]: # Expect 400 failure because TEManager do not have all # the topologies yet. - self.assertStatus(response, 400) + assert response // 100 == 2 if idx == 200: # Expect 200 success now that TEManager should be set # up with all the expected topology data. - self.assertStatus(response, 200) + assert response // 100 == 2 def test_place_connection_v2_with_three_topologies_400_response(self): """ @@ -313,7 +313,7 @@ def test_place_connection_v2_with_three_topologies_400_response(self): # Expect a 400 response because PCE would not be able to find # a solution for the connection request. - self.assertStatus(response, 400) + assert response // 100 == 4 self.assertEqual( response.get_json().get("status"), "Failure", @@ -327,7 +327,7 @@ def test_place_connection_v2_with_three_topologies_400_response(self): service_id = response.get_json().get("service_id") self.assertNotEqual(service_id, original_request_id) - def test_place_connection_v2_with_three_topologies_200_response(self): + def test_place_connection_v2_with_three_topologies_201_response(self): """ Test case for connection request format v2. This request should be able to find a path. @@ -366,7 +366,7 @@ def test_place_connection_v2_with_three_topologies_200_response(self): # Expect a 200 response because PCE should be able to find a # solution for the connection request. - self.assertStatus(response, 200) + assert response // 100 == 2 self.assertEqual( response.get_json().get("status"), "OK", @@ -414,7 +414,7 @@ def test_place_connection_v2_with_any_vlan_in_request(self): print(f"POST response body is : {response.data.decode('utf-8')}") print(f"POST Response JSON is : {response.get_json()}") - self.assertStatus(response, 200) + assert response // 100 == 2 service_id = response.get_json().get("service_id") @@ -426,7 +426,7 @@ def test_place_connection_v2_with_any_vlan_in_request(self): print(f"GET response body is : {response.data.decode('utf-8')}") print(f"GET response JSON is : {response.get_json()}") - self.assertStatus(response, 200) + assert response // 100 == 2 # Expect a response like this: # @@ -513,7 +513,7 @@ def test_z100_getconnection_by_id_expect_404(self): print(f"Response body is : {response.data.decode('utf-8')}") - self.assertStatus(response, 404) + assert response // 100 == 4 def test_z100_getconnection_by_id_expect_200(self): """ @@ -533,7 +533,7 @@ def test_z100_getconnection_by_id_expect_200(self): print(f"Response body: {post_response.data.decode('utf-8')}") - self.assertStatus(post_response, 200) + assert post_response // 100 == 2 service_id = post_response.get_json().get("service_id") print(f"Got service_id: {service_id}") @@ -546,7 +546,7 @@ def test_z100_getconnection_by_id_expect_200(self): print(f"Response body: {get_response.data.decode('utf-8')}") - self.assertStatus(get_response, 200) + assert get_response // 100 == 2 @patch("sdx_controller.utils.db_utils.DbUtils.get_all_entries_in_collection") def test_z105_getconnections_fail(self, mock_get_all_entries): @@ -566,7 +566,7 @@ def test_z105_getconnections_success(self): ) print(f"Response body is : {response.data.decode('utf-8')}") - self.assertStatus(response, 200) + assert response // 100 == 2 assert len(response.get_json()) != 0 From e45b5e358c76b5fab6652c9ec00f55b43b797004 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 25 Oct 2024 14:15:30 -0400 Subject: [PATCH 4/8] Fix test --- sdx_controller/test/test_l2vpn_controller.py | 37 ++++++++++---------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/sdx_controller/test/test_l2vpn_controller.py b/sdx_controller/test/test_l2vpn_controller.py index 6c557ec..9c4bc7f 100644 --- a/sdx_controller/test/test_l2vpn_controller.py +++ b/sdx_controller/test/test_l2vpn_controller.py @@ -69,7 +69,7 @@ def test_delete_connection_with_setup(self): print(f"Response body: {connection_response.data.decode('utf-8')}") - assert connection_response // 100 == 2 + assert connection_response.status_code // 100 == 2 service_id = connection_response.get_json().get("service_id") print(f"Deleting request_id: {service_id}") @@ -99,7 +99,7 @@ def test_getconnection_by_id(self): # The service_id we've supplied above should not exist. # TODO: test for existing service_id. See # https://github.com/atlanticwave-sdx/sdx-controller/issues/34. - assert response // 100 == 4 + assert response.status_code // 100 == 4 def test_place_connection_no_topology(self): """ @@ -120,7 +120,7 @@ def test_place_connection_no_topology(self): # Expect 400 failure because the request is incomplete: the # bare minimum connection request we sent does not have # ingress port data, etc., for example. - assert response // 100 == 4 + assert response.status_code // 100 == 4 def test_place_connection_v2_no_topology(self): """ @@ -141,7 +141,7 @@ def test_place_connection_v2_no_topology(self): # Expect 400 failure because the request is incomplete: the # bare minimum connection request we sent does not have # ingress port data, etc., for example. - assert response // 100 == 4 + assert response.status_code // 100 == 4 def __test_with_one_topology(self, topology_file): """ @@ -163,7 +163,7 @@ def __test_with_one_topology(self, topology_file): # Expect 400 failure, because TEManager do not have enough # topology data. - assert response // 100 == 4 + assert response.status_code // 100 == 4 def test_place_connection_with_amlight(self): """ @@ -206,7 +206,7 @@ def test_place_connection_no_id(self): # Expect a 400 response because the required ID field is # missing from the request. - assert response // 100 == 4 + assert response.status_code // 100 == 4 # JSON response should have a body like: # @@ -218,7 +218,6 @@ def test_place_connection_no_id(self): # } response = response.get_json() - assert response["status"] // 100 == 4 self.assertIn("is not valid under any of the given schemas", response["detail"]) def test_place_connection_with_three_topologies(self): @@ -242,7 +241,7 @@ def test_place_connection_with_three_topologies(self): # Expect 200 success because TEManager now should be properly # set up with all the expected topology data. - assert response // 100 == 2 + assert response.status_code // 100 == 2 def test_place_connection_with_three_topologies_added_in_sequence(self): """ @@ -276,11 +275,11 @@ def test_place_connection_with_three_topologies_added_in_sequence(self): if idx in [0, 1]: # Expect 400 failure because TEManager do not have all # the topologies yet. - assert response // 100 == 2 + assert response.status_code // 100 == 2 if idx == 200: # Expect 200 success now that TEManager should be set # up with all the expected topology data. - assert response // 100 == 2 + assert response.status_code // 100 == 2 def test_place_connection_v2_with_three_topologies_400_response(self): """ @@ -313,7 +312,7 @@ def test_place_connection_v2_with_three_topologies_400_response(self): # Expect a 400 response because PCE would not be able to find # a solution for the connection request. - assert response // 100 == 4 + assert response.status_code // 100 == 4 self.assertEqual( response.get_json().get("status"), "Failure", @@ -366,7 +365,7 @@ def test_place_connection_v2_with_three_topologies_201_response(self): # Expect a 200 response because PCE should be able to find a # solution for the connection request. - assert response // 100 == 2 + assert response.status_code // 100 == 2 self.assertEqual( response.get_json().get("status"), "OK", @@ -414,7 +413,7 @@ def test_place_connection_v2_with_any_vlan_in_request(self): print(f"POST response body is : {response.data.decode('utf-8')}") print(f"POST Response JSON is : {response.get_json()}") - assert response // 100 == 2 + assert response.status_code // 100 == 2 service_id = response.get_json().get("service_id") @@ -426,7 +425,7 @@ def test_place_connection_v2_with_any_vlan_in_request(self): print(f"GET response body is : {response.data.decode('utf-8')}") print(f"GET response JSON is : {response.get_json()}") - assert response // 100 == 2 + assert response.status_code // 100 == 2 # Expect a response like this: # @@ -513,7 +512,7 @@ def test_z100_getconnection_by_id_expect_404(self): print(f"Response body is : {response.data.decode('utf-8')}") - assert response // 100 == 4 + assert response.status_code // 100 == 4 def test_z100_getconnection_by_id_expect_200(self): """ @@ -533,7 +532,7 @@ def test_z100_getconnection_by_id_expect_200(self): print(f"Response body: {post_response.data.decode('utf-8')}") - assert post_response // 100 == 2 + assert post_response.status_code // 100 == 2 service_id = post_response.get_json().get("service_id") print(f"Got service_id: {service_id}") @@ -546,7 +545,7 @@ def test_z100_getconnection_by_id_expect_200(self): print(f"Response body: {get_response.data.decode('utf-8')}") - assert get_response // 100 == 2 + assert get_response.status_code // 100 == 2 @patch("sdx_controller.utils.db_utils.DbUtils.get_all_entries_in_collection") def test_z105_getconnections_fail(self, mock_get_all_entries): @@ -556,7 +555,7 @@ def test_z105_getconnections_fail(self, mock_get_all_entries): f"{BASE_PATH}/l2vpn/1.0", method="GET", ) - self.assertStatus(response, 404) + assert response.status_code // 100 == 4 def test_z105_getconnections_success(self): """Test case for getconnections.""" @@ -566,7 +565,7 @@ def test_z105_getconnections_success(self): ) print(f"Response body is : {response.data.decode('utf-8')}") - assert response // 100 == 2 + assert response.status_code // 100 == 2 assert len(response.get_json()) != 0 From d4b6a4e6f4ac86d111f3cfe1b522974db0901e36 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 25 Oct 2024 14:18:56 -0400 Subject: [PATCH 5/8] More fix --- sdx_controller/controllers/l2vpn_controller.py | 4 ++-- sdx_controller/test/test_l2vpn_controller.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sdx_controller/controllers/l2vpn_controller.py b/sdx_controller/controllers/l2vpn_controller.py index 541454e..b42d719 100644 --- a/sdx_controller/controllers/l2vpn_controller.py +++ b/sdx_controller/controllers/l2vpn_controller.py @@ -203,7 +203,7 @@ def patch_connection(service_id, body=None): # noqa: E501 f"Placing new connection {service_id} with te_manager: {current_app.te_manager}" ) reason, code = connection_handler.place_connection(current_app.te_manager, body) - if code == 200: + if code // 100 == 2: db_instance.add_key_value_pair_to_db( "connections", service_id, json.dumps(body) ) @@ -212,7 +212,7 @@ def patch_connection(service_id, body=None): # noqa: E501 ) response = { "service_id": service_id, - "status": "OK" if code == 201 else "Failure", + "status": "OK" if code // 100 == 2 else "Failure", "reason": reason, } except Exception as e: diff --git a/sdx_controller/test/test_l2vpn_controller.py b/sdx_controller/test/test_l2vpn_controller.py index 9c4bc7f..590483d 100644 --- a/sdx_controller/test/test_l2vpn_controller.py +++ b/sdx_controller/test/test_l2vpn_controller.py @@ -275,7 +275,7 @@ def test_place_connection_with_three_topologies_added_in_sequence(self): if idx in [0, 1]: # Expect 400 failure because TEManager do not have all # the topologies yet. - assert response.status_code // 100 == 2 + assert response.status_code // 100 == 4 if idx == 200: # Expect 200 success now that TEManager should be set # up with all the expected topology data. From a4bca1cc4b3ecbaebd1d93dc2ad6c0a6152d052c Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 25 Oct 2024 15:53:48 -0400 Subject: [PATCH 6/8] Update pce error handling --- sdx_controller/handlers/connection_handler.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/sdx_controller/handlers/connection_handler.py b/sdx_controller/handlers/connection_handler.py index e2a8e00..034bc1a 100644 --- a/sdx_controller/handlers/connection_handler.py +++ b/sdx_controller/handlers/connection_handler.py @@ -6,6 +6,7 @@ from sdx_pce.load_balancing.te_solver import TESolver from sdx_pce.topology.temanager import TEManager +from sdx_pce.utils.exceptions import TEError from sdx_controller.messaging.topic_queue_producer import TopicQueueProducer from sdx_controller.models.simple_link import SimpleLink @@ -143,7 +144,7 @@ def place_connection( connection_request=connection_request ) if traffic_matrix is None: - return "Could not generate a traffic matrix", 400 + return "Could not generate a traffic matrix", 402 logger.info(f"Generated graph: '{graph}', traffic matrix: '{traffic_matrix}'") @@ -152,7 +153,7 @@ def place_connection( logger.debug(f"TESolver result: {solution}") if solution is None or solution.connection_map is None: - return "Could not solve the request", 400 + return "Could not solve the request", 410 try: breakdown = te_manager.generate_connection_breakdown( @@ -166,6 +167,8 @@ def place_connection( ) logger.debug(f"Breakdown sent to LC, status: {status}, code: {code}") return status, code + except TEError as te_err: + return te_err except Exception as e: err = traceback.format_exc().replace("\n", ", ") logger.error(f"Error when generating/publishing breakdown: {e} - {err}") From 0ff347eed7e102b794564e404d9b09d81f58accb Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 25 Oct 2024 16:19:10 -0400 Subject: [PATCH 7/8] Use 201 --- sdx_controller/controllers/l2vpn_controller.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/sdx_controller/controllers/l2vpn_controller.py b/sdx_controller/controllers/l2vpn_controller.py index b42d719..b042047 100644 --- a/sdx_controller/controllers/l2vpn_controller.py +++ b/sdx_controller/controllers/l2vpn_controller.py @@ -144,6 +144,8 @@ def place_connection(body): db_instance.add_key_value_pair_to_db( "connections", service_id, json.dumps(body) ) + # Service created successfully + code = 201 logger.info( f"place_connection result: ID: {service_id} reason='{reason}', code={code}" @@ -207,6 +209,7 @@ def patch_connection(service_id, body=None): # noqa: E501 db_instance.add_key_value_pair_to_db( "connections", service_id, json.dumps(body) ) + code = 201 logger.info( f"place_connection result: ID: {service_id} reason='{reason}', code={code}" ) From 4af5b7926a6209d860aa5a26959881ee9de73556 Mon Sep 17 00:00:00 2001 From: Cong Wang Date: Fri, 25 Oct 2024 16:20:05 -0400 Subject: [PATCH 8/8] Add a comment --- sdx_controller/controllers/l2vpn_controller.py | 1 + 1 file changed, 1 insertion(+) diff --git a/sdx_controller/controllers/l2vpn_controller.py b/sdx_controller/controllers/l2vpn_controller.py index b042047..9a11e52 100644 --- a/sdx_controller/controllers/l2vpn_controller.py +++ b/sdx_controller/controllers/l2vpn_controller.py @@ -209,6 +209,7 @@ def patch_connection(service_id, body=None): # noqa: E501 db_instance.add_key_value_pair_to_db( "connections", service_id, json.dumps(body) ) + # Service created successfully code = 201 logger.info( f"place_connection result: ID: {service_id} reason='{reason}', code={code}"