-
Notifications
You must be signed in to change notification settings - Fork 7
Add tag pool for links + fix potential consistency and dead lock issues #281
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: master
Are you sure you want to change the base?
Changes from all commits
c35b0c3
e8420b2
ea698b8
0ce6464
af32f0d
5bb79c4
9be5649
ce7e867
2cc0e9e
7167b95
f601301
e9eafee
ddaf470
4d02e2b
1c4e757
d8a0f5f
5d892c3
a70355b
af5f1e2
c841475
c5e868f
3838473
a7ede81
bdf704e
78a78f9
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 |
|---|---|---|
|
|
@@ -35,7 +35,7 @@ | |
| class TopoController: | ||
| """TopoController.""" | ||
|
|
||
| def __init__(self, get_mongo=lambda: Mongo()) -> None: | ||
|
Member
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. Trivial comment but we've been using this way in other NApps too, do we really need this equivalent change and start deviating from the rest? |
||
| def __init__(self, get_mongo=Mongo) -> None: | ||
| """Constructor of TopoController.""" | ||
| self.mongo = get_mongo() | ||
| self.db_client = self.mongo.client | ||
|
|
@@ -156,6 +156,19 @@ def disable_interface(self, interface_id: str) -> Optional[dict]: | |
| interface_id, {"$set": {"enabled": False}} | ||
| ) | ||
|
|
||
| def delete_interface(self, interface_id: str) -> Optional[dict]: | ||
| """Try to delete an interface embedded in a switch.""" | ||
| switch_id, _, port_num = interface_id.rpartition(":") | ||
| port_num = int(port_num) | ||
| return self.db.switches.find_one_and_update( | ||
| {"_id": switch_id}, | ||
| {"$unset": {"interfaces.$[iface]": 1}}, | ||
|
Member
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. Won't this leave a null interface? Did you mean to use Can you review this again |
||
| array_filters=[{ | ||
| "iface.port_number": {"$eq": port_num} | ||
| }], | ||
| return_document=ReturnDocument.AFTER | ||
| ) | ||
|
|
||
| def add_interface_metadata( | ||
| self, interface_id: str, metadata: dict | ||
| ) -> Optional[dict]: | ||
|
|
@@ -189,6 +202,69 @@ def _update_interface( | |
| return_document=ReturnDocument.AFTER, | ||
| ) | ||
|
|
||
| def enable_interfaces( | ||
| self, | ||
| switch_id: str, | ||
| ports: list[int] | ||
| ): | ||
| """Try to enable several interfaces.""" | ||
| return self._update_interfaces_of_switch( | ||
| switch_id, ports, {"$set": {"enabled": True}} | ||
| ) | ||
|
|
||
| def disable_interfaces( | ||
| self, | ||
| switch_id: str, | ||
| ports: list[int] | ||
| ): | ||
| """Try to disable several interfaces.""" | ||
| return self._update_interfaces_of_switch( | ||
| switch_id, ports, {"$set": {"enabled": False}} | ||
| ) | ||
|
|
||
| def enable_interfaces_lldp( | ||
| self, | ||
| switch_id: str, | ||
| ports: list[int] | ||
| ): | ||
| """Try to enable lldp on several interfaces.""" | ||
| return self._update_interfaces_of_switch( | ||
| switch_id, ports, {"$set": {"lldp": True}} | ||
| ) | ||
|
|
||
| def disable_interfaces_lldp( | ||
| self, | ||
| switch_id: str, | ||
| ports: list[int] | ||
| ): | ||
| """Try to disable lldp on several interfaces.""" | ||
| return self._update_interfaces_of_switch( | ||
| switch_id, ports, {"$set": {"lldp": False}} | ||
| ) | ||
|
|
||
| def _update_interfaces_of_switch( | ||
| self, | ||
| switch_id: str, | ||
| ports: list[int], | ||
| update_expr: dict | ||
| ): | ||
| self._set_updated_at(update_expr) | ||
| interfaces_expression = {} | ||
| for operator, values in update_expr.items(): | ||
| interfaces_expression[operator] = { | ||
| f"interfaces.$[iface].{key}": value | ||
| for key, value in values.items() | ||
| } | ||
|
|
||
| return self.db.switches.find_one_and_update( | ||
| {"_id": switch_id}, | ||
| interfaces_expression, | ||
| array_filters=[{ | ||
| "iface.port_number": {"$in": ports} | ||
| }], | ||
| return_document=ReturnDocument.AFTER | ||
| ) | ||
|
|
||
| def upsert_link(self, link_id: str, link_dict: dict) -> dict: | ||
| """Update or insert a Link.""" | ||
| utc_now = datetime.utcnow() | ||
|
|
@@ -299,17 +375,23 @@ def upsert_interface_details( | |
| id_: str, | ||
| available_tags: dict[str, list[list[int]]], | ||
| tag_ranges: dict[str, list[list[int]]], | ||
| default_tag_ranges: dict[str, list[list[int]]], | ||
| special_available_tags: dict[str, list[str]], | ||
| special_tags: dict[str, list[str]] | ||
| special_tags: dict[str, list[str]], | ||
| default_special_tags: dict[str, list[str]], | ||
| supported_tag_types: list[str], | ||
| ) -> Optional[dict]: | ||
| """Update or insert interfaces details.""" | ||
| utc_now = datetime.utcnow() | ||
| model = InterfaceDetailDoc(**{ | ||
| "_id": id_, | ||
| "available_tags": available_tags, | ||
| "tag_ranges": tag_ranges, | ||
| "default_tag_ranges": default_tag_ranges, | ||
| "special_available_tags": special_available_tags, | ||
| "special_tags": special_tags, | ||
| "default_special_tags": default_special_tags, | ||
| "supported_tag_types": supported_tag_types, | ||
| "updated_at": utc_now | ||
| }).model_dump(exclude={"inserted_at"}) | ||
| updated = self.db.interface_details.find_one_and_update( | ||
|
|
@@ -358,3 +440,55 @@ def delete_interface_from_details(self, intf_id: str) -> Optional[dict]: | |
| return self.db.interface_details.find_one_and_delete( | ||
| {"_id": intf_id} | ||
| ) | ||
|
|
||
| # pylint: disable=too-many-arguments | ||
| def upsert_link_details( | ||
| self, | ||
| id_: str, | ||
| available_tags: dict[str, list[list[int]]], | ||
| tag_ranges: dict[str, list[list[int]]], | ||
| default_tag_ranges: dict[str, list[list[int]]], | ||
| special_available_tags: dict[str, list[str]], | ||
| special_tags: dict[str, list[str]], | ||
| default_special_tags: dict[str, list[str]], | ||
| supported_tag_types: list[str], | ||
| ) -> Optional[dict]: | ||
| """Update or insert link details.""" | ||
| utc_now = datetime.utcnow() | ||
| model = InterfaceDetailDoc(**{ | ||
| "_id": id_, | ||
| "available_tags": available_tags, | ||
| "tag_ranges": tag_ranges, | ||
| "default_tag_ranges": default_tag_ranges, | ||
| "special_available_tags": special_available_tags, | ||
| "special_tags": special_tags, | ||
| "default_special_tags": default_special_tags, | ||
| "supported_tag_types": supported_tag_types, | ||
| "updated_at": utc_now | ||
| }).model_dump(exclude={"inserted_at"}) | ||
| updated = self.db.link_details.find_one_and_update( | ||
| {"_id": id_}, | ||
| { | ||
| "$set": model, | ||
| "$setOnInsert": {"inserted_at": utc_now}, | ||
| }, | ||
| return_document=ReturnDocument.AFTER, | ||
| upsert=True, | ||
| ) | ||
| return updated | ||
|
|
||
| def get_links_details( | ||
| self, link_ids: List[str] | ||
| ) -> Optional[dict]: | ||
| """Try to get link details given a list of link ids.""" | ||
| return self.db.link_details.aggregate( | ||
| [ | ||
| {"$match": {"_id": {"$in": link_ids}}}, | ||
| ] | ||
| ) | ||
|
|
||
| def delete_link_from_details(self, link_id: str) -> Optional[dict]: | ||
| """Delete link from link_details.""" | ||
| return self.db.link_details.find_one_and_delete( | ||
| {"_id": link_id} | ||
| ) | ||
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.
Changelog should include the new endpoints