Skip to content

Make it so that links have their own tag pool separate from interfaces#583

Open
Ktmi wants to merge 27 commits intomasterfrom
feature/tag_capable
Open

Make it so that links have their own tag pool separate from interfaces#583
Ktmi wants to merge 27 commits intomasterfrom
feature/tag_capable

Conversation

@Ktmi
Copy link

@Ktmi Ktmi commented Apr 28, 2025

Part of #554, still needs changes on topology, of_lldp, and mef_eline. This PR exists in its current form to make sure that I'm moving in the right direction.

Summary

This PR adds in a new class called TAGCapable. This implements the handling of tags for any object which inherits it. As a result, all the tag handling code was removed from Interface and Link and moved to this class. Interface and Link now inherit from TAGCapble. Additionally, this PR makes a few changes to how tags should be handled:

  • _tag_lock was renamed to tag_lock. `tag_lock is no longer implicitly held, and instead should be held by the caller, before making any change to the tags. This was done to allow multiple changes to the tags while holding the lock, rather than one at a time, as well as allowing for holding locks on multiple objects simultaneously.
  • Notifying of listeners to changes in the tags is no longer implicit, and instead needs to be done explicitly with notify_tag_listeners. This was done to allow for not sending out tag changes, if the change needs to be cancelled.
  • Changed the call signature for several functions, which were ordered as func(tag_value, tag_type='vlan') to func(tag_type, tag_value). The code we are writing now doesn't implicitly assume tag_type='vlan', and this follows a more natural ordering to the arguments.
  • Adds in a new variable default_tag_ranges and defualt_special_tags. These are used as the values that tag_ranges and special_tags will be set to when reset_tag_ranges and reset_special_tags are called.

Local Tests

Need the topology implementation finished before proper local tests can be done. But just running this in the unit tests in this, and the unit tests for other NApps, it seems to work as expected. Will need to do more testing.

End-to-End Tests

E2E results:

kytos-1  | Starting enhanced syslogd: rsyslogd.
kytos-1  | /etc/openvswitch/conf.db does not exist ... (warning).
kytos-1  | Creating empty database /etc/openvswitch/conf.db.
kytos-1  | Starting ovsdb-server.
kytos-1  | rsyslogd: error during config processing: omfile: chown for file '/var/log/syslog' failed: Operation not permitted [v8.2302.0 try https://www.rsyslog.com/e/2207 ]
kytos-1  | Configuring Open vSwitch system IDs.
kytos-1  | Starting ovs-vswitchd.
kytos-1  | Enabling remote OVSDB managers.
kytos-1  | + '[' -z '' ']'
kytos-1  | + '[' -z '' ']'
kytos-1  | + echo 'There is no NAPPS_PATH specified. Default will be used.'
kytos-1  | + NAPPS_PATH=
kytos-1  | + sed -i 's/STATS_INTERVAL = 60/STATS_INTERVAL = 7/g' /var/lib/kytos/napps/kytos/of_core/settings.py
kytos-1  | There is no NAPPS_PATH specified. Default will be used.
kytos-1  | + sed -i 's/CONSISTENCY_MIN_VERDICT_INTERVAL =.*/CONSISTENCY_MIN_VERDICT_INTERVAL = 60/g' /var/lib/kytos/napps/kytos/flow_manager/settings.py
kytos-1  | + sed -i 's/LINK_UP_TIMER = 10/LINK_UP_TIMER = 1/g' /var/lib/kytos/napps/kytos/topology/settings.py
kytos-1  | + sed -i 's/DEPLOY_EVCS_INTERVAL = 60/DEPLOY_EVCS_INTERVAL = 5/g' /var/lib/kytos/napps/kytos/mef_eline/settings.py
kytos-1  | + sed -i 's/LLDP_LOOP_ACTIONS = \["log"\]/LLDP_LOOP_ACTIONS = \["disable","log"\]/' /var/lib/kytos/napps/kytos/of_lldp/settings.py
kytos-1  | + sed -i 's/LLDP_IGNORED_LOOPS = {}/LLDP_IGNORED_LOOPS = {"00:00:00:00:00:00:00:01": \[\[4, 5\]\]}/' /var/lib/kytos/napps/kytos/of_lldp/settings.py
kytos-1  | + sed -i 's/CONSISTENCY_COOKIE_IGNORED_RANGE =.*/CONSISTENCY_COOKIE_IGNORED_RANGE = [(0xdd00000000000000, 0xdd00000000000009)]/g' /var/lib/kytos/napps/kytos/flow_manager/settings.py
kytos-1  | + sed -i 's/LIVENESS_DEAD_MULTIPLIER =.*/LIVENESS_DEAD_MULTIPLIER = 3/g' /var/lib/kytos/napps/kytos/of_lldp/settings.py
kytos-1  | + kytosd --help
kytos-1  | + sed -i s/WARNING/DEBUG/g /etc/kytos/logging.ini
kytos-1  | + sed -i s/INFO/DEBUG/g /etc/kytos/logging.ini
kytos-1  | + sed -i 's/keys: root,kytos,api_server,socket/keys: root,kytos,api_server,socket,aiokafka/' /etc/kytos/logging.ini
kytos-1  | + sed -i 's/handlers: syslog,console/handlers: syslog,console,file/g' /etc/kytos/logging.ini
kytos-1  | + echo -e '\n\n[logger_aiokafka]\nlevel: INFO\nhandlers:\nqualname: aiokafka'
kytos-1  | + echo
kytos-1  | + test -z ''
kytos-1  | + TESTS=tests/
kytos-1  | + test -z ''
kytos-1  | + RERUNS=2
kytos-1  | + python3 scripts/wait_for_mongo.py
kytos-1  | Trying to run hello command on MongoDB...
kytos-1  | Trying to run 'hello' command on MongoDB...
kytos-1  | Trying to run 'hello' command on MongoDB...
kytos-1  | Ran 'hello' command on MongoDB successfully. It's ready!
kytos-1  | + python3 scripts/setup_kafka.py
kytos-1  | Starting setup_kafka.py...
kytos-1  | Attempting to create an admin client at ['broker1:19092', 'broker2:19092', 'broker3:19092']...
kytos-1  | Admin client was successful! Attempting to validate cluster...
kytos-1  | Cluster info: {'throttle_time_ms': 0, 'brokers': [{'node_id': 1, 'host': 'broker1', 'port': 19092, 'rack': None}, {'node_id': 2, 'host': 'broker2', 'port': 19092, 'rack': None}, {'node_id': 3, 'host': 'broker3', 'port': 19092, 'rack': None}], 'cluster_id': '5L6g3nShT-eMCtK--X86sw', 'controller_id': 2}
kytos-1  | Cluster was successfully validated! Attempting to create topic 'event_logs'...
kytos-1  | Topic 'event_logs' was created! Attempting to close the admin client...
kytos-1  | Kafka admin client closed.
kytos-1  | + python3 -m pytest tests/ --reruns 2 -r fEr
kytos-1  | ============================= test session starts ==============================
kytos-1  | platform linux -- Python 3.11.2, pytest-8.4.2, pluggy-1.6.0
kytos-1  | rootdir: /
kytos-1  | configfile: pytest.ini
kytos-1  | plugins: rerunfailures-13.0, timeout-2.2.0, asyncio-1.1.0, anyio-4.3.0
kytos-1  | asyncio: mode=Mode.AUTO, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function
kytos-1  | collected 301 items
kytos-1  | 
kytos-1  | tests/test_e2e_01_kytos_startup.py ..                                    [  0%]
kytos-1  | tests/test_e2e_05_topology.py ...................                        [  6%]
kytos-1  | tests/test_e2e_06_topology.py ....                                       [  8%]
kytos-1  | tests/test_e2e_10_mef_eline.py ..........ss.....x....................... [ 21%]
kytos-1  | .                                                                        [ 22%]
kytos-1  | tests/test_e2e_11_mef_eline.py ........                                  [ 24%]
kytos-1  | tests/test_e2e_12_mef_eline.py .....Xx.                                  [ 27%]
kytos-1  | tests/test_e2e_13_mef_eline.py ....Xs.s.....Xs.s.XXxX.xxxx..X........... [ 41%]
kytos-1  | .                                                                        [ 41%]
kytos-1  | tests/test_e2e_14_mef_eline.py ......                                    [ 43%]
kytos-1  | tests/test_e2e_15_mef_eline.py ......                                    [ 45%]
kytos-1  | tests/test_e2e_16_mef_eline.py ..                                        [ 46%]
kytos-1  | tests/test_e2e_17_mef_eline.py .....                                     [ 47%]
kytos-1  | tests/test_e2e_18_mef_eline.py .....                                     [ 49%]
kytos-1  | tests/test_e2e_20_flow_manager.py ............................           [ 58%]
kytos-1  | tests/test_e2e_21_flow_manager.py ...                                    [ 59%]
kytos-1  | tests/test_e2e_22_flow_manager.py ...............                        [ 64%]
kytos-1  | tests/test_e2e_23_flow_manager.py ..............                         [ 69%]
kytos-1  | tests/test_e2e_30_of_lldp.py .R...                                       [ 70%]
kytos-1  | tests/test_e2e_31_of_lldp.py ...RRF                                      [ 72%]
kytos-1  | tests/test_e2e_32_of_lldp.py ...                                         [ 73%]
kytos-1  | tests/test_e2e_40_sdntrace.py ................                           [ 78%]
kytos-1  | tests/test_e2e_41_kytos_auth.py ........                                 [ 81%]
kytos-1  | tests/test_e2e_42_sdntrace.py ..                                         [ 81%]
kytos-1  | tests/test_e2e_50_maintenance.py ...............................         [ 92%]
kytos-1  | tests/test_e2e_60_of_multi_table.py .....                                [ 93%]
kytos-1  | tests/test_e2e_70_kytos_stats.py .........                               [ 96%]
kytos-1  | tests/test_e2e_80_pathfinder.py ss......                                 [ 99%]
kytos-1  | tests/test_e2e_90_kafka_events.py .                                      [ 99%]
kytos-1  | tests/test_e2e_95_telemtry_int.py s                                      [100%]
kytos-1  | 
kytos-1  | =================================== FAILURES ===================================
kytos-1  | ________________ TestE2EOfLLDP.test_010_liveness_intf_deletion _________________
kytos-1  | 
kytos-1  | self = <tests.test_e2e_31_of_lldp.TestE2EOfLLDP object at 0x7882e3f1ba90>
kytos-1  | 
kytos-1  |     def test_010_liveness_intf_deletion(self) -> None:
kytos-1  |         """Test liveness not loaded after intf deletion."""
kytos-1  |         polling_interval = 1
kytos-1  |         self.set_polling_time(polling_interval)
kytos-1  |         intf_id = "00:00:00:00:00:00:00:01:1"
kytos-1  |         interface_ids = [intf_id]
kytos-1  |         self.enable_link_liveness(interface_ids)
kytos-1  |     
kytos-1  |         time.sleep(polling_interval * 5)
kytos-1  |     
kytos-1  |         # Assert GET liveness/ entries are in init state
kytos-1  |         api_url = f"{KYTOS_API}/of_lldp/v1/liveness/"
kytos-1  |         response = requests.get(api_url)
kytos-1  |         data = response.json()
kytos-1  |         for entry in data["interfaces"]:
kytos-1  |             assert entry["id"] in interface_ids, entry
kytos-1  |             assert entry["status"] == "init", entry
kytos-1  |     
kytos-1  |         # Disable the intf for deletion
kytos-1  |         api_url = f'{KYTOS_API}/topology/v3/interfaces/{intf_id}/disable/'
kytos-1  |         response = requests.post(api_url)
kytos-1  |         assert response.status_code == 200, response.text
kytos-1  |     
kytos-1  |         # Deactivate the interface for deletion
kytos-1  |         self.net.net.configLinkStatus('s1', 'h11', 'down')
kytos-1  |     
kytos-1  |         api_url = f'{KYTOS_API}/topology/v3/interfaces/{intf_id}'
kytos-1  |         response = requests.delete(api_url)
kytos-1  |         assert response.status_code == 200, response.text
kytos-1  |     
kytos-1  |         # Restart the controller maintaining config
kytos-1  | >       self.restart(wait_for=15)
kytos-1  | 
kytos-1  | tests/test_e2e_31_of_lldp.py:298: 
kytos-1  | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
kytos-1  | tests/test_e2e_31_of_lldp.py:38: in restart
kytos-1  |     self.net.start_controller(clean_config=clean_config, enable_all=enable_all)
kytos-1  | tests/helpers.py:402: in start_controller
kytos-1  |     self.wait_controller_start()
kytos-1  | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
kytos-1  | 
kytos-1  | self = <tests.helpers.NetworkTest object at 0x7882c02da290>
kytos-1  | 
kytos-1  |     def wait_controller_start(self):
kytos-1  |         """Wait until controller starts according to core/status API."""
kytos-1  |         wait_count = 0
kytos-1  |         last_error = ""
kytos-1  |         while wait_count < 60:
kytos-1  |             try:
kytos-1  |                 response = requests.get('http://127.0.0.1:8181/api/kytos/core/status/', timeout=3)
kytos-1  |                 assert response.json()['response'] == 'running', response.text
kytos-1  |                 break
kytos-1  |             except Exception as exc:
kytos-1  |                 last_error = str(exc)
kytos-1  |                 time.sleep(0.5)
kytos-1  |                 wait_count += 0.5
kytos-1  |         else:
kytos-1  |             msg = f"Timeout while starting Kytos controller. Last error: {last_error}"
kytos-1  | >           raise Exception(msg)
kytos-1  | E           Exception: Timeout while starting Kytos controller. Last error: HTTPConnectionPool(host='127.0.0.1', port=8181): Read timed out. (read timeout=3)
kytos-1  | 
kytos-1  | tests/helpers.py:422: Exception
kytos-1  | ---------------------------- Captured stdout setup -----------------------------
kytos-1  | FAIL to stop kytos after 5 seconds -- Kytos pid still exists.. Force stop!
kytos-1  | ---------------------------- Captured stdout setup -----------------------------
kytos-1  | FAIL to stop kytos after 5 seconds -- Kytos pid still exists.. Force stop!
kytos-1  | =============================== warnings summary ===============================
kytos-1  | usr/local/lib/python3.11/dist-packages/kytos/core/config.py:254
kytos-1  |   /usr/local/lib/python3.11/dist-packages/kytos/core/config.py:254: UserWarning: Unknown arguments: ['tests/', '--reruns', '2', '-r', 'fEr']
kytos-1  |     warnings.warn(f"Unknown arguments: {unknown}")
kytos-1  | 
kytos-1  | tests/test_e2e_01_kytos_startup.py: 17 warnings
kytos-1  | tests/test_e2e_05_topology.py: 17 warnings
kytos-1  | tests/test_e2e_06_topology.py: 37 warnings
kytos-1  | tests/test_e2e_10_mef_eline.py: 17 warnings
kytos-1  | tests/test_e2e_11_mef_eline.py: 25 warnings
kytos-1  | tests/test_e2e_12_mef_eline.py: 17 warnings
kytos-1  | tests/test_e2e_13_mef_eline.py: 17 warnings
kytos-1  | tests/test_e2e_14_mef_eline.py: 76 warnings
kytos-1  | tests/test_e2e_15_mef_eline.py: 17 warnings
kytos-1  | tests/test_e2e_16_mef_eline.py: 17 warnings
kytos-1  | tests/test_e2e_17_mef_eline.py: 37 warnings
kytos-1  | tests/test_e2e_18_mef_eline.py: 17 warnings
kytos-1  | tests/test_e2e_20_flow_manager.py: 17 warnings
kytos-1  | tests/test_e2e_21_flow_manager.py: 17 warnings
kytos-1  | tests/test_e2e_22_flow_manager.py: 17 warnings
kytos-1  | tests/test_e2e_23_flow_manager.py: 17 warnings
kytos-1  | tests/test_e2e_30_of_lldp.py: 16 warnings
kytos-1  | tests/test_e2e_31_of_lldp.py: 16 warnings
kytos-1  | tests/test_e2e_32_of_lldp.py: 11 warnings
kytos-1  | tests/test_e2e_40_sdntrace.py: 49 warnings
kytos-1  | tests/test_e2e_41_kytos_auth.py: 17 warnings
kytos-1  | tests/test_e2e_42_sdntrace.py: 84 warnings
kytos-1  | tests/test_e2e_50_maintenance.py: 17 warnings
kytos-1  | tests/test_e2e_60_of_multi_table.py: 17 warnings
kytos-1  | tests/test_e2e_70_kytos_stats.py: 17 warnings
kytos-1  | tests/test_e2e_80_pathfinder.py: 37 warnings
kytos-1  | tests/test_e2e_90_kafka_events.py: 17 warnings
kytos-1  |   /usr/lib/python3/dist-packages/mininet/node.py:1121: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
kytos-1  |     return ( StrictVersion( cls.OVSVersion ) <
kytos-1  | 
kytos-1  | tests/test_e2e_01_kytos_startup.py: 17 warnings
kytos-1  | tests/test_e2e_05_topology.py: 17 warnings
kytos-1  | tests/test_e2e_06_topology.py: 37 warnings
kytos-1  | tests/test_e2e_10_mef_eline.py: 17 warnings
kytos-1  | tests/test_e2e_11_mef_eline.py: 25 warnings
kytos-1  | tests/test_e2e_12_mef_eline.py: 17 warnings
kytos-1  | tests/test_e2e_13_mef_eline.py: 17 warnings
kytos-1  | tests/test_e2e_14_mef_eline.py: 76 warnings
kytos-1  | tests/test_e2e_15_mef_eline.py: 17 warnings
kytos-1  | tests/test_e2e_16_mef_eline.py: 17 warnings
kytos-1  | tests/test_e2e_17_mef_eline.py: 37 warnings
kytos-1  | tests/test_e2e_18_mef_eline.py: 17 warnings
kytos-1  | tests/test_e2e_20_flow_manager.py: 17 warnings
kytos-1  | tests/test_e2e_21_flow_manager.py: 17 warnings
kytos-1  | tests/test_e2e_22_flow_manager.py: 17 warnings
kytos-1  | tests/test_e2e_23_flow_manager.py: 17 warnings
kytos-1  | tests/test_e2e_30_of_lldp.py: 16 warnings
kytos-1  | tests/test_e2e_31_of_lldp.py: 16 warnings
kytos-1  | tests/test_e2e_32_of_lldp.py: 11 warnings
kytos-1  | tests/test_e2e_40_sdntrace.py: 49 warnings
kytos-1  | tests/test_e2e_41_kytos_auth.py: 17 warnings
kytos-1  | tests/test_e2e_42_sdntrace.py: 84 warnings
kytos-1  | tests/test_e2e_50_maintenance.py: 17 warnings
kytos-1  | tests/test_e2e_60_of_multi_table.py: 17 warnings
kytos-1  | tests/test_e2e_70_kytos_stats.py: 17 warnings
kytos-1  | tests/test_e2e_80_pathfinder.py: 37 warnings
kytos-1  | tests/test_e2e_90_kafka_events.py: 17 warnings
kytos-1  |   /usr/lib/python3/dist-packages/mininet/node.py:1122: DeprecationWarning: distutils Version classes are deprecated. Use packaging.version instead.
kytos-1  |     StrictVersion( '1.10' ) )
kytos-1  | 
kytos-1  | -- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
kytos-1  | ------------------------------- start/stop times -------------------------------
kytos-1  | rerun: 0
kytos-1  | tests/test_e2e_30_of_lldp.py::TestE2EOfLLDP::test_010_disable_of_lldp: 2026-02-13,02:13:41.285613 - 2026-02-13,02:14:06.485583
kytos-1  | self = <tests.test_e2e_30_of_lldp.TestE2EOfLLDP object at 0x7882e3da1350>
kytos-1  | 
kytos-1  |     def test_010_disable_of_lldp(self):
kytos-1  |         """ Test if the disabling OF LLDP in an interface worked properly. """
kytos-1  |         self.net.start_controller(clean_config=True, enable_all=False)
kytos-1  |         self.net.wait_switches_connect()
kytos-1  |         time.sleep(5)
kytos-1  |         self.enable_all_interfaces()
kytos-1  |     
kytos-1  |         # disabling all the UNI interfaces
kytos-1  |         payload = {
kytos-1  |             "interfaces": [
kytos-1  |                 "00:00:00:00:00:00:00:01:1", "00:00:00:00:00:00:00:01:2", "00:00:00:00:00:00:00:01:4294967294",
kytos-1  |                 "00:00:00:00:00:00:00:02:1", "00:00:00:00:00:00:00:02:4294967294",
kytos-1  |                 "00:00:00:00:00:00:00:03:1", "00:00:00:00:00:00:00:03:4294967294"
kytos-1  |             ]
kytos-1  |         }
kytos-1  |         expected_interfaces = [
kytos-1  |                 "00:00:00:00:00:00:00:01:3", "00:00:00:00:00:00:00:01:4",
kytos-1  |                 "00:00:00:00:00:00:00:02:2", "00:00:00:00:00:00:00:02:3",
kytos-1  |                 "00:00:00:00:00:00:00:03:2", "00:00:00:00:00:00:00:03:3"
kytos-1  |         ]
kytos-1  |     
kytos-1  |         api_url = KYTOS_API + '/of_lldp/v1/interfaces/disable/'
kytos-1  |         response = requests.post(api_url, json=payload)
kytos-1  |         assert response.status_code == 200, response.text
kytos-1  |     
kytos-1  |         api_url = KYTOS_API + '/of_lldp/v1/interfaces/'
kytos-1  |         response = requests.get(api_url)
kytos-1  |         data = response.json()
kytos-1  |         assert set(data["interfaces"]) == set(expected_interfaces)
kytos-1  |     
kytos-1  |         h11, h12, h2, h3 = self.net.net.get('h11', 'h12', 'h2', 'h3')
kytos-1  |         rx_stats_h11 = self.get_iface_stats_rx_pkt(h11)
kytos-1  |         rx_stats_h12 = self.get_iface_stats_rx_pkt(h12)
kytos-1  |         rx_stats_h2 = self.get_iface_stats_rx_pkt(h2)
kytos-1  |         rx_stats_h3 = self.get_iface_stats_rx_pkt(h3)
kytos-1  |         time.sleep(10)
kytos-1  |         rx_stats_h11_2 = self.get_iface_stats_rx_pkt(h11)
kytos-1  |         rx_stats_h12_2 = self.get_iface_stats_rx_pkt(h12)
kytos-1  |         rx_stats_h2_2 = self.get_iface_stats_rx_pkt(h2)
kytos-1  |         rx_stats_h3_2 = self.get_iface_stats_rx_pkt(h3)
kytos-1  |     
kytos-1  | >       assert rx_stats_h11_2 == rx_stats_h11 \
kytos-1  |             and rx_stats_h12_2 == rx_stats_h12 \
kytos-1  |             and rx_stats_h2_2 == rx_stats_h2 \
kytos-1  |             and rx_stats_h3_2 == rx_stats_h3
kytos-1  | E       assert (19 == 18)
kytos-1  | 
kytos-1  | tests/test_e2e_30_of_lldp.py:127: AssertionError
kytos-1  | rerun: 0
kytos-1  | tests/test_e2e_31_of_lldp.py::TestE2EOfLLDP::test_010_liveness_intf_deletion: 2026-02-13,02:20:08.025225 - 2026-02-13,02:27:15.923321
kytos-1  | self = <tests.test_e2e_31_of_lldp.TestE2EOfLLDP object at 0x7882e3f1ba90>
kytos-1  | 
kytos-1  |     def test_010_liveness_intf_deletion(self) -> None:
kytos-1  |         """Test liveness not loaded after intf deletion."""
kytos-1  |         polling_interval = 1
kytos-1  |         self.set_polling_time(polling_interval)
kytos-1  |         intf_id = "00:00:00:00:00:00:00:01:1"
kytos-1  |         interface_ids = [intf_id]
kytos-1  |         self.enable_link_liveness(interface_ids)
kytos-1  |     
kytos-1  |         time.sleep(polling_interval * 5)
kytos-1  |     
kytos-1  |         # Assert GET liveness/ entries are in init state
kytos-1  |         api_url = f"{KYTOS_API}/of_lldp/v1/liveness/"
kytos-1  |         response = requests.get(api_url)
kytos-1  |         data = response.json()
kytos-1  |         for entry in data["interfaces"]:
kytos-1  |             assert entry["id"] in interface_ids, entry
kytos-1  |             assert entry["status"] == "init", entry
kytos-1  |     
kytos-1  |         # Disable the intf for deletion
kytos-1  |         api_url = f'{KYTOS_API}/topology/v3/interfaces/{intf_id}/disable/'
kytos-1  |         response = requests.post(api_url)
kytos-1  |         assert response.status_code == 200, response.text
kytos-1  |     
kytos-1  |         # Deactivate the interface for deletion
kytos-1  |         self.net.net.configLinkStatus('s1', 'h11', 'down')
kytos-1  |     
kytos-1  |         api_url = f'{KYTOS_API}/topology/v3/interfaces/{intf_id}'
kytos-1  |         response = requests.delete(api_url)
kytos-1  |         assert response.status_code == 200, response.text
kytos-1  |     
kytos-1  |         # Restart the controller maintaining config
kytos-1  | >       self.restart(wait_for=15)
kytos-1  | 
kytos-1  | tests/test_e2e_31_of_lldp.py:298: 
kytos-1  | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
kytos-1  | tests/test_e2e_31_of_lldp.py:38: in restart
kytos-1  |     self.net.start_controller(clean_config=clean_config, enable_all=enable_all)
kytos-1  | tests/helpers.py:402: in start_controller
kytos-1  |     self.wait_controller_start()
kytos-1  | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
kytos-1  | 
kytos-1  | self = <tests.helpers.NetworkTest object at 0x7882c02da290>
kytos-1  | 
kytos-1  |     def wait_controller_start(self):
kytos-1  |         """Wait until controller starts according to core/status API."""
kytos-1  |         wait_count = 0
kytos-1  |         last_error = ""
kytos-1  |         while wait_count < 60:
kytos-1  |             try:
kytos-1  |                 response = requests.get('http://127.0.0.1:8181/api/kytos/core/status/', timeout=3)
kytos-1  |                 assert response.json()['response'] == 'running', response.text
kytos-1  |                 break
kytos-1  |             except Exception as exc:
kytos-1  |                 last_error = str(exc)
kytos-1  |                 time.sleep(0.5)
kytos-1  |                 wait_count += 0.5
kytos-1  |         else:
kytos-1  |             msg = f"Timeout while starting Kytos controller. Last error: {last_error}"
kytos-1  | >           raise Exception(msg)
kytos-1  | E           Exception: Timeout while starting Kytos controller. Last error: HTTPConnectionPool(host='127.0.0.1', port=8181): Read timed out. (read timeout=3)
kytos-1  | 
kytos-1  | tests/helpers.py:422: Exception
kytos-1  | rerun: 1
kytos-1  | tests/test_e2e_31_of_lldp.py::TestE2EOfLLDP::test_010_liveness_intf_deletion: 2026-02-13,02:27:37.065407 - 2026-02-13,02:34:44.996798
kytos-1  | self = <tests.test_e2e_31_of_lldp.TestE2EOfLLDP object at 0x7882e3f1ba90>
kytos-1  | 
kytos-1  |     def test_010_liveness_intf_deletion(self) -> None:
kytos-1  |         """Test liveness not loaded after intf deletion."""
kytos-1  |         polling_interval = 1
kytos-1  |         self.set_polling_time(polling_interval)
kytos-1  |         intf_id = "00:00:00:00:00:00:00:01:1"
kytos-1  |         interface_ids = [intf_id]
kytos-1  |         self.enable_link_liveness(interface_ids)
kytos-1  |     
kytos-1  |         time.sleep(polling_interval * 5)
kytos-1  |     
kytos-1  |         # Assert GET liveness/ entries are in init state
kytos-1  |         api_url = f"{KYTOS_API}/of_lldp/v1/liveness/"
kytos-1  |         response = requests.get(api_url)
kytos-1  |         data = response.json()
kytos-1  |         for entry in data["interfaces"]:
kytos-1  |             assert entry["id"] in interface_ids, entry
kytos-1  |             assert entry["status"] == "init", entry
kytos-1  |     
kytos-1  |         # Disable the intf for deletion
kytos-1  |         api_url = f'{KYTOS_API}/topology/v3/interfaces/{intf_id}/disable/'
kytos-1  |         response = requests.post(api_url)
kytos-1  |         assert response.status_code == 200, response.text
kytos-1  |     
kytos-1  |         # Deactivate the interface for deletion
kytos-1  |         self.net.net.configLinkStatus('s1', 'h11', 'down')
kytos-1  |     
kytos-1  |         api_url = f'{KYTOS_API}/topology/v3/interfaces/{intf_id}'
kytos-1  |         response = requests.delete(api_url)
kytos-1  |         assert response.status_code == 200, response.text
kytos-1  |     
kytos-1  |         # Restart the controller maintaining config
kytos-1  | >       self.restart(wait_for=15)
kytos-1  | 
kytos-1  | tests/test_e2e_31_of_lldp.py:298: 
kytos-1  | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
kytos-1  | tests/test_e2e_31_of_lldp.py:38: in restart
kytos-1  |     self.net.start_controller(clean_config=clean_config, enable_all=enable_all)
kytos-1  | tests/helpers.py:402: in start_controller
kytos-1  |     self.wait_controller_start()
kytos-1  | _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
kytos-1  | 
kytos-1  | self = <tests.helpers.NetworkTest object at 0x7882c02da290>
kytos-1  | 
kytos-1  |     def wait_controller_start(self):
kytos-1  |         """Wait until controller starts according to core/status API."""
kytos-1  |         wait_count = 0
kytos-1  |         last_error = ""
kytos-1  |         while wait_count < 60:
kytos-1  |             try:
kytos-1  |                 response = requests.get('http://127.0.0.1:8181/api/kytos/core/status/', timeout=3)
kytos-1  |                 assert response.json()['response'] == 'running', response.text
kytos-1  |                 break
kytos-1  |             except Exception as exc:
kytos-1  |                 last_error = str(exc)
kytos-1  |                 time.sleep(0.5)
kytos-1  |                 wait_count += 0.5
kytos-1  |         else:
kytos-1  |             msg = f"Timeout while starting Kytos controller. Last error: {last_error}"
kytos-1  | >           raise Exception(msg)
kytos-1  | E           Exception: Timeout while starting Kytos controller. Last error: HTTPConnectionPool(host='127.0.0.1', port=8181): Read timed out. (read timeout=3)
kytos-1  | 
kytos-1  | tests/helpers.py:422: Exception
kytos-1  | tests/test_e2e_31_of_lldp.py::TestE2EOfLLDP::test_010_liveness_intf_deletion: 2026-02-13,02:35:06.127242 - 2026-02-13,02:42:14.019770
kytos-1  | =========================== rerun test summary info ============================
kytos-1  | RERUN tests/test_e2e_30_of_lldp.py::TestE2EOfLLDP::test_010_disable_of_lldp
kytos-1  | RERUN tests/test_e2e_31_of_lldp.py::TestE2EOfLLDP::test_010_liveness_intf_deletion
kytos-1  | RERUN tests/test_e2e_31_of_lldp.py::TestE2EOfLLDP::test_010_liveness_intf_deletion
kytos-1  | =========================== short test summary info ============================
kytos-1  | FAILED tests/test_e2e_31_of_lldp.py::TestE2EOfLLDP::test_010_liveness_intf_deletion
kytos-1  | = 1 failed, 277 passed, 9 skipped, 7 xfailed, 7 xpassed, 1355 warnings, 3 rerun in 13730.45s (3:48:50) =

�[Kkytos-1 exited with code 1

@Ktmi Ktmi requested a review from a team as a code owner April 28, 2025 14:20
@viniarck
Copy link
Member

viniarck commented Apr 29, 2025

still needs changes on topology

Not ready for E2E tests.

That's fine @Ktmi as you progress. I'll recommend you leave it as a draft though in the meantime. When it's ready for review, and the issue discussion is ready too let me know.

@Ktmi Ktmi marked this pull request as draft April 29, 2025 16:09
@Ktmi Ktmi force-pushed the feature/tag_capable branch from 6631803 to 53254ce Compare July 22, 2025 22:17
@Ktmi Ktmi force-pushed the feature/tag_capable branch from 7aa75bf to 64d445e Compare August 13, 2025 18:44
@Ktmi
Copy link
Author

Ktmi commented Aug 14, 2025

I noticed some potential inconsistencies with locks in topology and since the topology PR which relies on this uses locks heavily, I added some more locks in this PR to help fix the issue on the topology side.

@Ktmi Ktmi marked this pull request as ready for review August 19, 2025 15:41
@Ktmi Ktmi marked this pull request as draft August 22, 2025 17:09
@Ktmi Ktmi marked this pull request as ready for review January 5, 2026 14:27
Copy link
Member

@viniarck viniarck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've just done partial review but it was meant for this other PR

@viniarck viniarck self-requested a review January 5, 2026 23:13
@viniarck
Copy link
Member

viniarck commented Jan 5, 2026

I've just done partial review but it was meant for this other PR

I'll review this one here later

Copy link
Member

@viniarck viniarck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great how it's evolving @Ktmi, just done a partial review

Check out the comments. Also changelog needs to be updated

Let me know when you need a final review

@Ktmi Ktmi force-pushed the feature/tag_capable branch from 1a4b61a to b746863 Compare January 14, 2026 21:24
@Ktmi Ktmi force-pushed the feature/tag_capable branch from a5d39e3 to a83382e Compare January 15, 2026 14:15
- Each ``Link`` now has a ``threading.Lock`` to perform any change or check on its attributes.
- Kytos shutdown will now wait for every NApp to shutdown completely.
- ``Links`` now have a separate tag pool from ``Interfaces``.
- ``Interfaces`` should now use the lock of their ``Switch`` to maintain consistency.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ktmi we also need to make it explicit here that's a breaking changing and NApps who used to use the related interface old tags method need to refactor as you've done for our core NApps, and then in the release notes you just mention that's expected for developers to refactor if they have other non core NApps.

Note: it's probably not worth trying to maintain deprecation compatibility due to extra effort it'd require in terms of code maintenance.

Copy link
Member

@viniarck viniarck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Another partial review, also last comment hasn't been fully addressed

@@ -94,9 +94,8 @@ def get_validated_tags(
def range_intersection(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as prior comment, unless we're aiming for other major improvements, I'm not sure if the refactor improves much readability here. It's harder to follow, and consequently maintain the code. Can you revert this part too? And use the old method and its signature?

Improvements welcome in the part in the future, but we have to have a clear goal of the main benefits, as it is, I'm not willing to take the risk.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants