From 3183393dd6530a0105851b5a9f5323a528076394 Mon Sep 17 00:00:00 2001 From: gretelliz Date: Mon, 20 Feb 2023 09:48:04 -0500 Subject: [PATCH 1/6] avoid returning an empty list with /traces endpoint --- main.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/main.py b/main.py index e55d3e2..a555ef2 100644 --- a/main.py +++ b/main.py @@ -77,10 +77,11 @@ def get_traces(self): continue list_ready.append(entry) dpid = entry['dpid'] - if dpid not in results: - results[dpid] = [] result = prepare_list_json(self.tracepath(entry, stored_flows)) - results[dpid].append(result) + if result: + if dpid not in results: + results[dpid] = [] + results[dpid].append(result) return jsonify(results) def tracepath(self, entries, stored_flows): From dd8f49521102cfb93a7368cceb3200638d5e3c79 Mon Sep 17 00:00:00 2001 From: gretelliz Date: Mon, 20 Feb 2023 13:53:18 -0500 Subject: [PATCH 2/6] Change output of bulk /traces --- main.py | 17 ++--- openapi.yml | 6 +- tests/unit/test_main.py | 136 ++------------------------------------- tests/unit/test_utils.py | 2 +- utils.py | 10 ++- 5 files changed, 22 insertions(+), 149 deletions(-) diff --git a/main.py b/main.py index a555ef2..5cdbeb7 100644 --- a/main.py +++ b/main.py @@ -13,7 +13,7 @@ from napps.amlight.sdntrace_cp.utils import (convert_entries, convert_list_entries, find_endpoint, get_stored_flows, - prepare_json, prepare_list_json) + prepare_json) class Main(KytosNApp): @@ -70,19 +70,10 @@ def get_traces(self): entries = request.get_json() entries = convert_list_entries(entries) stored_flows = get_stored_flows() - results = {} - list_ready = [] + results = [] for entry in entries: - if entry in list_ready: - continue - list_ready.append(entry) - dpid = entry['dpid'] - result = prepare_list_json(self.tracepath(entry, stored_flows)) - if result: - if dpid not in results: - results[dpid] = [] - results[dpid].append(result) - return jsonify(results) + results.append(self.tracepath(entry, stored_flows)) + return jsonify(prepare_json(results)) def tracepath(self, entries, stored_flows): """Trace a path for a packet represented by entries.""" diff --git a/openapi.yml b/openapi.yml index e8c3bab..d9ac8c8 100644 --- a/openapi.yml +++ b/openapi.yml @@ -248,8 +248,8 @@ paths: schema: type: object properties: - switch: - type: array + result: + type: array items: type: array items: @@ -279,4 +279,4 @@ paths: vlan: type: integer description: VLAN ID - example: 100 + example: 100 \ No newline at end of file diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py index 6beab55..d0ac6e8 100644 --- a/tests/unit/test_main.py +++ b/tests/unit/test_main.py @@ -432,7 +432,7 @@ def test_get_traces(self, mock_stored_flows): url, data=json.dumps(payload), content_type="application/json" ) current_data = json.loads(response.data) - result1 = current_data["00:00:00:00:00:00:00:01"] + result1 = current_data["result"] assert len(result1) == 1 assert len(result1[0]) == 1 @@ -490,142 +490,18 @@ def test_traces(self, mock_stored_flows): url, data=json.dumps(payload), content_type="application/json" ) current_data = json.loads(response.data) - result1 = current_data["00:00:00:00:00:00:00:01"] - result2 = current_data["00:00:00:00:00:00:00:02"] - - assert result1[0][0]["dpid"] == "00:00:00:00:00:00:00:01" - assert result1[0][0]["port"] == 1 - assert result1[0][0]["type"] == "starting" - assert result1[0][0]["vlan"] == 100 - assert result1[0][0]["out"] == {"port": 2, "vlan": 100} - - assert result2[0][0]["dpid"] == "00:00:00:00:00:00:00:02" - assert result2[0][0]["port"] == 1 - assert result2[0][0]["type"] == "starting" - assert result2[0][0]["vlan"] == 100 - assert result2[0][0]["out"] == {"port": 2, "vlan": 100} - - @patch("napps.amlight.sdntrace_cp.main.get_stored_flows") - def test_traces_same_switch(self, mock_stored_flows): - """Test traces rest call for two traces with samw switches.""" - api = get_test_client(get_controller_mock(), self.napp) - url = f"{self.server_name_url}/traces/" - - payload = [ - { - "trace": { - "switch": { - "dpid": "00:00:00:00:00:00:00:01", - "in_port": 1 - }, - "eth": {"dl_vlan": 100}, - } - }, - { - "trace": { - "switch": { - "dpid": "00:00:00:00:00:00:00:01", - "in_port": 2 - }, - "eth": {"dl_vlan": 100}, - } - } - ] - - stored_flow = { - "id": 1, - "flow": { - "table_id": 0, - "cookie": 84114964, - "hard_timeout": 0, - "idle_timeout": 0, - "priority": 10, - "match": {"dl_vlan": 100}, - "actions": [{"action_type": "output", "port": 3}], - } - } - - mock_stored_flows.return_value = { - "00:00:00:00:00:00:00:01": [stored_flow] - } - - response = api.put( - url, data=json.dumps(payload), content_type="application/json" - ) - current_data = json.loads(response.data) - result = current_data["00:00:00:00:00:00:00:01"] + result = current_data["result"] - assert len(current_data) == 1 assert len(result) == 2 - assert len(result[0]) == 1 - assert len(result[1]) == 1 assert result[0][0]["dpid"] == "00:00:00:00:00:00:00:01" assert result[0][0]["port"] == 1 assert result[0][0]["type"] == "starting" assert result[0][0]["vlan"] == 100 - assert result[0][0]["out"] == {"port": 3, "vlan": 100} + assert result[0][0]["out"] == {"port": 2, "vlan": 100} - assert result[1][0]["dpid"] == "00:00:00:00:00:00:00:01" - assert result[1][0]["port"] == 2 + assert result[1][0]["dpid"] == "00:00:00:00:00:00:00:02" + assert result[1][0]["port"] == 1 assert result[1][0]["type"] == "starting" assert result[1][0]["vlan"] == 100 - assert result[1][0]["out"] == {"port": 3, "vlan": 100} - - @patch("napps.amlight.sdntrace_cp.main.get_stored_flows") - def test_traces_twice(self, mock_stored_flows): - """Test traces rest call for two equal traces.""" - api = get_test_client(get_controller_mock(), self.napp) - url = f"{self.server_name_url}/traces/" - - payload = [ - { - "trace": { - "switch": { - "dpid": "00:00:00:00:00:00:00:01", - "in_port": 1 - }, - "eth": {"dl_vlan": 100}, - } - }, - { - "trace": { - "switch": { - "dpid": "00:00:00:00:00:00:00:01", - "in_port": 1 - }, - "eth": {"dl_vlan": 100}, - } - } - ] - stored_flow = { - "id": 1, - "flow": { - "table_id": 0, - "cookie": 84114964, - "hard_timeout": 0, - "idle_timeout": 0, - "priority": 10, - "match": {"dl_vlan": 100, "in_port": 1}, - "actions": [{"action_type": "output", "port": 2}], - } - } - - mock_stored_flows.return_value = { - "00:00:00:00:00:00:00:01": [stored_flow] - } - - response = api.put( - url, data=json.dumps(payload), content_type="application/json" - ) - current_data = json.loads(response.data) - result = current_data["00:00:00:00:00:00:00:01"] - - assert len(current_data) == 1 - assert len(result) == 1 - - assert result[0][0]["dpid"] == "00:00:00:00:00:00:00:01" - assert result[0][0]["port"] == 1 - assert result[0][0]["type"] == "starting" - assert result[0][0]["vlan"] == 100 - assert result[0][0]["out"] == {"port": 2, "vlan": 100} + assert result[1][0]["out"] == {"port": 2, "vlan": 100} diff --git a/tests/unit/test_utils.py b/tests/unit/test_utils.py index b2534d2..a4a4a5b 100644 --- a/tests/unit/test_utils.py +++ b/tests/unit/test_utils.py @@ -128,7 +128,7 @@ def test_prepare_list_json(self): } trace_result.append(trace_step) - result = utils.prepare_list_json(trace_result) + result = utils._prepare_json(trace_result) self.assertEqual( result, [ diff --git a/utils.py b/utils.py index 02ddf71..11ed45f 100644 --- a/utils.py +++ b/utils.py @@ -58,7 +58,7 @@ def find_endpoint(switch, port): return None -def prepare_list_json(trace_result): +def _prepare_json(trace_result): """Prepare return list of json for REST call.""" result = [] for trace_step in trace_result: @@ -70,7 +70,13 @@ def prepare_list_json(trace_result): def prepare_json(trace_result): """Prepare return json for REST call.""" - return {'result': prepare_list_json(trace_result)} + result = [] + if trace_result and isinstance(trace_result[0], list): + for trace in trace_result: + result.append(_prepare_json(trace)) + else: + result = _prepare_json(trace_result) + return {'result': result} def format_result(trace): From df46ed53b7e0590f2fe08ea2ea290d3e26ac6daf Mon Sep 17 00:00:00 2001 From: gretelliz Date: Wed, 22 Feb 2023 12:59:31 -0500 Subject: [PATCH 3/6] Update for new version of PUT /traces --- main.py | 17 ++++++++++++----- utils.py | 2 +- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/main.py b/main.py index 5cdbeb7..9bc4471 100644 --- a/main.py +++ b/main.py @@ -83,18 +83,19 @@ def tracepath(self, entries, stored_flows): trace_type = 'starting' do_trace = True while do_trace: + if 'dpid' not in entries or 'in_port' not in entries: + break trace_step = {'in': {'dpid': entries['dpid'], 'port': entries['in_port'], 'time': str(datetime.now()), 'type': trace_type}} if 'dl_vlan' in entries: trace_step['in'].update({'vlan': entries['dl_vlan'][-1]}) + switch = self.controller.get_switch_by_dpid(entries['dpid']) - if (switch is None) or \ - (switch.dpid not in stored_flows): - result = None - else: - result = self.trace_step(switch, entries, stored_flows) + if not switch: + break + result = self.trace_step(switch, entries, stored_flows) if result: out = {'port': result['out_port']} if 'dl_vlan' in result['entries']: @@ -106,6 +107,7 @@ def tracepath(self, entries, stored_flows): next_step = {'dpid': result['dpid'], 'port': result['in_port']} if self.has_loop(next_step, trace_result): + # Loop do_trace = False else: entries = result['entries'] @@ -113,8 +115,11 @@ def tracepath(self, entries, stored_flows): entries['in_port'] = result['in_port'] trace_type = 'trace' else: + if trace_type != 'starting': + trace_step['in']['type'] = 'last' do_trace = False else: + # Incomplete break trace_result.append(trace_step) self.traces.update({ @@ -196,6 +201,8 @@ def match_flows(self, switch, args, stored_flows, many=True): :return: If many, the list of matched flows, or the matched flow """ response = [] + if switch.dpid not in stored_flows: + return None try: for flow in stored_flows[switch.dpid]: match = Main.do_match(flow, args) diff --git a/utils.py b/utils.py index 11ed45f..2d617a1 100644 --- a/utils.py +++ b/utils.py @@ -59,7 +59,7 @@ def find_endpoint(switch, port): def _prepare_json(trace_result): - """Prepare return list of json for REST call.""" + """Auxiliar function to return the json for REST call.""" result = [] for trace_step in trace_result: result.append(trace_step['in']) From 750cffdae4aa56c0bef27679052cc61c81f5b8bb Mon Sep 17 00:00:00 2001 From: gretelliz Date: Fri, 24 Feb 2023 13:40:04 -0500 Subject: [PATCH 4/6] Update CHANGELOG --- CHANGELOG.rst | 13 +++++++++++++ main.py | 3 +-- tests/unit/test_main.py | 8 ++++---- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index dba418e..eeaf844 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,19 @@ All notable changes to the sdntrace_cp NApp will be documented in this file. [UNRELEASED] - Under development ******************************** +Added +===== + +Changed +======= +- ``PUT /traces`` will return the results in order, without aggregating them by `dpid`. Also, failed traces are not omitted. + +Removed +======= + +Fixed +===== + [2022.3.0] - 2022-12-15 *********************** diff --git a/main.py b/main.py index 9bc4471..65f2e0a 100644 --- a/main.py +++ b/main.py @@ -115,8 +115,7 @@ def tracepath(self, entries, stored_flows): entries['in_port'] = result['in_port'] trace_type = 'trace' else: - if trace_type != 'starting': - trace_step['in']['type'] = 'last' + trace_step['in']['type'] = 'last' do_trace = False else: # Incomplete diff --git a/tests/unit/test_main.py b/tests/unit/test_main.py index d0ac6e8..de5334c 100644 --- a/tests/unit/test_main.py +++ b/tests/unit/test_main.py @@ -388,7 +388,7 @@ def test_trace(self, mock_stored_flows): assert len(result) == 1 assert result[0]["dpid"] == "00:00:00:00:00:00:00:01" assert result[0]["port"] == 1 - assert result[0]["type"] == "starting" + assert result[0]["type"] == "last" assert result[0]["vlan"] == 100 assert result[0]["out"] == {"port": 2, "vlan": 200} @@ -438,7 +438,7 @@ def test_get_traces(self, mock_stored_flows): assert len(result1[0]) == 1 assert result1[0][0]["dpid"] == "00:00:00:00:00:00:00:01" assert result1[0][0]["port"] == 1 - assert result1[0][0]["type"] == "starting" + assert result1[0][0]["type"] == "last" assert result1[0][0]["vlan"] == 100 assert result1[0][0]["out"] == {"port": 2} @@ -496,12 +496,12 @@ def test_traces(self, mock_stored_flows): assert result[0][0]["dpid"] == "00:00:00:00:00:00:00:01" assert result[0][0]["port"] == 1 - assert result[0][0]["type"] == "starting" + assert result[0][0]["type"] == "last" assert result[0][0]["vlan"] == 100 assert result[0][0]["out"] == {"port": 2, "vlan": 100} assert result[1][0]["dpid"] == "00:00:00:00:00:00:00:02" assert result[1][0]["port"] == 1 - assert result[1][0]["type"] == "starting" + assert result[1][0]["type"] == "last" assert result[1][0]["vlan"] == 100 assert result[1][0]["out"] == {"port": 2, "vlan": 100} From 7c9ae7795469e152021c9f05b2584dace9427657 Mon Sep 17 00:00:00 2001 From: gretelliz Date: Fri, 24 Feb 2023 14:46:29 -0500 Subject: [PATCH 5/6] update version --- CHANGELOG.rst | 3 +++ kytos.json | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index eeaf844..8dd99e4 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -6,6 +6,9 @@ All notable changes to the sdntrace_cp NApp will be documented in this file. [UNRELEASED] - Under development ******************************** +[2022.3.1] - 2023-02-24 +*********************** + Added ===== diff --git a/kytos.json b/kytos.json index 1c5648d..efed426 100644 --- a/kytos.json +++ b/kytos.json @@ -3,7 +3,7 @@ "username": "amlight", "name": "sdntrace_cp", "description": "Run tracepaths on OpenFlow in the Control Plane", - "version": "2022.3.0", + "version": "2022.3.1", "napp_dependencies": [], "license": "MIT", "tags": [], From 201ea8f42ac61cf8f97d804a3435ccaa243801d0 Mon Sep 17 00:00:00 2001 From: Vinicius Arcanjo Date: Mon, 27 Feb 2023 11:27:05 -0300 Subject: [PATCH 6/6] Removed extra sections from changelog.rst --- CHANGELOG.rst | 9 --------- 1 file changed, 9 deletions(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 8dd99e4..a1bad93 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -9,19 +9,10 @@ All notable changes to the sdntrace_cp NApp will be documented in this file. [2022.3.1] - 2023-02-24 *********************** -Added -===== - Changed ======= - ``PUT /traces`` will return the results in order, without aggregating them by `dpid`. Also, failed traces are not omitted. -Removed -======= - -Fixed -===== - [2022.3.0] - 2022-12-15 ***********************