Skip to content

Commit 9dd4074

Browse files
authored
net, traffic_generator: improve naming + retry decorator using (RedHatQE#2389)
Client\Server looks quite common and such naming does not reflect the real intention. The usage traffic_generator.Client does not solve the problem as well. It's crucial to explicitly point out that we work with Tcp traffic and the classes implement TCP client and TCP server in reality. And this clarity is significant for tests also. The commit also includes replacing TimeoutSampler with retry decorator, that leads a little refactoring for classes to align the logic. Retry-enabled `_ensure_is_running()` method is added to `__enter__()`. PodTcpClient already uses a similar implementation. We need to make sure once when entering into the context manager that the client\server process is running, then it is enough to use the atomic method `is_running()` without retry to determine the status of the process. Signed-off-by: Sergei Volkov <sevolkov@redhat.com>
1 parent d9fd8a5 commit 9dd4074

File tree

5 files changed

+49
-42
lines changed

5 files changed

+49
-42
lines changed

libs/net/traffic_generator.py

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from ocp_resources.pod import Pod
66
from ocp_utilities.exceptions import CommandExecFailed
7-
from timeout_sampler import TimeoutExpiredError, TimeoutSampler, retry
7+
from timeout_sampler import retry
88

99
from libs.vm.vm import BaseVirtualMachine
1010

@@ -15,7 +15,7 @@
1515
LOGGER = logging.getLogger(__name__)
1616

1717

18-
class BaseClient(ABC):
18+
class BaseTcpClient(ABC):
1919
"""Base abstract class for network traffic generator client."""
2020

2121
def __init__(self, server_ip: str, server_port: int):
@@ -24,7 +24,7 @@ def __init__(self, server_ip: str, server_port: int):
2424
self._cmd = f"{_IPERF_BIN} --client {self._server_ip} --time 0 --port {self.server_port} --connect-timeout 300"
2525

2626
@abstractmethod
27-
def __enter__(self) -> "BaseClient":
27+
def __enter__(self) -> "BaseTcpClient":
2828
pass
2929

3030
@abstractmethod
@@ -36,7 +36,7 @@ def is_running(self) -> bool:
3636
pass
3737

3838

39-
class Server:
39+
class TcpServer:
4040
"""
4141
Represents a server running on a virtual machine for testing network performance.
4242
Implemented with iperf3
@@ -55,11 +55,13 @@ def __init__(
5555
self._port = port
5656
self._cmd = f"{_IPERF_BIN} --server --port {self._port} --one-off"
5757

58-
def __enter__(self) -> "Server":
58+
def __enter__(self) -> "TcpServer":
5959
self._vm.console(
6060
commands=[f"{self._cmd} &"],
6161
timeout=_DEFAULT_CMD_TIMEOUT_SEC,
6262
)
63+
self._ensure_is_running()
64+
6365
return self
6466

6567
def __exit__(self, exc_type: BaseException, exc_value: BaseException, traceback: object) -> None:
@@ -72,10 +74,13 @@ def vm(self) -> BaseVirtualMachine:
7274
def is_running(self) -> bool:
7375
return _is_process_running(vm=self._vm, cmd=self._cmd)
7476

77+
@retry(wait_timeout=30, sleep=2, exceptions_dict={})
78+
def _ensure_is_running(self) -> bool:
79+
return self.is_running()
80+
7581

76-
class Client(BaseClient):
77-
"""
78-
Represents a client that connects to a server to test network performance.
82+
class VMTcpClient(BaseTcpClient):
83+
"""Represents a TCP client that connects to a server to test network performance.
7984
Implemented with iperf3
8085
8186
Args:
@@ -93,11 +98,13 @@ def __init__(
9398
super().__init__(server_ip=server_ip, server_port=server_port)
9499
self._vm = vm
95100

96-
def __enter__(self) -> "Client":
101+
def __enter__(self) -> "VMTcpClient":
97102
self._vm.console(
98103
commands=[f"{self._cmd} &"],
99104
timeout=_DEFAULT_CMD_TIMEOUT_SEC,
100105
)
106+
self._ensure_is_running()
107+
101108
return self
102109

103110
def __exit__(self, exc_type: BaseException, exc_value: BaseException, traceback: object) -> None:
@@ -110,6 +117,10 @@ def vm(self) -> BaseVirtualMachine:
110117
def is_running(self) -> bool:
111118
return _is_process_running(vm=self._vm, cmd=self._cmd)
112119

120+
@retry(wait_timeout=30, sleep=2, exceptions_dict={})
121+
def _ensure_is_running(self) -> bool:
122+
return self.is_running()
123+
113124

114125
def _stop_process(vm: BaseVirtualMachine, cmd: str) -> None:
115126
try:
@@ -118,25 +129,18 @@ def _stop_process(vm: BaseVirtualMachine, cmd: str) -> None:
118129
LOGGER.warning(str(e))
119130

120131

121-
def _is_process_running( # type: ignore[return]
122-
vm: BaseVirtualMachine, cmd: str
123-
) -> bool:
132+
def _is_process_running(vm: BaseVirtualMachine, cmd: str) -> bool:
124133
try:
125-
for sample in TimeoutSampler(
126-
wait_timeout=60,
127-
sleep=5,
128-
func=vm.console,
134+
vm.console(
129135
commands=[f"pgrep -fx '{cmd}'"],
130136
timeout=_DEFAULT_CMD_TIMEOUT_SEC,
131-
):
132-
if sample:
133-
return True
134-
except TimeoutExpiredError as e:
135-
LOGGER.warning(f"Process is not running on VM {vm.name}. Error: {str(e.last_exp)}")
137+
)
138+
return True
139+
except CommandExecFailed:
136140
return False
137141

138142

139-
class PodClient(BaseClient):
143+
class PodTcpClient(BaseTcpClient):
140144
"""Represents a TCP client that connects to a server to test network performance.
141145
142146
Expects pod to have iperf3 container.
@@ -155,7 +159,7 @@ def __init__(self, pod: Pod, server_ip: str, server_port: int, bind_interface: s
155159
self._container = _IPERF_BIN
156160
self._cmd += f" --bind {bind_interface}" if bind_interface else ""
157161

158-
def __enter__(self) -> "PodClient":
162+
def __enter__(self) -> "PodTcpClient":
159163
# run the command in the background using nohup to ensure it keeps running after the exec session ends
160164
self._pod.execute(
161165
command=["sh", "-c", f"nohup {self._cmd} >/tmp/{_IPERF_BIN}.log 2>&1 &"], container=self._container
@@ -178,5 +182,5 @@ def _ensure_is_running(self) -> bool:
178182
return self.is_running()
179183

180184

181-
def is_tcp_connection(server: Server, client: Client | PodClient) -> bool:
185+
def is_tcp_connection(server: TcpServer, client: BaseTcpClient) -> bool:
182186
return server.is_running() and client.is_running()

tests/network/bgp/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313
from ocp_resources.pod import Pod
1414

1515
from libs.net import netattachdef as libnad
16-
from libs.net.traffic_generator import PodClient as TcpClient
17-
from libs.net.traffic_generator import Server as TcpServer
16+
from libs.net.traffic_generator import PodTcpClient as TcpClient
17+
from libs.net.traffic_generator import TcpServer
1818
from libs.net.udn import create_udn_namespace
1919
from libs.net.vmspec import IP_ADDRESS, lookup_iface_status, lookup_primary_network
2020
from libs.vm.vm import BaseVirtualMachine

tests/network/localnet/conftest.py

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
from ocp_resources.node import Node
77

88
import tests.network.libs.nodenetworkconfigurationpolicy as libnncp
9-
from libs.net.traffic_generator import Client, Server
9+
from libs.net.traffic_generator import TcpServer
10+
from libs.net.traffic_generator import VMTcpClient as TcpClient
1011
from libs.net.vmspec import lookup_iface_status
1112
from libs.vm.vm import BaseVirtualMachine
1213
from tests.network.libs import cluster_user_defined_network as libcudn
@@ -143,14 +144,14 @@ def localnet_running_vms(
143144

144145

145146
@pytest.fixture()
146-
def localnet_server(localnet_running_vms: tuple[BaseVirtualMachine, BaseVirtualMachine]) -> Generator[Server]:
147+
def localnet_server(localnet_running_vms: tuple[BaseVirtualMachine, BaseVirtualMachine]) -> Generator[TcpServer]:
147148
with create_traffic_server(vm=localnet_running_vms[0]) as server:
148149
assert server.is_running()
149150
yield server
150151

151152

152153
@pytest.fixture()
153-
def localnet_client(localnet_running_vms: tuple[BaseVirtualMachine, BaseVirtualMachine]) -> Generator[Client]:
154+
def localnet_client(localnet_running_vms: tuple[BaseVirtualMachine, BaseVirtualMachine]) -> Generator[TcpClient]:
154155
with create_traffic_client(
155156
server_vm=localnet_running_vms[0],
156157
client_vm=localnet_running_vms[1],
@@ -295,7 +296,7 @@ def ovs_bridge_localnet_running_vms(
295296
@pytest.fixture()
296297
def localnet_ovs_bridge_server(
297298
ovs_bridge_localnet_running_vms: tuple[BaseVirtualMachine, BaseVirtualMachine],
298-
) -> Generator[Server]:
299+
) -> Generator[TcpServer]:
299300
with create_traffic_server(vm=ovs_bridge_localnet_running_vms[0]) as server:
300301
assert server.is_running()
301302
yield server
@@ -304,7 +305,7 @@ def localnet_ovs_bridge_server(
304305
@pytest.fixture()
305306
def localnet_ovs_bridge_client(
306307
ovs_bridge_localnet_running_vms: tuple[BaseVirtualMachine, BaseVirtualMachine],
307-
) -> Generator[Client]:
308+
) -> Generator[TcpClient]:
308309
with create_traffic_client(
309310
server_vm=ovs_bridge_localnet_running_vms[0],
310311
client_vm=ovs_bridge_localnet_running_vms[1],

tests/network/localnet/liblocalnet.py

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
from kubernetes.client import ApiException
66
from kubernetes.dynamic import DynamicClient
77

8-
from libs.net.traffic_generator import Client, Server
8+
from libs.net.traffic_generator import TcpServer
9+
from libs.net.traffic_generator import VMTcpClient as TcpClient
910
from libs.net.vmspec import IP_ADDRESS, add_network_interface, add_volume_disk, lookup_iface_status
1011
from libs.vm.affinity import new_pod_anti_affinity
1112
from libs.vm.factory import base_vmspec, fedora_vm
@@ -38,14 +39,14 @@ def run_vms(vms: tuple[BaseVirtualMachine, ...]) -> tuple[BaseVirtualMachine, ..
3839
return vms
3940

4041

41-
def create_traffic_server(vm: BaseVirtualMachine) -> Server:
42-
return Server(vm=vm, port=_IPERF_SERVER_PORT)
42+
def create_traffic_server(vm: BaseVirtualMachine) -> TcpServer:
43+
return TcpServer(vm=vm, port=_IPERF_SERVER_PORT)
4344

4445

4546
def create_traffic_client(
4647
server_vm: BaseVirtualMachine, client_vm: BaseVirtualMachine, spec_logical_network: str
47-
) -> Client:
48-
return Client(
48+
) -> TcpClient:
49+
return TcpClient(
4950
vm=client_vm,
5051
server_ip=lookup_iface_status(vm=server_vm, iface_name=spec_logical_network)[IP_ADDRESS],
5152
server_port=_IPERF_SERVER_PORT,
@@ -150,9 +151,9 @@ def client_server_active_connection(
150151
server_vm: BaseVirtualMachine,
151152
spec_logical_network: str,
152153
port: int = _IPERF_SERVER_PORT,
153-
) -> Generator[tuple[Client, Server], None, None]:
154-
with Server(vm=server_vm, port=port) as server:
155-
with Client(
154+
) -> Generator[tuple[TcpClient, TcpServer], None, None]:
155+
with TcpServer(vm=server_vm, port=port) as server:
156+
with TcpClient(
156157
vm=client_vm,
157158
server_ip=lookup_iface_status(vm=server_vm, iface_name=spec_logical_network)[IP_ADDRESS],
158159
server_port=port,

tests/network/user_defined_network/test_user_defined_network.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
from ocp_resources.user_defined_network import Layer2UserDefinedNetwork
55
from ocp_resources.utils.constants import TIMEOUT_1MINUTE
66

7-
from libs.net.traffic_generator import Client, Server, is_tcp_connection
7+
from libs.net.traffic_generator import TcpServer, is_tcp_connection
8+
from libs.net.traffic_generator import VMTcpClient as TcpClient
89
from libs.net.vmspec import lookup_iface_status, lookup_primary_network
910
from libs.vm import affinity
1011
from tests.network.libs.vm_factory import udn_vm
@@ -74,14 +75,14 @@ def vmb_udn(udn_namespace, namespaced_layer2_user_defined_network, udn_affinity_
7475

7576
@pytest.fixture(scope="class")
7677
def server(vmb_udn):
77-
with Server(vm=vmb_udn, port=SERVER_PORT) as server:
78+
with TcpServer(vm=vmb_udn, port=SERVER_PORT) as server:
7879
assert server.is_running()
7980
yield server
8081

8182

8283
@pytest.fixture(scope="class")
8384
def client(vma_udn, vmb_udn):
84-
with Client(
85+
with TcpClient(
8586
vm=vma_udn,
8687
server_ip=lookup_iface_status(vm=vmb_udn, iface_name=lookup_primary_network(vm=vmb_udn).name)[IP_ADDRESS],
8788
server_port=SERVER_PORT,

0 commit comments

Comments
 (0)