Skip to content

Commit

Permalink
Merge pull request #109 from kytos-ng/fix/issue_107
Browse files Browse the repository at this point in the history
[Fix][Issue 107] RuntimeError: dictionary changed size during iteration
  • Loading branch information
viniarck authored Aug 11, 2022
2 parents 97a04ed + 8efd02b commit 62e9049
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 22 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ Fixed
=====
- Send topology.switches and topology.links shallow copy on ``kytos/topology.topology_loaded`` and ``kytos/topology.updated`` events
- Send object metadata shallow copy on ``kytos/topology.{entities}.metadata.{action}`` event
- Shallow copy shared iterables that are used on REST endpoints

Security
========
Expand Down
45 changes: 23 additions & 22 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ def _get_link_or_create(self, endpoint_a, endpoint_b):
def _get_switches_dict(self):
"""Return a dictionary with the known switches."""
switches = {'switches': {}}
for idx, switch in enumerate(self.controller.switches.values()):
for idx, switch in enumerate(self.controller.switches.copy().values()):
switch_data = switch.as_dict()
if not all(key in switch_data['metadata']
for key in ('lat', 'lng')):
Expand All @@ -111,7 +111,7 @@ def _get_switches_dict(self):
def _get_links_dict(self):
"""Return a dictionary with the known links."""
return {'links': {link.id: link.as_dict() for link in
self.links.values()}}
self.links.copy().values()}}

def _get_topology_dict(self):
"""Return a dictionary with the known topology."""
Expand All @@ -120,14 +120,15 @@ def _get_topology_dict(self):

def _get_topology(self):
"""Return an object representing the topology."""
return Topology(dict(self.controller.switches), dict(self.links))
return Topology(self.controller.switches.copy(), self.links.copy())

def _get_link_from_interface(self, interface):
"""Return the link of the interface, or None if it does not exist."""
for link in self.links.values():
if interface in (link.endpoint_a, link.endpoint_b):
return link
return None
with self._links_lock:
for link in self.links.values():
if interface in (link.endpoint_a, link.endpoint_b):
return link
return None

def _load_link(self, link_att):
endpoint_a = link_att['endpoint_a']['id']
Expand Down Expand Up @@ -356,7 +357,7 @@ def enable_interface(self, interface_enable_id=None, dpid=None):
msg = f"Switch {dpid} interface {interface_number} not found"
return jsonify(msg), 404
else:
for interface in switch.interfaces.values():
for interface in switch.interfaces.copy().values():
interface.enable()
self.topo_controller.upsert_switch(switch.id, switch.as_dict())
self.notify_topology_update()
Expand Down Expand Up @@ -384,7 +385,7 @@ def disable_interface(self, interface_disable_id=None, dpid=None):
msg = f"Switch {dpid} interface {interface_number} not found"
return jsonify(msg), 404
else:
for interface in switch.interfaces.values():
for interface in switch.interfaces.copy().values():
interface.disable()
self.topo_controller.upsert_switch(switch.id, switch.as_dict())
self.notify_topology_update()
Expand Down Expand Up @@ -569,15 +570,16 @@ def on_link_liveness_disabled(self, event) -> None:

def get_links_from_interfaces(self, interfaces) -> dict:
"""Get links from interfaces."""
links = {}
for interface in interfaces:
for link in self.links.values():
if any((
interface.id == link.endpoint_a.id,
interface.id == link.endpoint_b.id,
)):
links[link.id] = link
return links
links_found = {}
with self._links_lock:
for interface in interfaces:
for link in self.links.values():
if any((
interface.id == link.endpoint_a.id,
interface.id == link.endpoint_b.id,
)):
links_found[link.id] = link
return links_found

def handle_link_liveness_disabled(self, interfaces) -> None:
"""Handle link liveness disabled."""
Expand Down Expand Up @@ -739,8 +741,7 @@ def handle_link_up(self, interface):
interface.activate()
self.topo_controller.activate_interface(interface.id)
self.notify_topology_update()
with self._links_lock:
link = self._get_link_from_interface(interface)
link = self._get_link_from_interface(interface)
if not link:
return
if link.endpoint_a == interface:
Expand Down Expand Up @@ -954,8 +955,8 @@ def notify_metadata_changes(self, obj, action):
)

name = f'kytos/topology.{entities}.metadata.{action}'
event = KytosEvent(name=name, content={entity: obj,
'metadata': dict(obj.metadata)})
content = {entity: obj, 'metadata': obj.metadata.copy()}
event = KytosEvent(name=name, content=content)
self.controller.buffers.app.put(event)
log.debug(f'Metadata from {obj.id} was {action}.')

Expand Down

0 comments on commit 62e9049

Please sign in to comment.