From a41391edfcb5dea9036f742a2a24313004551903 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Tue, 23 Jan 2024 14:19:01 -0600 Subject: [PATCH 01/42] Update a comment --- swagger_server/test/test_connection_controller.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/swagger_server/test/test_connection_controller.py b/swagger_server/test/test_connection_controller.py index 8606a2a4..a094e399 100644 --- a/swagger_server/test/test_connection_controller.py +++ b/swagger_server/test/test_connection_controller.py @@ -39,12 +39,11 @@ def test_getconnection_by_id(self): # https://github.com/atlanticwave-sdx/sdx-controller/issues/34. self.assertStatus(response, 204) - def test_place_connection(self): + def test_place_connection_no_topology(self): """ Test case for place_connection. - Place an connection request from the SDX-Controller without - sufficient . + Place a connection request with no topology present. """ body = Connection() response = self.client.open( From 271023f9983e8f0cb25dfad0c25b2d9f8469a7d4 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Tue, 23 Jan 2024 14:48:23 -0600 Subject: [PATCH 02/42] Pull up a common path --- swagger_server/test/test_connection_controller.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/swagger_server/test/test_connection_controller.py b/swagger_server/test/test_connection_controller.py index a094e399..de0579a5 100644 --- a/swagger_server/test/test_connection_controller.py +++ b/swagger_server/test/test_connection_controller.py @@ -9,6 +9,8 @@ from swagger_server.models.connection import Connection # noqa: E501 from swagger_server.test import BaseTestCase +BASE_PATH = "/SDX-Controller/1.0.0" + class TestConnectionController(BaseTestCase): """ConnectionController integration test stubs""" @@ -18,19 +20,21 @@ def test_delete_connection(self): Delete connection order by ID """ + connection_id = 2 response = self.client.open( - "/SDX-Controller/1.0.0/connection/{connection_id}".format(connection_id=2), + f"{BASE_PATH}/connection/{connection_id}", method="DELETE", ) - self.assert200(response, "Response body is : " + response.data.decode("utf-8")) + self.assert200(response, f"Response body is : {response.data.decode('utf-8')}") def test_getconnection_by_id(self): """Test case for getconnection_by_id Find connection by ID """ + connection_id = 10 response = self.client.open( - "/SDX-Controller/1.0.0/connection/{connection_id}".format(connection_id=10), + f"{BASE_PATH}/connection/{connection_id}", method="GET", ) @@ -47,7 +51,7 @@ def test_place_connection_no_topology(self): """ body = Connection() response = self.client.open( - "/SDX-Controller/1.0.0/connection", + f"{BASE_PATH}/connection", method="POST", data=json.dumps(body), content_type="application/json", From cee55f2c8698a2f7d6c197f2b96a278993ff0a43 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Tue, 23 Jan 2024 14:48:45 -0600 Subject: [PATCH 03/42] Format comments --- swagger_server/test/test_connection_controller.py | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/swagger_server/test/test_connection_controller.py b/swagger_server/test/test_connection_controller.py index de0579a5..eab1b798 100644 --- a/swagger_server/test/test_connection_controller.py +++ b/swagger_server/test/test_connection_controller.py @@ -16,9 +16,10 @@ class TestConnectionController(BaseTestCase): """ConnectionController integration test stubs""" def test_delete_connection(self): - """Test case for delete_connection + """ + Test case for delete_connection. - Delete connection order by ID + Delete connection order by ID. """ connection_id = 2 response = self.client.open( @@ -28,9 +29,10 @@ def test_delete_connection(self): self.assert200(response, f"Response body is : {response.data.decode('utf-8')}") def test_getconnection_by_id(self): - """Test case for getconnection_by_id + """ + Test case for getconnection_by_id. - Find connection by ID + Find connection by ID. """ connection_id = 10 response = self.client.open( @@ -50,6 +52,7 @@ def test_place_connection_no_topology(self): Place a connection request with no topology present. """ body = Connection() + response = self.client.open( f"{BASE_PATH}/connection", method="POST", From 2a9d1440b471e3ab1a6461eabac00c5c5e448b78 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Tue, 23 Jan 2024 18:27:45 -0600 Subject: [PATCH 04/42] Refactor out a create_app() --- swagger_server/__main__.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/swagger_server/__main__.py b/swagger_server/__main__.py index a2c256ce..9b16780f 100644 --- a/swagger_server/__main__.py +++ b/swagger_server/__main__.py @@ -17,18 +17,25 @@ LOG_FILE = os.environ.get("LOG_FILE") +def create_app(): + """ + Create a connexion app. + """ + app = connexion.App(__name__, specification_dir="./swagger/") + app.app.json_encoder = encoder.JSONEncoder + app.add_api( + "swagger.yaml", arguments={"title": "SDX-Controller"}, pythonic_params=True + ) + return app + + def main(): if LOG_FILE: logging.basicConfig(filename=LOG_FILE, level=logging.INFO) else: logging.basicConfig(level=logging.DEBUG) - # Run swagger service - app = connexion.App(__name__, specification_dir="./swagger/") - app.app.json_encoder = encoder.JSONEncoder - app.add_api( - "swagger.yaml", arguments={"title": "SDX-Controller"}, pythonic_params=True - ) + app = create_app() # Run swagger in a thread threading.Thread(target=lambda: app.run(port=8080)).start() From ab467cc4212bd16597e1c66f6f0ebbe6a757069e Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Tue, 23 Jan 2024 18:29:31 -0600 Subject: [PATCH 05/42] Use the common create_app() --- swagger_server/test/__init__.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/swagger_server/test/__init__.py b/swagger_server/test/__init__.py index c44f774f..8076c16f 100644 --- a/swagger_server/test/__init__.py +++ b/swagger_server/test/__init__.py @@ -4,12 +4,13 @@ from flask_testing import TestCase from swagger_server.encoder import JSONEncoder +from swagger_server.__main__ import create_app class BaseTestCase(TestCase): def create_app(self): logging.getLogger("connexion.operation").setLevel("ERROR") - app = connexion.App(__name__, specification_dir="../swagger/") - app.app.json_encoder = JSONEncoder - app.add_api("swagger.yaml") + + app = create_app() + return app.app From 5a8c5e78f249f24a3a1615b01b316c46788cc749 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Thu, 25 Jan 2024 09:58:11 -0600 Subject: [PATCH 06/42] Use TEManager, not TopologyManager --- swagger_server/__main__.py | 9 +++++---- swagger_server/handlers/lc_message_handler.py | 14 +++++++++----- swagger_server/messaging/rpc_queue_consumer.py | 11 ++++++----- 3 files changed, 20 insertions(+), 14 deletions(-) diff --git a/swagger_server/__main__.py b/swagger_server/__main__.py index 9b16780f..7d26c07a 100644 --- a/swagger_server/__main__.py +++ b/swagger_server/__main__.py @@ -6,7 +6,7 @@ from queue import Queue import connexion -from sdx_pce.topology.manager import TopologyManager +from sdx_pce.topology.temanager import TEManager from swagger_server import encoder from swagger_server.messaging.rpc_queue_consumer import RpcConsumer @@ -26,6 +26,9 @@ def create_app(): app.add_api( "swagger.yaml", arguments={"title": "SDX-Controller"}, pythonic_params=True ) + + app.te_manager = TEManager(topology_data=None) + return app @@ -44,10 +47,8 @@ def main(): db_instance = DbUtils() db_instance.initialize_db() - topology_manager = TopologyManager() - thread_queue = Queue() - rpc = RpcConsumer(thread_queue, "", topology_manager) + rpc = RpcConsumer(thread_queue, "", app.te_manager) rpc.start_sdx_consumer(thread_queue, db_instance) diff --git a/swagger_server/handlers/lc_message_handler.py b/swagger_server/handlers/lc_message_handler.py index 09b17393..530ff01b 100644 --- a/swagger_server/handlers/lc_message_handler.py +++ b/swagger_server/handlers/lc_message_handler.py @@ -8,9 +8,9 @@ class LcMessageHandler: - def __init__(self, db_instance, manager): + def __init__(self, db_instance, te_manager): self.db_instance = db_instance - self.manager = manager + self.te_manager = te_manager self.parse_helper = ParseHelper() self.connection_handler = ConnectionHandler(db_instance) @@ -43,7 +43,7 @@ def process_lc_json_msg( if domain_name in domain_list: logger.info("Updating topo") logger.debug(msg_json) - self.manager.update_topology(msg_json) + self.te_manager.update_topology(msg_json) if "link_failure" in msg_json: logger.info("Processing link failure.") self.connection_handler.handle_link_failure(msg_json) @@ -53,7 +53,7 @@ def process_lc_json_msg( self.db_instance.add_key_value_pair_to_db("domain_list", domain_list) logger.info("Adding topo") - self.manager.add_topology(msg_json) + self.te_manager.add_topology(msg_json) if self.db_instance.read_from_db("num_domain_topos") is None: num_domain_topos = 1 @@ -71,7 +71,11 @@ def process_lc_json_msg( db_key = "LC-" + str(num_domain_topos) self.db_instance.add_key_value_pair_to_db(db_key, json.dumps(msg_json)) - latest_topo = json.dumps(self.manager.get_topology().to_dict()) + # TODO: use TEManager API directly; but TEManager does not + # expose a `get_topology()` method yet. + latest_topo = json.dumps( + self.te_manager.topology_manager.get_topology().to_dict() + ) # use 'latest_topo' as PK to save latest topo to db self.db_instance.add_key_value_pair_to_db("latest_topo", latest_topo) logger.info("Save to database complete.") diff --git a/swagger_server/messaging/rpc_queue_consumer.py b/swagger_server/messaging/rpc_queue_consumer.py index 1128a695..af05f4c1 100644 --- a/swagger_server/messaging/rpc_queue_consumer.py +++ b/swagger_server/messaging/rpc_queue_consumer.py @@ -18,7 +18,7 @@ class RpcConsumer(object): - def __init__(self, thread_queue, exchange_name, topology_manager): + def __init__(self, thread_queue, exchange_name, te_manager): self.logger = logging.getLogger(__name__) self.connection = pika.BlockingConnection( pika.ConnectionParameters(host=MQ_HOST) @@ -30,7 +30,7 @@ def __init__(self, thread_queue, exchange_name, topology_manager): self.channel.queue_declare(queue=SUB_QUEUE) self._thread_queue = thread_queue - self.manager = topology_manager + self.te_manager = te_manager def on_request(self, ch, method, props, message_body): response = message_body @@ -59,11 +59,12 @@ def start_consumer(self): def start_sdx_consumer(self, thread_queue, db_instance): MESSAGE_ID = 0 HEARTBEAT_ID = 0 - rpc = RpcConsumer(thread_queue, "", self.manager) + + rpc = RpcConsumer(thread_queue, "", self.te_manager) t1 = threading.Thread(target=rpc.start_consumer, args=()) t1.start() - lc_message_handler = LcMessageHandler(db_instance, self.manager) + lc_message_handler = LcMessageHandler(db_instance, self.te_manager) parse_helper = ParseHelper() latest_topo = {} @@ -101,7 +102,7 @@ def start_sdx_consumer(self, thread_queue, db_instance): # Get the actual thing minus the Mongo ObjectID. topology = topology[db_key] topo_json = json.loads(topology) - self.manager.add_topology(topo_json) + self.te_manager.add_topology(topo_json) logger.debug(f"Read {db_key}: {topology}") while True: From 2cc5323e21d43a63177dbfd0869b13c5f3ee52b8 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Thu, 25 Jan 2024 11:58:25 -0600 Subject: [PATCH 07/42] Save a handle to TEManager in test cases --- swagger_server/test/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/swagger_server/test/__init__.py b/swagger_server/test/__init__.py index 8076c16f..550d613a 100644 --- a/swagger_server/test/__init__.py +++ b/swagger_server/test/__init__.py @@ -13,4 +13,8 @@ def create_app(self): app = create_app() + # TODO: we need a handle to TEManager in tests, so we will use + # this. There must be a better way to accesss this though. + self.te_manager = app.te_manager + return app.app From 521f94a8d991a50a1f7f4ea0fc674ea441752cc2 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Thu, 25 Jan 2024 13:10:51 -0600 Subject: [PATCH 08/42] Test place_connection() with mock topologies also This does not work as it should yet because place_connection() sets up its own TEManager instance with topologies populated from the DB. --- swagger_server/test/__init__.py | 19 +++++++++++- .../test/test_connection_controller.py | 31 ++++++++++++++++++- 2 files changed, 48 insertions(+), 2 deletions(-) diff --git a/swagger_server/test/__init__.py b/swagger_server/test/__init__.py index 550d613a..3b1c8d0a 100644 --- a/swagger_server/test/__init__.py +++ b/swagger_server/test/__init__.py @@ -3,8 +3,15 @@ import connexion from flask_testing import TestCase -from swagger_server.encoder import JSONEncoder from swagger_server.__main__ import create_app +from swagger_server.encoder import JSONEncoder + +try: + # Use stdlib modules with Python > 3.8. + from importlib.resources import files +except ImportError: + # Use compatibility library with Python 3.8. + from importlib_resources import files class BaseTestCase(TestCase): @@ -18,3 +25,13 @@ def create_app(self): self.te_manager = app.te_manager return app.app + + +class TestData: + TOPOLOGY_DIR = files("sdx_datamodel") / "data" / "topologies" + TOPOLOGY_FILE_ZAOXI = TOPOLOGY_DIR / "zaoxi.json" + TOPOLOGY_FILE_SAX = TOPOLOGY_DIR / "sax.json" + TOPOLOGY_FILE_AMLIGHT = TOPOLOGY_DIR / "amlight.json" + + REQUESTS_DIR = files("sdx_datamodel") / "data" / "requests" + CONNECTION_REQ = REQUESTS_DIR / "test_request.json" diff --git a/swagger_server/test/test_connection_controller.py b/swagger_server/test/test_connection_controller.py index eab1b798..a167a30f 100644 --- a/swagger_server/test/test_connection_controller.py +++ b/swagger_server/test/test_connection_controller.py @@ -7,7 +7,7 @@ from flask import json from swagger_server.models.connection import Connection # noqa: E501 -from swagger_server.test import BaseTestCase +from swagger_server.test import BaseTestCase, TestData BASE_PATH = "/SDX-Controller/1.0.0" @@ -66,6 +66,35 @@ def test_place_connection_no_topology(self): # ingress port data, etc., for example. self.assertStatus(response, 400) + def test_place_connection_with_three_topologies(self): + """ + Test case for place_connection. + + Place a connection request when some topologies are known. + """ + for topology_file in [ + TestData.TOPOLOGY_FILE_AMLIGHT, + TestData.TOPOLOGY_FILE_SAX, + TestData.TOPOLOGY_FILE_ZAOXI, + ]: + topology = json.loads(topology_file.read_text()) + self.te_manager.add_topology(topology) + + request = json.loads(TestData.CONNECTION_REQ.read_text()) + + response = self.client.open( + f"{BASE_PATH}/connection", + method="POST", + data=json.dumps(request), + content_type="application/json", + ) + + print(f"Response body is : {response.data.decode('utf-8')}") + + # Expect 400 failure for now because TEManager is not properly + # set up within the handler yet. + self.assertStatus(response, 400) + if __name__ == "__main__": unittest.main() From e0c86fd277c2398fb4791a3bf86ace1d3698feeb Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Tue, 30 Jan 2024 13:45:20 -0600 Subject: [PATCH 09/42] Add TestData back This was removed on merging because swagger_server/test/__init__.py was gone. --- sdx_controller/test/__init__.py | 17 +++++++++++++++++ .../test/test_connection_controller.py | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/sdx_controller/test/__init__.py b/sdx_controller/test/__init__.py index b5efdd65..4303f0c9 100644 --- a/sdx_controller/test/__init__.py +++ b/sdx_controller/test/__init__.py @@ -4,6 +4,13 @@ import connexion from flask_testing import TestCase +try: + # Use stdlib modules with Python > 3.8. + from importlib.resources import files +except ImportError: + # Use compatibility library with Python 3.8. + from importlib_resources import files + from sdx_controller import create_app @@ -16,3 +23,13 @@ def create_app(self): # doesn't use a message queue right now. app = create_app(run_listener=True if os.getenv("MQ_HOST") else False) return app.app + + +class TestData: + TOPOLOGY_DIR = files("sdx_datamodel") / "data" / "topologies" + TOPOLOGY_FILE_ZAOXI = TOPOLOGY_DIR / "zaoxi.json" + TOPOLOGY_FILE_SAX = TOPOLOGY_DIR / "sax.json" + TOPOLOGY_FILE_AMLIGHT = TOPOLOGY_DIR / "amlight.json" + + REQUESTS_DIR = files("sdx_datamodel") / "data" / "requests" + CONNECTION_REQ = REQUESTS_DIR / "test_request.json" diff --git a/sdx_controller/test/test_connection_controller.py b/sdx_controller/test/test_connection_controller.py index 9777b0a7..f3412663 100644 --- a/sdx_controller/test/test_connection_controller.py +++ b/sdx_controller/test/test_connection_controller.py @@ -7,7 +7,7 @@ from flask import json from sdx_controller.models.connection import Connection # noqa: E501 -from sdx_controller.test import BaseTestCase +from sdx_controller.test import BaseTestCase, TestData BASE_PATH = "/SDX-Controller/1.0.0" From 1e2fdb21917c583156901b759d157175173b9d31 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Tue, 30 Jan 2024 13:52:36 -0600 Subject: [PATCH 10/42] Set up a handle to TEManager during app creation --- sdx_controller/__init__.py | 8 +++++--- sdx_controller/test/__init__.py | 6 ++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/sdx_controller/__init__.py b/sdx_controller/__init__.py index 3e89c09b..79844fcc 100644 --- a/sdx_controller/__init__.py +++ b/sdx_controller/__init__.py @@ -4,7 +4,7 @@ from queue import Queue import connexion -from sdx_pce.topology.manager import TopologyManager +from sdx_pce.topology.temanager import TEManager from sdx_controller import encoder from sdx_controller.messaging.rpc_queue_consumer import RpcConsumer @@ -19,10 +19,9 @@ def create_rpc_thread(app): """ Start a thread to get items off the message queue. """ - topology_manager = TopologyManager() thread_queue = Queue() - app.rpc_consumer = RpcConsumer(thread_queue, "", topology_manager) + app.rpc_consumer = RpcConsumer(thread_queue, "", app.te_manager) rpc_thread = threading.Thread( target=app.rpc_consumer.start_sdx_consumer, kwargs={"thread_queue": thread_queue, "db_instance": app.db_instance}, @@ -64,6 +63,9 @@ def create_app(run_listener: bool = True): app.db_instance = DbUtils() app.db_instance.initialize_db() + # Get a handle to PCE. + app.te_manager = TEManager(topology_data=None) + if run_listener: create_rpc_thread(app) diff --git a/sdx_controller/test/__init__.py b/sdx_controller/test/__init__.py index 4303f0c9..75fe48c6 100644 --- a/sdx_controller/test/__init__.py +++ b/sdx_controller/test/__init__.py @@ -22,6 +22,12 @@ def create_app(self): # RabbitMQ insteance just for testing, since the test suite # doesn't use a message queue right now. app = create_app(run_listener=True if os.getenv("MQ_HOST") else False) + + # We need a handle to the TEManager instance in tests, but + # accessing it this way feels like a work-around. There must + # be a better way to get a handle to TEManager. + self.te_manager = app.te_manager + return app.app From 7a550b39d6b7cabcb86ed30953489d1d7e33f26d Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Tue, 30 Jan 2024 16:23:47 -0600 Subject: [PATCH 11/42] Remove unused functions --- .../controllers/connection_controller.py | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/sdx_controller/controllers/connection_controller.py b/sdx_controller/controllers/connection_controller.py index 5b49acbe..f6c2de62 100644 --- a/sdx_controller/controllers/connection_controller.py +++ b/sdx_controller/controllers/connection_controller.py @@ -20,29 +20,6 @@ connection_handler = ConnectionHandler(db_instance) -def is_json(myjson): - try: - json.loads(myjson) - except ValueError: - return False - return True - - -def find_between(s, first, last): - """ - Find the substring of `s` that is betwen `first` and `last`. - """ - if s is None or first is None or last is None: - return None - - try: - start = s.index(first) + len(first) - end = s.index(last, start) - return s[start:end] - except ValueError: - return "" - - def delete_connection(connection_id): """ Delete connection order by ID. From f74facc175c27f9affa2bb602b51457ee1e19ea0 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:28:44 -0600 Subject: [PATCH 12/42] Add a workaround to get a handle to TEManager --- sdx_controller/__init__.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sdx_controller/__init__.py b/sdx_controller/__init__.py index 79844fcc..580def8e 100644 --- a/sdx_controller/__init__.py +++ b/sdx_controller/__init__.py @@ -66,6 +66,12 @@ def create_app(run_listener: bool = True): # Get a handle to PCE. app.te_manager = TEManager(topology_data=None) + # TODO: This is a hack, until we find a better way to get a handle + # to TEManager from Flask current_app, which are typically + # available to request handlers. There must be a better way to + # pass this around. + app.app.te_manager = app.te_manager + if run_listener: create_rpc_thread(app) From 55665ca96bcd92de2be2a6d45970805f8bd1f17e Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:30:35 -0600 Subject: [PATCH 13/42] Use the "global" TEManager in place_connection() --- sdx_controller/controllers/connection_controller.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sdx_controller/controllers/connection_controller.py b/sdx_controller/controllers/connection_controller.py index f6c2de62..90500898 100644 --- a/sdx_controller/controllers/connection_controller.py +++ b/sdx_controller/controllers/connection_controller.py @@ -3,6 +3,8 @@ import connexion +from flask import current_app + from sdx_controller.handlers.connection_handler import ConnectionHandler from sdx_controller.utils.db_utils import DbUtils @@ -64,7 +66,9 @@ def place_connection(body): db_instance.add_key_value_pair_to_db("connection_data", json.dumps(body)) logger.info("Saving to database complete.") - reason, code = connection_handler.place_connection(body) + logger.info(f"Handling request with te_manager: {current_app.te_manager}") + + reason, code = connection_handler.place_connection(current_app.te_manager, body) logger.info(f"place_connection result: reason='{reason}', code={code}") return reason, code From 66c0d09de56b3e9d4c273686cc427dec7f6890e0 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:32:25 -0600 Subject: [PATCH 14/42] Use "global" TEManager in place_connection() --- sdx_controller/handlers/connection_handler.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdx_controller/handlers/connection_handler.py b/sdx_controller/handlers/connection_handler.py index 0c272cb7..17c54d52 100644 --- a/sdx_controller/handlers/connection_handler.py +++ b/sdx_controller/handlers/connection_handler.py @@ -85,7 +85,9 @@ def _send_breakdown_to_lc(self, breakdown, connection_request): # leading up to this point were successful. return "Connection published", 200 - def place_connection(self, connection_request: dict) -> Tuple[str, int]: + def place_connection( + self, temanager: TEManager, connection_request: dict + ) -> Tuple[str, int]: """ Do the actual work of creating a connection. From 22825eb7ce56ad66878becb7e6e3d97e185fee7a Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:33:02 -0600 Subject: [PATCH 15/42] Return success status and code from place_connection() --- sdx_controller/handlers/connection_handler.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdx_controller/handlers/connection_handler.py b/sdx_controller/handlers/connection_handler.py index 17c54d52..3a64d64a 100644 --- a/sdx_controller/handlers/connection_handler.py +++ b/sdx_controller/handlers/connection_handler.py @@ -160,6 +160,8 @@ def place_connection( breakdown = temanager.generate_connection_breakdown(solution) self._send_breakdown_to_lc(breakdown, connection_request) + return "OK", 200 + def handle_link_failure(self, msg_json): logger.debug("---Handling connections that contain failed link.---") link_connections_dict_str = self.db_instance.read_from_db( From 0e739679bad4d83b94b0ea05e675157c3fb8027b Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:34:26 -0600 Subject: [PATCH 16/42] Just comment out the extra TEManager setup, for now To be removed later --- sdx_controller/handlers/connection_handler.py | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/sdx_controller/handlers/connection_handler.py b/sdx_controller/handlers/connection_handler.py index 3a64d64a..f0631124 100644 --- a/sdx_controller/handlers/connection_handler.py +++ b/sdx_controller/handlers/connection_handler.py @@ -100,40 +100,40 @@ def place_connection( """ num_domain_topos = 0 - if self.db_instance.read_from_db("num_domain_topos"): - num_domain_topos = self.db_instance.read_from_db("num_domain_topos")[ - "num_domain_topos" - ] - - # Initializing TEManager with `None` topology data is a - # work-around for - # https://github.com/atlanticwave-sdx/sdx-controller/issues/145 - temanager = TEManager(topology_data=None) - lc_domain_topo_dict = {} - - # Read LC-1, LC-2, LC-3, and LC-4 topologies because of - # https://github.com/atlanticwave-sdx/sdx-controller/issues/152 - for i in range(1, int(num_domain_topos) + 2): - lc = f"LC-{i}" - logger.debug(f"Reading {lc} from DB") - curr_topo = self.db_instance.read_from_db(lc) - if curr_topo is None: - logger.debug(f"Read {lc} from DB: {curr_topo}") - continue - else: - # Get the actual thing minus the Mongo ObjectID. - curr_topo_str = curr_topo.get(lc) - # Just log a substring, not the whole thing. - logger.debug(f"Read {lc} from DB: {curr_topo_str[0:50]}...") - - curr_topo_json = json.loads(curr_topo_str) - lc_domain_topo_dict[curr_topo_json["domain_name"]] = curr_topo_json[ - "lc_queue_name" - ] - logger.debug( - f"Adding #{i} topology {curr_topo_json.get('id')} to TEManager" - ) - temanager.add_topology(curr_topo_json) + # if self.db_instance.read_from_db("num_domain_topos"): + # num_domain_topos = self.db_instance.read_from_db("num_domain_topos")[ + # "num_domain_topos" + # ] + + # # Initializing TEManager with `None` topology data is a + # # work-around for + # # https://github.com/atlanticwave-sdx/sdx-controller/issues/145 + # temanager = TEManager(topology_data=None) + # lc_domain_topo_dict = {} + + # # Read LC-1, LC-2, LC-3, and LC-4 topologies because of + # # https://github.com/atlanticwave-sdx/sdx-controller/issues/152 + # for i in range(1, int(num_domain_topos) + 2): + # lc = f"LC-{i}" + # logger.debug(f"Reading {lc} from DB") + # curr_topo = self.db_instance.read_from_db(lc) + # if curr_topo is None: + # logger.debug(f"Read {lc} from DB: {curr_topo}") + # continue + # else: + # # Get the actual thing minus the Mongo ObjectID. + # curr_topo_str = curr_topo.get(lc) + # # Just log a substring, not the whole thing. + # logger.debug(f"Read {lc} from DB: {curr_topo_str[0:50]}...") + + # curr_topo_json = json.loads(curr_topo_str) + # lc_domain_topo_dict[curr_topo_json["domain_name"]] = curr_topo_json[ + # "lc_queue_name" + # ] + # logger.debug( + # f"Adding #{i} topology {curr_topo_json.get('id')} to TEManager" + # ) + # temanager.add_topology(curr_topo_json) for num, val in enumerate(temanager.get_topology_map().values()): logger.info(f"TE topology #{num}: {val}") From dbdff387884560e1ab1aa6a08dafb9892a591ebb Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:35:58 -0600 Subject: [PATCH 17/42] Update assertion and comment --- sdx_controller/test/test_connection_controller.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdx_controller/test/test_connection_controller.py b/sdx_controller/test/test_connection_controller.py index f3412663..c8de42ea 100644 --- a/sdx_controller/test/test_connection_controller.py +++ b/sdx_controller/test/test_connection_controller.py @@ -91,9 +91,9 @@ def test_place_connection_with_three_topologies(self): print(f"Response body is : {response.data.decode('utf-8')}") - # Expect 400 failure for now because TEManager is not properly - # set up within the handler yet. - self.assertStatus(response, 400) + # Expect 200 success because TEManager now should be properly + # set up with all the expected topology data. + self.assertStatus(response, 200) if __name__ == "__main__": From 7f196d8a4b74abf2f7c48f592b85ca4484878e33 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:36:17 -0600 Subject: [PATCH 18/42] Avoid unnecessary json.loads()/json.dumps() steps --- sdx_controller/test/test_connection_controller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdx_controller/test/test_connection_controller.py b/sdx_controller/test/test_connection_controller.py index c8de42ea..54d9f362 100644 --- a/sdx_controller/test/test_connection_controller.py +++ b/sdx_controller/test/test_connection_controller.py @@ -80,12 +80,12 @@ def test_place_connection_with_three_topologies(self): topology = json.loads(topology_file.read_text()) self.te_manager.add_topology(topology) - request = json.loads(TestData.CONNECTION_REQ.read_text()) + request = TestData.CONNECTION_REQ.read_text() response = self.client.open( f"{BASE_PATH}/connection", method="POST", - data=json.dumps(request), + data=request, content_type="application/json", ) From deae25dd6d0b954b0c9fe3145e9f48f8611a2c4c Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:30:35 -0600 Subject: [PATCH 19/42] Use the "global" TEManager in place_connection() controller --- sdx_controller/controllers/connection_controller.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sdx_controller/controllers/connection_controller.py b/sdx_controller/controllers/connection_controller.py index f6c2de62..81318d64 100644 --- a/sdx_controller/controllers/connection_controller.py +++ b/sdx_controller/controllers/connection_controller.py @@ -2,6 +2,7 @@ import logging import connexion +from flask import current_app from sdx_controller.handlers.connection_handler import ConnectionHandler from sdx_controller.utils.db_utils import DbUtils @@ -64,7 +65,9 @@ def place_connection(body): db_instance.add_key_value_pair_to_db("connection_data", json.dumps(body)) logger.info("Saving to database complete.") - reason, code = connection_handler.place_connection(body) + logger.info(f"Handling request with te_manager: {current_app.te_manager}") + + reason, code = connection_handler.place_connection(current_app.te_manager, body) logger.info(f"place_connection result: reason='{reason}', code={code}") return reason, code From 2fc6c040bf4851455108ffe13700a868aa3bca19 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:32:25 -0600 Subject: [PATCH 20/42] Use the "global" TEManager in place_connection() handler --- sdx_controller/handlers/connection_handler.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/sdx_controller/handlers/connection_handler.py b/sdx_controller/handlers/connection_handler.py index 0c272cb7..17c54d52 100644 --- a/sdx_controller/handlers/connection_handler.py +++ b/sdx_controller/handlers/connection_handler.py @@ -85,7 +85,9 @@ def _send_breakdown_to_lc(self, breakdown, connection_request): # leading up to this point were successful. return "Connection published", 200 - def place_connection(self, connection_request: dict) -> Tuple[str, int]: + def place_connection( + self, temanager: TEManager, connection_request: dict + ) -> Tuple[str, int]: """ Do the actual work of creating a connection. From f05674b8a6fba3be0dffe41bf94174aadca3f858 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:33:02 -0600 Subject: [PATCH 21/42] Return success status and code from place_connection() --- sdx_controller/handlers/connection_handler.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/sdx_controller/handlers/connection_handler.py b/sdx_controller/handlers/connection_handler.py index 17c54d52..3a64d64a 100644 --- a/sdx_controller/handlers/connection_handler.py +++ b/sdx_controller/handlers/connection_handler.py @@ -160,6 +160,8 @@ def place_connection( breakdown = temanager.generate_connection_breakdown(solution) self._send_breakdown_to_lc(breakdown, connection_request) + return "OK", 200 + def handle_link_failure(self, msg_json): logger.debug("---Handling connections that contain failed link.---") link_connections_dict_str = self.db_instance.read_from_db( From 99911646e22b8e12aa317c253c925808431be812 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:34:26 -0600 Subject: [PATCH 22/42] Just comment out the extra TEManager setup, for now To be removed later --- sdx_controller/handlers/connection_handler.py | 68 +++++++++---------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/sdx_controller/handlers/connection_handler.py b/sdx_controller/handlers/connection_handler.py index 3a64d64a..f0631124 100644 --- a/sdx_controller/handlers/connection_handler.py +++ b/sdx_controller/handlers/connection_handler.py @@ -100,40 +100,40 @@ def place_connection( """ num_domain_topos = 0 - if self.db_instance.read_from_db("num_domain_topos"): - num_domain_topos = self.db_instance.read_from_db("num_domain_topos")[ - "num_domain_topos" - ] - - # Initializing TEManager with `None` topology data is a - # work-around for - # https://github.com/atlanticwave-sdx/sdx-controller/issues/145 - temanager = TEManager(topology_data=None) - lc_domain_topo_dict = {} - - # Read LC-1, LC-2, LC-3, and LC-4 topologies because of - # https://github.com/atlanticwave-sdx/sdx-controller/issues/152 - for i in range(1, int(num_domain_topos) + 2): - lc = f"LC-{i}" - logger.debug(f"Reading {lc} from DB") - curr_topo = self.db_instance.read_from_db(lc) - if curr_topo is None: - logger.debug(f"Read {lc} from DB: {curr_topo}") - continue - else: - # Get the actual thing minus the Mongo ObjectID. - curr_topo_str = curr_topo.get(lc) - # Just log a substring, not the whole thing. - logger.debug(f"Read {lc} from DB: {curr_topo_str[0:50]}...") - - curr_topo_json = json.loads(curr_topo_str) - lc_domain_topo_dict[curr_topo_json["domain_name"]] = curr_topo_json[ - "lc_queue_name" - ] - logger.debug( - f"Adding #{i} topology {curr_topo_json.get('id')} to TEManager" - ) - temanager.add_topology(curr_topo_json) + # if self.db_instance.read_from_db("num_domain_topos"): + # num_domain_topos = self.db_instance.read_from_db("num_domain_topos")[ + # "num_domain_topos" + # ] + + # # Initializing TEManager with `None` topology data is a + # # work-around for + # # https://github.com/atlanticwave-sdx/sdx-controller/issues/145 + # temanager = TEManager(topology_data=None) + # lc_domain_topo_dict = {} + + # # Read LC-1, LC-2, LC-3, and LC-4 topologies because of + # # https://github.com/atlanticwave-sdx/sdx-controller/issues/152 + # for i in range(1, int(num_domain_topos) + 2): + # lc = f"LC-{i}" + # logger.debug(f"Reading {lc} from DB") + # curr_topo = self.db_instance.read_from_db(lc) + # if curr_topo is None: + # logger.debug(f"Read {lc} from DB: {curr_topo}") + # continue + # else: + # # Get the actual thing minus the Mongo ObjectID. + # curr_topo_str = curr_topo.get(lc) + # # Just log a substring, not the whole thing. + # logger.debug(f"Read {lc} from DB: {curr_topo_str[0:50]}...") + + # curr_topo_json = json.loads(curr_topo_str) + # lc_domain_topo_dict[curr_topo_json["domain_name"]] = curr_topo_json[ + # "lc_queue_name" + # ] + # logger.debug( + # f"Adding #{i} topology {curr_topo_json.get('id')} to TEManager" + # ) + # temanager.add_topology(curr_topo_json) for num, val in enumerate(temanager.get_topology_map().values()): logger.info(f"TE topology #{num}: {val}") From 18860773d07e9bfb4f837b55c477ca663cc6ef55 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:35:58 -0600 Subject: [PATCH 23/42] Update assertion and comment --- sdx_controller/test/test_connection_controller.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sdx_controller/test/test_connection_controller.py b/sdx_controller/test/test_connection_controller.py index f3412663..c8de42ea 100644 --- a/sdx_controller/test/test_connection_controller.py +++ b/sdx_controller/test/test_connection_controller.py @@ -91,9 +91,9 @@ def test_place_connection_with_three_topologies(self): print(f"Response body is : {response.data.decode('utf-8')}") - # Expect 400 failure for now because TEManager is not properly - # set up within the handler yet. - self.assertStatus(response, 400) + # Expect 200 success because TEManager now should be properly + # set up with all the expected topology data. + self.assertStatus(response, 200) if __name__ == "__main__": From a8bb4e3a98e3b2b707885e93e82bf1dac67e82ed Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:36:17 -0600 Subject: [PATCH 24/42] Avoid unnecessary json.loads()/json.dumps() steps --- sdx_controller/test/test_connection_controller.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdx_controller/test/test_connection_controller.py b/sdx_controller/test/test_connection_controller.py index c8de42ea..54d9f362 100644 --- a/sdx_controller/test/test_connection_controller.py +++ b/sdx_controller/test/test_connection_controller.py @@ -80,12 +80,12 @@ def test_place_connection_with_three_topologies(self): topology = json.loads(topology_file.read_text()) self.te_manager.add_topology(topology) - request = json.loads(TestData.CONNECTION_REQ.read_text()) + request = TestData.CONNECTION_REQ.read_text() response = self.client.open( f"{BASE_PATH}/connection", method="POST", - data=json.dumps(request), + data=request, content_type="application/json", ) From 62d69f25262a98df2b6b2aa75a2a74731255ec2b Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:54:37 -0600 Subject: [PATCH 25/42] Remove unused imports --- sdx_controller/test/__init__.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sdx_controller/test/__init__.py b/sdx_controller/test/__init__.py index 75fe48c6..f2449ab0 100644 --- a/sdx_controller/test/__init__.py +++ b/sdx_controller/test/__init__.py @@ -1,7 +1,5 @@ -import logging import os -import connexion from flask_testing import TestCase try: From d8d01caffdb695e4333f89359923ecdd6312f14c Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:58:15 -0600 Subject: [PATCH 26/42] Remove merge artifact duplicate import --- sdx_controller/controllers/connection_controller.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sdx_controller/controllers/connection_controller.py b/sdx_controller/controllers/connection_controller.py index 124b547a..81318d64 100644 --- a/sdx_controller/controllers/connection_controller.py +++ b/sdx_controller/controllers/connection_controller.py @@ -4,8 +4,6 @@ import connexion from flask import current_app -from flask import current_app - from sdx_controller.handlers.connection_handler import ConnectionHandler from sdx_controller.utils.db_utils import DbUtils From d52ea00c01f909cfcabf37dbf2e7349f34fb387c Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Wed, 31 Jan 2024 16:59:19 -0600 Subject: [PATCH 27/42] Comment out unused variable --- sdx_controller/handlers/connection_handler.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdx_controller/handlers/connection_handler.py b/sdx_controller/handlers/connection_handler.py index f0631124..9d78340e 100644 --- a/sdx_controller/handlers/connection_handler.py +++ b/sdx_controller/handlers/connection_handler.py @@ -98,7 +98,7 @@ def place_connection( Note that we can return early if things fail. Return value is a tuple of the form (reason, HTTP code). """ - num_domain_topos = 0 + # num_domain_topos = 0 # if self.db_instance.read_from_db("num_domain_topos"): # num_domain_topos = self.db_instance.read_from_db("num_domain_topos")[ From 9b8d450edbf4bfa746355df08d8598ae1e201bd8 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Thu, 1 Feb 2024 09:06:00 -0600 Subject: [PATCH 28/42] Return what the helper returns --- sdx_controller/handlers/connection_handler.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/sdx_controller/handlers/connection_handler.py b/sdx_controller/handlers/connection_handler.py index 9d78340e..799bad33 100644 --- a/sdx_controller/handlers/connection_handler.py +++ b/sdx_controller/handlers/connection_handler.py @@ -158,9 +158,7 @@ def place_connection( return "Could not solve the request", 400 breakdown = temanager.generate_connection_breakdown(solution) - self._send_breakdown_to_lc(breakdown, connection_request) - - return "OK", 200 + return self._send_breakdown_to_lc(breakdown, connection_request) def handle_link_failure(self, msg_json): logger.debug("---Handling connections that contain failed link.---") From d7f35f2e55e949ff45f1bde8964f7a2aa22ca288 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Thu, 1 Feb 2024 09:15:50 -0600 Subject: [PATCH 29/42] Remove unused code --- sdx_controller/handlers/connection_handler.py | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/sdx_controller/handlers/connection_handler.py b/sdx_controller/handlers/connection_handler.py index 799bad33..b63ea045 100644 --- a/sdx_controller/handlers/connection_handler.py +++ b/sdx_controller/handlers/connection_handler.py @@ -98,43 +98,6 @@ def place_connection( Note that we can return early if things fail. Return value is a tuple of the form (reason, HTTP code). """ - # num_domain_topos = 0 - - # if self.db_instance.read_from_db("num_domain_topos"): - # num_domain_topos = self.db_instance.read_from_db("num_domain_topos")[ - # "num_domain_topos" - # ] - - # # Initializing TEManager with `None` topology data is a - # # work-around for - # # https://github.com/atlanticwave-sdx/sdx-controller/issues/145 - # temanager = TEManager(topology_data=None) - # lc_domain_topo_dict = {} - - # # Read LC-1, LC-2, LC-3, and LC-4 topologies because of - # # https://github.com/atlanticwave-sdx/sdx-controller/issues/152 - # for i in range(1, int(num_domain_topos) + 2): - # lc = f"LC-{i}" - # logger.debug(f"Reading {lc} from DB") - # curr_topo = self.db_instance.read_from_db(lc) - # if curr_topo is None: - # logger.debug(f"Read {lc} from DB: {curr_topo}") - # continue - # else: - # # Get the actual thing minus the Mongo ObjectID. - # curr_topo_str = curr_topo.get(lc) - # # Just log a substring, not the whole thing. - # logger.debug(f"Read {lc} from DB: {curr_topo_str[0:50]}...") - - # curr_topo_json = json.loads(curr_topo_str) - # lc_domain_topo_dict[curr_topo_json["domain_name"]] = curr_topo_json[ - # "lc_queue_name" - # ] - # logger.debug( - # f"Adding #{i} topology {curr_topo_json.get('id')} to TEManager" - # ) - # temanager.add_topology(curr_topo_json) - for num, val in enumerate(temanager.get_topology_map().values()): logger.info(f"TE topology #{num}: {val}") From af918517f66500c66c7d494e0d2008c9cb8057b6 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Thu, 1 Feb 2024 09:16:31 -0600 Subject: [PATCH 30/42] Rename a variable for ease of grepping --- sdx_controller/handlers/connection_handler.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/sdx_controller/handlers/connection_handler.py b/sdx_controller/handlers/connection_handler.py index b63ea045..6c3749f7 100644 --- a/sdx_controller/handlers/connection_handler.py +++ b/sdx_controller/handlers/connection_handler.py @@ -86,7 +86,7 @@ def _send_breakdown_to_lc(self, breakdown, connection_request): return "Connection published", 200 def place_connection( - self, temanager: TEManager, connection_request: dict + self, te_manager: TEManager, connection_request: dict ) -> Tuple[str, int]: """ Do the actual work of creating a connection. @@ -98,14 +98,14 @@ def place_connection( Note that we can return early if things fail. Return value is a tuple of the form (reason, HTTP code). """ - for num, val in enumerate(temanager.get_topology_map().values()): + for num, val in enumerate(te_manager.get_topology_map().values()): logger.info(f"TE topology #{num}: {val}") - graph = temanager.generate_graph_te() + graph = te_manager.generate_graph_te() if graph is None: return "Could not generate a graph", 400 - traffic_matrix = temanager.generate_traffic_matrix( + traffic_matrix = te_manager.generate_traffic_matrix( connection_request=connection_request ) if traffic_matrix is None: @@ -120,7 +120,7 @@ def place_connection( if solution is None or solution.connection_map is None: return "Could not solve the request", 400 - breakdown = temanager.generate_connection_breakdown(solution) + breakdown = te_manager.generate_connection_breakdown(solution) return self._send_breakdown_to_lc(breakdown, connection_request) def handle_link_failure(self, msg_json): From 165022400a70a77ebb6baf27a442b2afe242a8a0 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Thu, 1 Feb 2024 16:29:29 -0600 Subject: [PATCH 31/42] We only have a WSGI interface --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index b3d7acb4..06bcf991 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,4 +21,4 @@ RUN --mount=source=.git,target=.git,type=bind \ EXPOSE 8080 ENTRYPOINT ["python3"] -CMD ["-m", "uvicorn", "sdx_controller.app:app"] +CMD ["-m", "uvicorn", "sdx_controller.app:app", "--interface", "wsgi"] From 982f945e948090747909db1e860fa2c3089bcdf1 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Thu, 1 Feb 2024 16:29:41 -0600 Subject: [PATCH 32/42] Bind to 0.0.0.0 --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 06bcf991..4cf086b6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,4 +21,4 @@ RUN --mount=source=.git,target=.git,type=bind \ EXPOSE 8080 ENTRYPOINT ["python3"] -CMD ["-m", "uvicorn", "sdx_controller.app:app", "--interface", "wsgi"] +CMD ["-m", "uvicorn", "sdx_controller.app:app", "--interface", "wsgi", "--port", "8080", "--host", "0.0.0.0"] From a6a8d8df341dfe506e64cdb0aaf78492315e49a1 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Thu, 1 Feb 2024 16:30:00 -0600 Subject: [PATCH 33/42] Remove EXPOSE, which apparently is no-op --- Dockerfile | 2 -- 1 file changed, 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4cf086b6..db1e6a1a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,7 +18,5 @@ COPY . /usr/src/app RUN --mount=source=.git,target=.git,type=bind \ pip install --no-cache-dir .[wsgi] -EXPOSE 8080 - ENTRYPOINT ["python3"] CMD ["-m", "uvicorn", "sdx_controller.app:app", "--interface", "wsgi", "--port", "8080", "--host", "0.0.0.0"] From e05108bd4ce6f3eebc55ab3bd543ca9c3f45ee04 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Fri, 2 Feb 2024 09:04:06 -0600 Subject: [PATCH 34/42] Put EXPOSE 8080 back in Dockerfile This accidentally got deleted during merge. I believe EXPOSE is a no-op and should go anyway, but let us test that theory separately. --- Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Dockerfile b/Dockerfile index 41625ecd..01dd7e02 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,5 +18,7 @@ COPY . /usr/src/app RUN --mount=source=.git,target=.git,type=bind \ pip install --no-cache-dir .[wsgi] +EXPOSE 8080 + ENTRYPOINT ["python3"] CMD ["-m", "uvicorn", "sdx_controller.app:asgi_app", "--host", "0.0.0.0", "--port", "8080"] From f28f88eadd138315650a5c42041176b41dd7311a Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Fri, 2 Feb 2024 09:26:43 -0600 Subject: [PATCH 35/42] Add yet another place_connection() test --- .../test/test_connection_controller.py | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/sdx_controller/test/test_connection_controller.py b/sdx_controller/test/test_connection_controller.py index 54d9f362..5e8f28db 100644 --- a/sdx_controller/test/test_connection_controller.py +++ b/sdx_controller/test/test_connection_controller.py @@ -95,6 +95,42 @@ def test_place_connection_with_three_topologies(self): # set up with all the expected topology data. self.assertStatus(response, 200) + def test_place_connection_with_three_topologies_added_in_sequence(self): + """ + Test case for place_connection. + + Place the same connection request while adding topologies. + """ + for idx, topology_file in enumerate( + [ + TestData.TOPOLOGY_FILE_AMLIGHT, + TestData.TOPOLOGY_FILE_SAX, + TestData.TOPOLOGY_FILE_ZAOXI, + ] + ): + topology = json.loads(topology_file.read_text()) + self.te_manager.add_topology(topology) + + request = TestData.CONNECTION_REQ.read_text() + + response = self.client.open( + f"{BASE_PATH}/connection", + method="POST", + data=request, + content_type="application/json", + ) + + print(f"Response body is : {response.data.decode('utf-8')}") + + if idx in [0, 1]: + # Expect 400 failure because TEManager do not have all + # the topologies yet. + self.assertStatus(response, 400) + if idx == 200: + # Expect 200 success now that TEManager should be set + # up with all the expected topology data. + self.assertStatus(response, 200) + if __name__ == "__main__": unittest.main() From 133eb9f24f803d97842f480341da691794e580c2 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Fri, 2 Feb 2024 09:37:23 -0600 Subject: [PATCH 36/42] Add more place_connection() tests --- .../test/test_connection_controller.py | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/sdx_controller/test/test_connection_controller.py b/sdx_controller/test/test_connection_controller.py index 5e8f28db..c3f2d338 100644 --- a/sdx_controller/test/test_connection_controller.py +++ b/sdx_controller/test/test_connection_controller.py @@ -66,6 +66,46 @@ def test_place_connection_no_topology(self): # ingress port data, etc., for example. self.assertStatus(response, 400) + def __test_with_one_topology(self, topology_file): + """ + A helper method to test place_connection() with just one topology. + """ + topology = json.loads(topology_file.read_text()) + self.te_manager.add_topology(topology) + + request = TestData.CONNECTION_REQ.read_text() + + response = self.client.open( + f"{BASE_PATH}/connection", + method="POST", + data=request, + content_type="application/json", + ) + + print(f"Response body is : {response.data.decode('utf-8')}") + + # Expect 400 failure, because TEManager do not have enough + # topology data. + self.assertStatus(response, 400) + + def test_place_connection_with_amlight(self): + """ + Test place_connection() with just Amlight topology. + """ + self.__test_with_one_topology(TestData.TOPOLOGY_FILE_AMLIGHT) + + def test_place_connection_with_sax(self): + """ + Test place_connection() with just SAX topology. + """ + self.__test_with_one_topology(TestData.TOPOLOGY_FILE_SAX) + + def test_place_connection_with_zaoxi(self): + """ + Test place_connection() with just ZAOXI topology. + """ + self.__test_with_one_topology(TestData.TOPOLOGY_FILE_ZAOXI) + def test_place_connection_with_three_topologies(self): """ Test case for place_connection. From de0d6886b375b60b1392a3b73b8123d20a69a023 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Fri, 2 Feb 2024 09:51:47 -0600 Subject: [PATCH 37/42] Remove superfluous noqa --- sdx_controller/test/test_connection_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdx_controller/test/test_connection_controller.py b/sdx_controller/test/test_connection_controller.py index c3f2d338..d4ad8952 100644 --- a/sdx_controller/test/test_connection_controller.py +++ b/sdx_controller/test/test_connection_controller.py @@ -6,7 +6,7 @@ from flask import json -from sdx_controller.models.connection import Connection # noqa: E501 +from sdx_controller.models.connection import Connection from sdx_controller.test import BaseTestCase, TestData BASE_PATH = "/SDX-Controller/1.0.0" From 57fd5ebe1eadc12d9a68ea46c775957c00d08985 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Fri, 2 Feb 2024 09:52:53 -0600 Subject: [PATCH 38/42] Test with Python 3.11 as well --- .github/workflows/test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 12847e88..3b3f9e3a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -44,6 +44,7 @@ jobs: - "3.8" - "3.9" - "3.10" + - "3.11" steps: From a010e2108a3c5d9fa83452ec124dc1680a5be768 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Fri, 2 Feb 2024 16:15:17 -0600 Subject: [PATCH 39/42] Get rid of the final TopologyManager usage --- .../controllers/topology_controller.py | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/sdx_controller/controllers/topology_controller.py b/sdx_controller/controllers/topology_controller.py index 576a98e2..07aa9f43 100644 --- a/sdx_controller/controllers/topology_controller.py +++ b/sdx_controller/controllers/topology_controller.py @@ -1,14 +1,13 @@ import json +from flask import current_app from sdx_pce.topology.grenmlconverter import GrenmlConverter -from sdx_pce.topology.manager import TopologyManager from sdx_controller.utils.db_utils import DbUtils # Get DB connection and tables set up. db_instance = DbUtils() db_instance.initialize_db() -manager = TopologyManager() def get_topology(): # noqa: E501 @@ -41,18 +40,8 @@ def get_topologyby_grenml(): # noqa: E501 :rtype: Topology """ - - num_domain_topos = 0 - - if db_instance.read_from_db("num_domain_topos") is not None: - num_domain_topos = db_instance.read_from_db("num_domain_topos") - - for i in range(1, int(num_domain_topos) + 1): - curr_topo_str = db_instance.read_from_db("LC-" + str(i)) - curr_topo_json = json.loads(curr_topo_str) - manager.add_topology(curr_topo_json) - - converter = GrenmlConverter(manager.get_topology()) + topology = current_app.te_manager.get_topology() + converter = GrenmlConverter(topology) converter.read_topology() return converter.get_xml_str() From f9cdfebfa9079e63dd49efe423eedce43b47e1e7 Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Fri, 2 Feb 2024 16:17:50 -0600 Subject: [PATCH 40/42] Remove unused import --- sdx_controller/controllers/topology_controller.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/sdx_controller/controllers/topology_controller.py b/sdx_controller/controllers/topology_controller.py index 07aa9f43..e1b09f64 100644 --- a/sdx_controller/controllers/topology_controller.py +++ b/sdx_controller/controllers/topology_controller.py @@ -1,5 +1,3 @@ -import json - from flask import current_app from sdx_pce.topology.grenmlconverter import GrenmlConverter From cf0117defe4f994980878df8d285953db3503eda Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Fri, 15 Mar 2024 11:46:07 -0500 Subject: [PATCH 41/42] Remove trailing whitespace --- compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compose.yml b/compose.yml index 9b7d3f3c..6d1068a3 100644 --- a/compose.yml +++ b/compose.yml @@ -5,7 +5,7 @@ services: mongodb: # See https://hub.docker.com/_/mongo/ for documentation about # MongoDB Docker images. - image: mongo:7.0.5 + image: mongo:7.0.5 ports: - ${MONGO_PORT}:${MONGO_PORT} environment: From 5f39dca250c2e54125ca91a138b36769c896203d Mon Sep 17 00:00:00 2001 From: Sajith Sasidharan Date: Fri, 15 Mar 2024 11:46:22 -0500 Subject: [PATCH 42/42] Add a healthcheck for MongoDB in compose --- compose.yml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/compose.yml b/compose.yml index 6d1068a3..53459a8b 100644 --- a/compose.yml +++ b/compose.yml @@ -21,11 +21,8 @@ services: - type: volume source: mongodb target: /data/db:Z - # healthcheck: - # test: ["CMD", "mongo", "--eval", "db.version()"] - # interval: 10s - # timeout: 5s - # retries: 3 + healthcheck: + test: ["CMD", "mongosh", "localhost:${MONGO_PORT}/test", "--quiet"] sdx-controller: image: sdx-controller