Skip to content

Commit

Permalink
Merge pull request #502 from kytos-ng/event/flows_deepcopy
Browse files Browse the repository at this point in the history
Events with flows are deep copied
  • Loading branch information
viniarck authored Aug 26, 2024
2 parents 8932c80 + b73371e commit 89a60e3
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 8 deletions.
8 changes: 8 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@ All notable changes to the MEF_ELine NApp will be documented in this file.
[UNRELEASED] - Under development
********************************

[2024.1.2] - 2024-08-26
***********************

Fixed
=====
- Flows sent through an event are deep copies, meaning these can be modified from a subscriber NApp without affecting other subscribers.
- Added exception handler when getting path for disjointed paths.

[2024.1.1] - 2024-08-23
***********************

Expand Down
2 changes: 1 addition & 1 deletion kytos.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"username": "kytos",
"name": "mef_eline",
"description": "NApp to provision circuits from user request",
"version": "2024.1.1",
"version": "2024.1.2",
"napp_dependencies": ["kytos/flow_manager", "kytos/pathfinder", "amlight/sndtrace_cp"],
"license": "MIT",
"tags": [],
Expand Down
5 changes: 3 additions & 2 deletions main.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import time
import traceback
from collections import defaultdict
from copy import deepcopy
from threading import Lock
from typing import Optional

Expand Down Expand Up @@ -875,7 +876,7 @@ def handle_link_down(self, event):

if failover_event_contents:
emit_event(self.controller, "failover_link_down",
content=failover_event_contents)
content=deepcopy(failover_event_contents))
send_flow_mods_event(self.controller, switch_flows, 'install')

for evc in evcs_normal:
Expand Down Expand Up @@ -970,7 +971,7 @@ def handle_cleanup_evcs_old_path(self, event):
total_flows = merge_flow_dicts(removed_flows, total_flows)
content = map_evc_event_content(
evc,
removed_flows=removed_flows,
removed_flows=deepcopy(removed_flows),
current_path=evc.current_path.as_dict(),
)
event_contents[evc.id] = content
Expand Down
4 changes: 2 additions & 2 deletions models/evc.py
Original file line number Diff line number Diff line change
Expand Up @@ -964,8 +964,8 @@ def setup_failover_path(self):
emit_event(self._controller, "failover_deployed", content={
self.id: map_evc_event_content(
self,
flows=out_new_flows,
removed_flows=out_removed_flows,
flows=deepcopy(out_new_flows),
removed_flows=deepcopy(out_removed_flows),
error_reason=reason,
current_path=self.current_path.as_dict(),
)
Expand Down
12 changes: 10 additions & 2 deletions models/path.py
Original file line number Diff line number Diff line change
Expand Up @@ -227,8 +227,16 @@ def get_disjoint_paths(
if not unwanted_links:
return None

paths = cls.get_paths(circuit, max_paths=cutoff,
**circuit.secondary_constraints)
try:
paths = cls.get_paths(circuit, max_paths=cutoff,
**circuit.secondary_constraints)
except PathFinderException as err:
log.error(
f"{circuit} failed to get disjointed paths from pathfinder."
f" Error {err}"
)
return None

for path in paths:
links_n, switches_n = cls.get_shared_components(
path, unwanted_links, unwanted_switches
Expand Down
30 changes: 29 additions & 1 deletion tests/unit/models/test_path.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from unittest.mock import call, patch, Mock, MagicMock
import pytest
from napps.kytos.mef_eline import settings

from httpx import TimeoutException
from kytos.core.common import EntityStatus
from kytos.core.link import Link
from kytos.core.switch import Switch
Expand Down Expand Up @@ -849,6 +849,34 @@ def test_get_disjoint_paths_simple_evc(self, mock_httpx_post):
[link.id for link in expected_disjoint_path]
)

@patch("httpx.post")
@patch("napps.kytos.mef_eline.models.path.log")
@patch("time.sleep")
def test_get_disjoint_paths_error(self, _, mock_log, mock_post):
"""Test get_disjoint_paths"""
mock_post.side_effect = TimeoutException('mock')
unwanted_path = [
Link(
id_to_interface_mock("00:00:00:00:00:00:00:01:4"),
id_to_interface_mock("00:00:00:00:00:00:00:03:3")
),
]
evc = MagicMock()
evc.secondary_constraints = {
"spf_attribute": "hop",
"spf_max_path_cost": 20,
"mandatory_metrics": {
"ownership": "red"
}
}
evc.uni_a.interface.id = "1"
evc.uni_z.interface.id = "2"
evc.uni_a.interface.switch.id = "00:00:00:00:00:00:00:01"
evc.uni_z.interface.switch.id = "00:00:00:00:00:00:00:05"
path = DynamicPathManager.get_disjoint_paths(evc, unwanted_path)
assert len(list(path)) == 0
assert mock_log.error.call_count == 1

def test_get_shared_components(self):
"""Test get_shared_components"""
mock_path = {"hops": [
Expand Down

0 comments on commit 89a60e3

Please sign in to comment.