-
Notifications
You must be signed in to change notification settings - Fork 1
Pull conn status from oxp #203
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 7 commits
75302ef
9a770c9
edc28c4
e9e9851
c37f3c9
5369336
1e7bd64
2902fe9
f14395d
a6a88cf
8f21d76
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -27,7 +27,7 @@ dependencies = [ | |
| "connexion[swagger-ui] == 2.14.2", | ||
| "asgiref >= 3.7.2", | ||
| "pymongo > 3.0", | ||
| "sdx-datamodel @ git+https://github.com/atlanticwave-sdx/datamodel@v3.2.1", | ||
| "sdx-datamodel @ git+https://github.com/atlanticwave-sdx/datamodel@v3.2.0", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi Cong, can you please confirm this change? like using a older version?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Somehow datamodel's most recent tag is 3.2.0 (https://github.com/atlanticwave-sdx/datamodel/tags). I'll check with Yufeng to make sure tags are consistent. |
||
| ] | ||
|
|
||
| [project.optional-dependencies] | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,108 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||
| import json | ||||||||||||||||||||||||||||||||||||||||||||||||
| import logging | ||||||||||||||||||||||||||||||||||||||||||||||||
| import os.path | ||||||||||||||||||||||||||||||||||||||||||||||||
| import sys | ||||||||||||||||||||||||||||||||||||||||||||||||
| import time | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| import requests | ||||||||||||||||||||||||||||||||||||||||||||||||
| from sdx_datamodel.constants import Constants, MessageQueueNames | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| # append abspath, so this file can import other modules from parent directory | ||||||||||||||||||||||||||||||||||||||||||||||||
| sys.path.append( | ||||||||||||||||||||||||||||||||||||||||||||||||
| os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)) | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| from messaging.rpc_queue_producer import RpcProducer | ||||||||||||||||||||||||||||||||||||||||||||||||
| from utils.db_utils import DbUtils | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| SDXLC_DOMAIN = os.environ.get("SDXLC_DOMAIN") | ||||||||||||||||||||||||||||||||||||||||||||||||
| OXP_LIST_CONNECTIONS_URL = os.environ.get("OXP_LIST_CONNECTIONS_URL") | ||||||||||||||||||||||||||||||||||||||||||||||||
| OXP_PULL_CONNECTIONS_INTERVAL = os.environ.get("OXP_PULL_CONNECTIONS_INTERVAL") | ||||||||||||||||||||||||||||||||||||||||||||||||
| PUB_QUEUE = MessageQueueNames.OXP_UPDATE | ||||||||||||||||||||||||||||||||||||||||||||||||
| logger = logging.getLogger(__name__) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| def main(): | ||||||||||||||||||||||||||||||||||||||||||||||||
| db_instance = DbUtils() | ||||||||||||||||||||||||||||||||||||||||||||||||
| db_instance.initialize_db() | ||||||||||||||||||||||||||||||||||||||||||||||||
| process_oxp_connections(db_instance) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| # Periodically pull l2vpn (connection) status from OXP, and handle status change. | ||||||||||||||||||||||||||||||||||||||||||||||||
| # Possible l2vpn status are: | ||||||||||||||||||||||||||||||||||||||||||||||||
| # “up” if the L2VPN is operational, | ||||||||||||||||||||||||||||||||||||||||||||||||
| # “down” if the L2VPN is not operational due to topology issues/lack of path, or endpoints being down, | ||||||||||||||||||||||||||||||||||||||||||||||||
| # “error” when there is an error with the L2VPN, | ||||||||||||||||||||||||||||||||||||||||||||||||
| # “under provisioning” when the L2VPN is still being provisioned by the OXPs, | ||||||||||||||||||||||||||||||||||||||||||||||||
| # “maintenance” when the L2VPN is being affected by a network maintenance. | ||||||||||||||||||||||||||||||||||||||||||||||||
| def process_oxp_connections(db_instance): | ||||||||||||||||||||||||||||||||||||||||||||||||
| while True: | ||||||||||||||||||||||||||||||||||||||||||||||||
| time.sleep(int(OXP_PULL_CONNECTIONS_INTERVAL)) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||
| response = requests.get(OXP_LIST_CONNECTIONS_URL) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
congwang09 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||
| connections = response.content | ||||||||||||||||||||||||||||||||||||||||||||||||
| except (requests.ConnectionError, requests.HTTPError): | ||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug("Error connecting to OXP...") | ||||||||||||||||||||||||||||||||||||||||||||||||
|
congwang09 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if not response.ok: | ||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||
|
congwang09 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug("Received connections from OXP.") | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||
| connections_json = response.json() | ||||||||||||||||||||||||||||||||||||||||||||||||
| except ValueError: | ||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug("Cannot parse connections, invalid JSON.") | ||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if not connections_json: | ||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug("No connections yet.") | ||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| for service_id, connection in connections_json.items(): | ||||||||||||||||||||||||||||||||||||||||||||||||
| # Fetch existing connection from DB | ||||||||||||||||||||||||||||||||||||||||||||||||
| existing_connection = db_instance.get_value_by_key(service_id) | ||||||||||||||||||||||||||||||||||||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Cong, another doubt arrived while reviewing the SDX-COntroller side: can you please double check if we really want to maintain a database entry in the SDX-LC? It will make things a bit more complicated to make sure the L2VPNs are removed when removed, inserted, updated, etc. My question is: what is the actual advantage of keeping state on the SDX-LC (at least for l2vpns)?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hi Italo, the db in LC is to compare existing l2vpn's "status" with new "status" pulled from OXP, and only send specific l2vpn to SDX controller if status changes. If without database, we will need to periodically forward a long list of all l2vpn to SDX controller, and let SDX controller decide if status has changed. I think this would not be very efficient. I'm open to other options if you have better ideas.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, you are right Cong. From the efficiency perspective, this would save a few messages and bytes from being exchanged. However, when we designed the SDX-LC one of the ideas was not to maintain state or having much intelligence on it, so that we could have one central entity where the actual processing would happen (and then we can concentrate the decision making process and intelligence). If we are to change this idea, that is fine for me. However, in that case, you have to delete the L2VPN from SDX-LC local database upon receiving a removal request from sdx-controller, right? can you please double check that? sdx-lc/sdx_lc/handlers/sdx_controller_msg_handler.py Lines 122 to 144 in 85bff21
Also, the pull L2VPN from OXP routine should check the local DB for missing L2VPNs and notify the Controller that missing L2VPN, right? Currently, this does not seems covered on the routine Finally, for "alien" L2VPNs (i.e., the ones returned by OXP but not found on the local DB) we also should notify the SDX-Controller, right? currently, the routine is just ignoring them https://github.com/atlanticwave-sdx/sdx-lc/pull/203/changes#diff-92d2d9f91fcf0945f76b15e8823c1b9cc0b5106b66ea27f2c54d73caa69ff713R67 |
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if not existing_connection: | ||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(f"New connection {service_id}, ignored") | ||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| try: | ||||||||||||||||||||||||||||||||||||||||||||||||
| existing_connection_json = json.loads(existing_connection) | ||||||||||||||||||||||||||||||||||||||||||||||||
| except ValueError: | ||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(f"Invalid JSON in DB for {service_id}") | ||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| existing_connection_status = ( | ||||||||||||||||||||||||||||||||||||||||||||||||
| existing_connection_json.get("status") | ||||||||||||||||||||||||||||||||||||||||||||||||
| if existing_connection_json | ||||||||||||||||||||||||||||||||||||||||||||||||
| else None | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||
| new_status = connection.get("status") | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if existing_connection_status == new_status: | ||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug(f"Status unchanged for {service_id}") | ||||||||||||||||||||||||||||||||||||||||||||||||
| continue | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| existing_connection_json["status"] = new_status | ||||||||||||||||||||||||||||||||||||||||||||||||
| logger.debug( | ||||||||||||||||||||||||||||||||||||||||||||||||
|
congwang09 marked this conversation as resolved.
Outdated
|
||||||||||||||||||||||||||||||||||||||||||||||||
| f"Status change for {service_id}: " | ||||||||||||||||||||||||||||||||||||||||||||||||
| f"{existing_connection_status} changed to {new_status}" | ||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||
| db_instance.add_key_value_pair_to_db(service_id, existing_connection_json) | ||||||||||||||||||||||||||||||||||||||||||||||||
| rpc_msg = { | ||||||||||||||||||||||||||||||||||||||||||||||||
| "lc_domain": SDXLC_DOMAIN, | ||||||||||||||||||||||||||||||||||||||||||||||||
| "msg_type": "oxp_conn_status_change", | ||||||||||||||||||||||||||||||||||||||||||||||||
| "service_id": service_id, | ||||||||||||||||||||||||||||||||||||||||||||||||
| "existing_status": existing_connection_status, | ||||||||||||||||||||||||||||||||||||||||||||||||
| "new_status": new_status, | ||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||
| rpc_producer = RpcProducer(5, "", PUB_QUEUE) | ||||||||||||||||||||||||||||||||||||||||||||||||
| rpc_producer.call(json.dumps(rpc_msg)) | ||||||||||||||||||||||||||||||||||||||||||||||||
| rpc_producer.stop() | ||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||
| if __name__ == "__main__": | ||||||||||||||||||||||||||||||||||||||||||||||||
| main() | ||||||||||||||||||||||||||||||||||||||||||||||||
|
congwang09 marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
according to the L2VPN provisioning API, the same endpoint used for creating L2VPNs is used to list all L2VPNs. Thus, I believe we could have the same env var here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct me if I was wrong, the endpoint for creating l2vpn is "1.0.0/connection", while the one list all connections is "1.0.0/connections"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that was the earlier endpoint, but when we finished the spec for L2VPN provisioning API, we refactor the Kytos SDX Napp to support the new endpoints, which are both (for creating and listing)
/l2vpn/1.0see more: https://github.com/atlanticwave-sdx/sdx-end-to-end-tests/blob/e98cce8412ee820529187d0fbf478adbdcf63493/env/ampath-lc.env#L7