diff --git a/framework/python/src/common/models.py b/framework/python/src/common/models.py index ec1b19911..73057629c 100644 --- a/framework/python/src/common/models.py +++ b/framework/python/src/common/models.py @@ -43,7 +43,7 @@ class Device(): test_modules: Dict = field(default_factory=dict) ip_addr: str = None firmware: str = None - kernel: str = None + kernel: str = '' device_folder: str = None reports: List[TestReport] = field(default_factory=list) max_device_reports: int = None diff --git a/framework/python/src/common/util.py b/framework/python/src/common/util.py index 3ef8827dc..2db7113fb 100644 --- a/framework/python/src/common/util.py +++ b/framework/python/src/common/util.py @@ -153,3 +153,34 @@ def diff_dicts(d1: t.Dict[t.Any, t.Any], d2: t.Dict[t.Any, t.Any]) -> t.Dict: if items_added: diff['items_added'] = items_added return diff + + +def get_device_os_ssh(ip: str) -> str: + """Attempts to determine the OS of a device via SSH""" + try: + cmd = f'timeout 10 docker exec tr-ct-gateway nc -v -w 2 {ip} 22' + command_result = run_command(cmd, output=True, timeout=10) + if isinstance(command_result, tuple): + output, _ = command_result + if output: + return output.rsplit(' ', maxsplit=1)[-1].strip() + return '' + except Exception as e: + LOGGER.error(f'Error determining device OS via SSH: {e}') + return '' + +def get_device_os_nmap(ip: str) -> str: + """Attempts to determine the OS of a device via Nmap""" + try: + cmd = f'docker exec tr-ct-gateway nmap -Pn -O -F -T4 --max-retries 1 {ip}' + command_result = run_command(cmd, output=True, timeout=10) + if isinstance(command_result, tuple): + output, _ = command_result + if output: + for line in output.splitlines(): + if 'OS details:' in line: + return line.split('OS details:')[1].strip() + return '' + except Exception as e: + LOGGER.error(f'Error determining device OS via Nmap: {e}') + return '' diff --git a/framework/python/src/core/session.py b/framework/python/src/core/session.py index 1d5f1dae0..425667ecd 100644 --- a/framework/python/src/core/session.py +++ b/framework/python/src/core/session.py @@ -432,6 +432,10 @@ def get_ipv4_subnet(self): def get_ipv6_subnet(self): return self._ipv6_subnet + def set_device_kernel(self, kernel: str): + if self._device is not None: + self._device.kernel = kernel + def get_status(self) -> TestrunStatus: return self._status diff --git a/framework/python/src/net_orc/network_orchestrator.py b/framework/python/src/net_orc/network_orchestrator.py index f081931ac..0a54e2dc5 100644 --- a/framework/python/src/net_orc/network_orchestrator.py +++ b/framework/python/src/net_orc/network_orchestrator.py @@ -311,9 +311,22 @@ def _start_device_monitor(self, device): prn=self._monitor_packet_callback) sniffer.start() + device_os_discover_attempts = 3 + device_os = '' while sniffer.running: time.sleep(1) + # Discovering device OS + if device_os_discover_attempts > 0: + device_os = util.get_device_os_nmap(device.ip_addr) + if not device_os: + device_os = util.get_device_os_ssh(device.ip_addr) + if device_os: + self._session.set_device_kernel(device_os) + device_os_discover_attempts = 0 + else: + device_os_discover_attempts -= 1 + # Check Testrun hasn't been cancelled if self._session.get_status() in (TestrunStatus.STOPPING, TestrunStatus.CANCELLED): diff --git a/modules/network/gateway/gateway.Dockerfile b/modules/network/gateway/gateway.Dockerfile index 58c3f98ab..d26784272 100644 --- a/modules/network/gateway/gateway.Dockerfile +++ b/modules/network/gateway/gateway.Dockerfile @@ -21,6 +21,8 @@ ARG MODULE_DIR=modules/network/$MODULE_NAME # Install required packages RUN apt-get update && \ apt-get install -y iptables \ + netcat-openbsd \ + nmap \ isc-dhcp-client && \ rm -rf /var/lib/apt/lists/*