From a86d82b40852ec3a45c9a8783f3508e87ce2ebee Mon Sep 17 00:00:00 2001 From: jhughesbiot Date: Fri, 5 Apr 2024 14:32:36 -0600 Subject: [PATCH 1/2] Monitor device interface during monitor period and cancel testrun if disconnected --- framework/python/src/core/testrun.py | 1 + framework/python/src/net_orc/ip_control.py | 7 +++++++ .../python/src/net_orc/network_orchestrator.py | 15 +++++++++++++-- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/framework/python/src/core/testrun.py b/framework/python/src/core/testrun.py index 2c62108ee..d77458c81 100644 --- a/framework/python/src/core/testrun.py +++ b/framework/python/src/core/testrun.py @@ -408,6 +408,7 @@ def _device_stable(self, mac_addr): # Do not continue testing if Testrun has cancelled during monitor phase if self.get_session().get_status() == 'Cancelled': + self._stop_network() return LOGGER.info(f'Device with mac address {mac_addr} is ready for testing.') diff --git a/framework/python/src/net_orc/ip_control.py b/framework/python/src/net_orc/ip_control.py index 5c9f86d18..1eeafc1a9 100644 --- a/framework/python/src/net_orc/ip_control.py +++ b/framework/python/src/net_orc/ip_control.py @@ -41,6 +41,13 @@ def add_namespace(self, namespace): success = util.run_command('ip netns add ' + namespace) return success + def check_interface_status(self, interface_name): + output = util.run_command(cmd=f'ip link show {interface_name}',output=True) + if 'state DOWN ' in output[0]: + return False + else: + return True + def delete_link(self, interface_name): """Delete an ip link""" success = util.run_command('ip link delete ' + interface_name) diff --git a/framework/python/src/net_orc/network_orchestrator.py b/framework/python/src/net_orc/network_orchestrator.py index 90dce8500..ed4e77350 100644 --- a/framework/python/src/net_orc/network_orchestrator.py +++ b/framework/python/src/net_orc/network_orchestrator.py @@ -16,7 +16,7 @@ import ipaddress import json import os -from scapy.all import sniff, wrpcap, BOOTP +from scapy.all import sniff, wrpcap, BOOTP, AsyncSniffer import shutil import subprocess import sys @@ -243,11 +243,22 @@ def _start_device_monitor(self, device): LOGGER.info(f'Monitoring device with mac addr {device.mac_addr} ' f'for {str(self._session.get_monitor_period())} seconds') + + device_runtime_dir = os.path.join(RUNTIME_DIR, TEST_DIR, device.mac_addr.replace(':', '')) - packet_capture = sniff(iface=self._session.get_device_interface(), + sniffer = AsyncSniffer(iface=self._session.get_device_interface(), timeout=self._session.get_monitor_period()) + sniffer.start() + + while sniffer.running: + if not self._ip_ctrl.check_interface_status(self._session.get_device_interface()): + self._session.set_status('Cancelled') + sniffer.stop() + LOGGER.error('Device interface disconnected, cancelling Testrun') + + packet_capture = sniffer.results wrpcap(os.path.join(device_runtime_dir, 'monitor.pcap'), packet_capture) self._monitor_in_progress = False From 7349c3ac21ab1b7f0d1a001103e36a15a5e38311 Mon Sep 17 00:00:00 2001 From: jhughesbiot Date: Mon, 8 Apr 2024 15:48:35 -0600 Subject: [PATCH 2/2] pylint cleanup --- .../src/net_orc/network_orchestrator.py | 42 +++++++++---------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/framework/python/src/net_orc/network_orchestrator.py b/framework/python/src/net_orc/network_orchestrator.py index ed4e77350..351a0715c 100644 --- a/framework/python/src/net_orc/network_orchestrator.py +++ b/framework/python/src/net_orc/network_orchestrator.py @@ -47,8 +47,7 @@ class NetworkOrchestrator: """Manage and controls a virtual testing network.""" - def __init__(self, - session): + def __init__(self, session): self._session = session self._monitor_in_progress = False @@ -74,12 +73,12 @@ def start(self): shutil.rmtree(os.path.join(os.getcwd(), NET_DIR), ignore_errors=True) # Cleanup any old config files test files - conf_runtime_dir = os.path.join(RUNTIME_DIR,'conf') + conf_runtime_dir = os.path.join(RUNTIME_DIR, 'conf') shutil.rmtree(conf_runtime_dir, ignore_errors=True) os.makedirs(conf_runtime_dir, exist_ok=True) # Copy the system config file to the runtime directory - system_conf_runtime = os.path.join(conf_runtime_dir,'system.json') + system_conf_runtime = os.path.join(conf_runtime_dir, 'system.json') with open(system_conf_runtime, 'w', encoding='utf-8') as f: json.dump(self.get_session().get_config(), f, indent=2) @@ -199,7 +198,7 @@ def _device_discovered(self, mac_addr): wrpcap(os.path.join(device_runtime_dir, 'startup.pcap'), packet_capture) # Copy the device config file to the runtime directory - runtime_device_conf = os.path.join(device_runtime_dir,'device_config.json') + runtime_device_conf = os.path.join(device_runtime_dir, 'device_config.json') with open(runtime_device_conf, 'w', encoding='utf-8') as f: json.dump(self._session.get_target_device().to_config_json(), f, indent=2) @@ -243,8 +242,6 @@ def _start_device_monitor(self, device): LOGGER.info(f'Monitoring device with mac addr {device.mac_addr} ' f'for {str(self._session.get_monitor_period())} seconds') - - device_runtime_dir = os.path.join(RUNTIME_DIR, TEST_DIR, device.mac_addr.replace(':', '')) @@ -253,7 +250,8 @@ def _start_device_monitor(self, device): sniffer.start() while sniffer.running: - if not self._ip_ctrl.check_interface_status(self._session.get_device_interface()): + if not self._ip_ctrl.check_interface_status( + self._session.get_device_interface()): self._session.set_status('Cancelled') sniffer.stop() LOGGER.error('Device interface disconnected, cancelling Testrun') @@ -493,20 +491,19 @@ def _start_network_service(self, net_module): try: client = docker.from_env() net_module.container = client.containers.run( - net_module.image_name, - auto_remove=True, - cap_add=['NET_ADMIN'], - name=net_module.container_name, - hostname=net_module.container_name, - network=PRIVATE_DOCKER_NET, - privileged=True, - detach=True, - mounts=net_module.mounts, - environment={ - 'TZ': self.get_session().get_timezone(), - 'HOST_USER': util.get_host_user() - } - ) + net_module.image_name, + auto_remove=True, + cap_add=['NET_ADMIN'], + name=net_module.container_name, + hostname=net_module.container_name, + network=PRIVATE_DOCKER_NET, + privileged=True, + detach=True, + mounts=net_module.mounts, + environment={ + 'TZ': self.get_session().get_timezone(), + 'HOST_USER': util.get_host_user() + }) except docker.errors.ContainerError as error: LOGGER.error('Container run error') LOGGER.error(error) @@ -734,6 +731,7 @@ def restore_net(self): def get_session(self): return self._session + class NetworkModule: """Define all the properties of a Network Module"""