From 078483f933c047bca702fdc81cc87fe0f5a81130 Mon Sep 17 00:00:00 2001 From: vshepard Date: Thu, 7 Aug 2025 01:41:15 +0200 Subject: [PATCH 1/6] Remove usage of not standard nc in remote_ops.py is_port_free --- testgres/operations/remote_ops.py | 33 ++++++++++++++++++------------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/testgres/operations/remote_ops.py b/testgres/operations/remote_ops.py index 15d78b1..99f6278 100644 --- a/testgres/operations/remote_ops.py +++ b/testgres/operations/remote_ops.py @@ -10,6 +10,7 @@ import logging import typing import copy +import socket from ..exceptions import ExecUtilException from ..exceptions import InvalidOperationException @@ -681,22 +682,31 @@ def get_process_children(self, pid): def is_port_free(self, number: int) -> bool: assert type(number) == int # noqa: E721 - cmd = ["nc", "-w", "5", "-z", "-v", "localhost", str(number)] + # grep -q returns 0 if a listening socket on that port is found + port_hex = format(number, '04X') - exit_status, output, error = self.exec_command(cmd=cmd, encoding=get_default_encoding(), ignore_errors=True, verbose=True) + # Search /proc/net/tcp and tcp6 for any entry with this port + cmd = ['/bin/bash', '-lc', + f"grep -q ':{port_hex} ' /proc/net/tcp /proc/net/tcp6"] - assert type(output) == str # noqa: E721 - assert type(error) == str # noqa: E721 + exit_status, output, error = self.exec_command( + cmd=cmd, + encoding=get_default_encoding(), + ignore_errors=True, + verbose=True + ) + # grep exit 0 -> port is busy if exit_status == 0: - return __class__._is_port_free__process_0(error) + return False + # grep exit 1 -> port is free if exit_status == 1: - return __class__._is_port_free__process_1(error) - - errMsg = "nc returns an unknown result code: {0}".format(exit_status) + return True - RaiseError.CommandExecutionError( + # any other code is an unexpected error + errMsg = f"grep returned unexpected exit code: {exit_status}" + raise RaiseError.CommandExecutionError( cmd=cmd, exit_code=exit_status, message=errMsg, @@ -746,12 +756,7 @@ def _is_port_free__process_0(error: str) -> bool: @staticmethod def _is_port_free__process_1(error: str) -> bool: assert type(error) == str # noqa: E721 - # - # Example of error text: - # "nc: connect to localhost (127.0.0.1) port 1024 (tcp) failed: Connection refused\n" - # # May be here is needed to check error message? - # return True @staticmethod From cb0d9fb1c360ac8710e0c243c7b381bad4adc477 Mon Sep 17 00:00:00 2001 From: "d.kovalenko" Date: Thu, 7 Aug 2025 08:21:59 +0300 Subject: [PATCH 2/6] Fix for flake8 checks [remote_ops.py] [del] import socket --- testgres/operations/remote_ops.py | 1 - 1 file changed, 1 deletion(-) diff --git a/testgres/operations/remote_ops.py b/testgres/operations/remote_ops.py index 99f6278..9805c9d 100644 --- a/testgres/operations/remote_ops.py +++ b/testgres/operations/remote_ops.py @@ -10,7 +10,6 @@ import logging import typing import copy -import socket from ..exceptions import ExecUtilException from ..exceptions import InvalidOperationException From dca1f74e81905a6857e53dc59e21ca686e09d8ae Mon Sep 17 00:00:00 2001 From: vshepard Date: Thu, 7 Aug 2025 01:41:15 +0200 Subject: [PATCH 3/6] Remove usage of not standard nc in remote_ops.py is_port_free --- testgres/operations/remote_ops.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testgres/operations/remote_ops.py b/testgres/operations/remote_ops.py index 9805c9d..71810bb 100644 --- a/testgres/operations/remote_ops.py +++ b/testgres/operations/remote_ops.py @@ -10,6 +10,7 @@ import logging import typing import copy +import socket from ..exceptions import ExecUtilException from ..exceptions import InvalidOperationException @@ -685,7 +686,7 @@ def is_port_free(self, number: int) -> bool: port_hex = format(number, '04X') # Search /proc/net/tcp and tcp6 for any entry with this port - cmd = ['/bin/bash', '-lc', + cmd = ['/bin/bash', '-c', f"grep -q ':{port_hex} ' /proc/net/tcp /proc/net/tcp6"] exit_status, output, error = self.exec_command( From 753bdb001ea9cde96194169931ac911c73cbc98a Mon Sep 17 00:00:00 2001 From: "d.kovalenko" Date: Fri, 15 Aug 2025 16:34:15 +0300 Subject: [PATCH 4/6] [flake8] One more time --- testgres/operations/remote_ops.py | 1 - 1 file changed, 1 deletion(-) diff --git a/testgres/operations/remote_ops.py b/testgres/operations/remote_ops.py index 71810bb..c862f70 100644 --- a/testgres/operations/remote_ops.py +++ b/testgres/operations/remote_ops.py @@ -10,7 +10,6 @@ import logging import typing import copy -import socket from ..exceptions import ExecUtilException from ..exceptions import InvalidOperationException From 7654478125042da2ba002aab15c004150e15204d Mon Sep 17 00:00:00 2001 From: "d.kovalenko" Date: Fri, 15 Aug 2025 23:10:19 +0300 Subject: [PATCH 5/6] RemoteOperations::is_port_free uses a regexp, tcp6 is removed We will use a more clever analyzer for content of /proc/net/tcp. I deleted a support of TCP/IP v6 because: - LocalOperations does not support it - We do not have the tests for TCP/IP v6 We should add the support of TCP/IP v6 separately and completely. --- testgres/operations/remote_ops.py | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/testgres/operations/remote_ops.py b/testgres/operations/remote_ops.py index c862f70..6322020 100644 --- a/testgres/operations/remote_ops.py +++ b/testgres/operations/remote_ops.py @@ -10,6 +10,7 @@ import logging import typing import copy +import re from ..exceptions import ExecUtilException from ..exceptions import InvalidOperationException @@ -684,9 +685,20 @@ def is_port_free(self, number: int) -> bool: # grep -q returns 0 if a listening socket on that port is found port_hex = format(number, '04X') - # Search /proc/net/tcp and tcp6 for any entry with this port - cmd = ['/bin/bash', '-c', - f"grep -q ':{port_hex} ' /proc/net/tcp /proc/net/tcp6"] + # sl local_address rem_address st tx_queue rx_queue tr tm->when retrnsmt ... + # 137: 0A01A8C0:EC08 1DA2A959:01BB 01 00000000:00000000 02:00000000 00000000 ... + C_REGEXP = r"^\s*[0-9]+:\s*[0-9a-fA-F]{8}:" + re.escape(port_hex) + r"\s+[0-9a-fA-F]{8}:[0-9a-fA-F]{4}\s+" + + # Search /proc/net/tcp for any entry with this port + # NOTE: grep requires quote string with regular expression + # TODO: added a support for tcp/ip v6 + grep_cmd_s = "grep -q -E \"" + C_REGEXP + "\" /proc/net/tcp" + + cmd = [ + "/bin/bash", + "-c", + grep_cmd_s, + ] exit_status, output, error = self.exec_command( cmd=cmd, From 1c675f008cf205caf4c576b75e469905e2fae45c Mon Sep 17 00:00:00 2001 From: "d.kovalenko" Date: Fri, 15 Aug 2025 23:25:35 +0300 Subject: [PATCH 6/6] debug: is_port_free requires number in range [0..65535] --- testgres/operations/local_ops.py | 2 ++ testgres/operations/remote_ops.py | 2 ++ 2 files changed, 4 insertions(+) diff --git a/testgres/operations/local_ops.py b/testgres/operations/local_ops.py index 99d8e32..c2bed24 100644 --- a/testgres/operations/local_ops.py +++ b/testgres/operations/local_ops.py @@ -583,6 +583,8 @@ def get_process_children(self, pid): def is_port_free(self, number: int) -> bool: assert type(number) == int # noqa: E721 + assert number >= 0 + assert number <= 65535 # OK? with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: try: diff --git a/testgres/operations/remote_ops.py b/testgres/operations/remote_ops.py index 6322020..4cdb158 100644 --- a/testgres/operations/remote_ops.py +++ b/testgres/operations/remote_ops.py @@ -681,6 +681,8 @@ def get_process_children(self, pid): def is_port_free(self, number: int) -> bool: assert type(number) == int # noqa: E721 + assert number >= 0 + assert number <= 65535 # OK? # grep -q returns 0 if a listening socket on that port is found port_hex = format(number, '04X')