From c31812f8799f3c3232cbe6d96f2d53e5f6e575df Mon Sep 17 00:00:00 2001 From: William Zhao Date: Thu, 16 May 2024 15:41:42 -0400 Subject: [PATCH] Refactor Iperf into another inherited class of PerfServer/Client Signed-off-by: William Zhao --- iperf.py | 154 ++------------------------------------- perf.py | 173 ++++++++++++++++++++++++++++++++++++++++++++ trafficFlowTests.py | 5 +- validateOffload.py | 5 +- 4 files changed, 184 insertions(+), 153 deletions(-) create mode 100644 perf.py diff --git a/iperf.py b/iperf.py index f89f7241..62eb7fdc 100644 --- a/iperf.py +++ b/iperf.py @@ -10,84 +10,23 @@ import time from syncManager import SyncManager import sys +import perf IPERF_EXE = "iperf3" IPERF_UDP_OPT = "-u -b 25G" IPERF_REV_OPT = "-R" -EXTERNAL_IPERF3_SERVER = "external-iperf3-server" # Finishing switching iperf data handling to dataclass -class IperfServer(Task): +class IperfServer(perf.PerfServer): def __init__(self, tc: TestConfig, ts: TestSettings): - super().__init__(tc, ts.server_index, ts.node_server_name, ts.server_is_tenant) - self.exec_persistent = ts.server_is_persistent - self.port = 5201 + self.index - self.pod_type = ts.server_pod_type - self.connection_mode = ts.connection_mode - - self.template_args["default_network"] = ts.server_default_network - if self.connection_mode == ConnectionMode.EXTERNAL_IP: - self.pod_name = EXTERNAL_IPERF3_SERVER - return - if self.pod_type == PodType.SRIOV: - self.in_file_template = "./manifests/sriov-pod.yaml.j2" - self.out_file_yaml = ( - f"./manifests/yamls/sriov-pod-{self.node_name}-server.yaml" - ) - self.template_args["pod_name"] = ( - f"sriov-pod-{self.node_name}-server-{self.port}" - ) - elif self.pod_type == PodType.NORMAL: - self.in_file_template = "./manifests/pod.yaml.j2" - self.out_file_yaml = f"./manifests/yamls/pod-{self.node_name}-server.yaml" - self.template_args["pod_name"] = ( - f"normal-pod-{self.node_name}-server-{self.port}" - ) - elif self.pod_type == PodType.HOSTBACKED: - self.in_file_template = "./manifests/host-pod.yaml.j2" - self.out_file_yaml = ( - f"./manifests/yamls/host-pod-{self.node_name}-server.yaml" - ) - self.template_args["pod_name"] = ( - f"host-pod-{self.node_name}-server-{self.port}" - ) - - self.template_args["port"] = f"{self.port}" - - self.pod_name = self.template_args["pod_name"] if self.exec_persistent: self.template_args["command"] = IPERF_EXE self.template_args["args"] = f'["-s", "-p", "{self.port}"]' - common.j2_render(self.in_file_template, self.out_file_yaml, self.template_args) - logger.info(f"Generated Server Pod Yaml {self.out_file_yaml}") - - self.cluster_ip_addr = self.create_cluster_ip_service() - self.nodeport_ip_addr = self.create_node_port_service(self.port + 25000) - - def confirm_server_alive(self) -> None: - if self.connection_mode == ConnectionMode.EXTERNAL_IP: - # Podman scenario - end_time = time.monotonic() + 60 - while time.monotonic() < end_time: - r = self.lh.run( - f"podman ps --filter status=running --filter name={self.pod_name} --format '{{{{.Names}}}}'" - ) - if self.pod_name in r.out: - break - time.sleep(5) - else: - # Kubernetes/OpenShift scenario - r = self.run_oc( - f"wait --for=condition=ready pod/{self.pod_name} --timeout=1m" - ) - if not r or r.returncode != 0: - logger.error(f"Failed to start server: {r.err}") - sys.exit(-1) - SyncManager.set_server_alive() + perf.PerfServer.__init__(self, tc, ts) def setup(self) -> None: if self.connection_mode == ConnectionMode.EXTERNAL_IP: @@ -117,57 +56,10 @@ def server(self: IperfServer, cmd: str) -> Result: self.exec_thread.start() self.confirm_server_alive() - def run(self, duration: int) -> None: - pass - - def output(self, out: common.TftAggregateOutput) -> None: - pass - - def generate_output(self, data: str) -> common.BaseOutput: - return common.BaseOutput("", {}) - -class IperfClient(Task): +class IperfClient(perf.PerfClient): def __init__(self, tc: TestConfig, ts: TestSettings, server: IperfServer): - super().__init__(tc, ts.client_index, ts.node_client_name, ts.client_is_tenant) - self.server = server - self.port = self.server.port - self.pod_type = ts.client_pod_type - self.connection_mode = ts.connection_mode - self.test_type = ts.test_type - self.test_case_id = ts.test_case_id - self.ts = ts - self.reverse = ts.reverse - self.cmd = "" - - self.template_args["default_network"] = ts.client_default_network - if self.pod_type == PodType.SRIOV: - self.in_file_template = "./manifests/sriov-pod.yaml.j2" - self.out_file_yaml = ( - f"./manifests/yamls/sriov-pod-{self.node_name}-client.yaml" - ) - self.template_args["pod_name"] = ( - f"sriov-pod-{self.node_name}-client-{self.port}" - ) - elif self.pod_type == PodType.NORMAL: - self.in_file_template = "./manifests/pod.yaml.j2" - self.out_file_yaml = f"./manifests/yamls/pod-{self.node_name}-client.yaml" - self.template_args["pod_name"] = ( - f"normal-pod-{self.node_name}-client-{self.port}" - ) - elif self.pod_type == PodType.HOSTBACKED: - self.in_file_template = "./manifests/host-pod.yaml.j2" - self.out_file_yaml = ( - f"./manifests/yamls/host-pod-{self.node_name}-client.yaml" - ) - self.template_args["pod_name"] = ( - f"host-pod-{self.node_name}-client-{self.port}" - ) - - self.pod_name = self.template_args["pod_name"] - - common.j2_render(self.in_file_template, self.out_file_yaml, self.template_args) - logger.info(f"Generated Client Pod Yaml {self.out_file_yaml}") + perf.PerfClient.__init__(self, tc, ts, server) def run(self, duration: int) -> None: def client(self: IperfClient, cmd: str) -> Result: @@ -248,41 +140,5 @@ def print_udp_results(self, data: dict) -> None: f" Total Lost Percent: {total_lost_percent:.2f}%" ) - def get_target_ip(self) -> str: - if self.connection_mode == ConnectionMode.CLUSTER_IP: - logger.debug( - f"get_target_ip() ClusterIP connection to {self.server.cluster_ip_addr}" - ) - return self.server.cluster_ip_addr - elif self.connection_mode == ConnectionMode.NODE_PORT_IP: - logger.debug( - f"get_target_ip() NodePortIP connection to {self.server.nodeport_ip_addr}" - ) - return self.server.nodeport_ip_addr - elif self.connection_mode == ConnectionMode.EXTERNAL_IP: - external_pod_ip = self.get_podman_ip(EXTERNAL_IPERF3_SERVER) - logger.debug(f"get_target_ip() External connection to {external_pod_ip}") - return external_pod_ip - server_ip = self.server.get_pod_ip() - logger.debug(f"get_target_ip() Connection to server at {server_ip}") - return server_ip - - def get_podman_ip(self, pod_name: str) -> str: - cmd = "podman inspect --format '{{.NetworkSettings.IPAddress}}' " + pod_name - - for _ in range(5): - ret = self.lh.run(cmd) - if ret.returncode == 0: - ip_address = ret.out.strip() - if ip_address: - logger.debug(f"get_podman_ip({pod_name}) found: {ip_address}") - return ip_address - - time.sleep(2) - - raise Exception( - f"get_podman_ip(): failed to get {pod_name} ip after 5 attempts" - ) - def iperf_error_occurred(self, data: dict) -> bool: return "error" in data diff --git a/perf.py b/perf.py new file mode 100644 index 00000000..960e5907 --- /dev/null +++ b/perf.py @@ -0,0 +1,173 @@ +import common +from common import PodType, ConnectionMode, TestType, IperfOutput +from logger import logger +from testConfig import TestConfig +from thread import ReturnValueThread +from task import Task +from common import Result +from testSettings import TestSettings +import json +import time +from syncManager import SyncManager +import sys + +EXTERNAL_PERF_SERVER = "external-perf-server" + + +class PerfServer(Task): + def __init__(self, tc: TestConfig, ts: TestSettings): + Task.__init__( + self, tc, ts.server_index, ts.node_server_name, ts.server_is_tenant + ) + self.exec_persistent = ts.server_is_persistent + self.port = 5201 + self.index + self.pod_type = ts.server_pod_type + self.connection_mode = ts.connection_mode + + self.template_args["default_network"] = ts.server_default_network + if self.connection_mode == ConnectionMode.EXTERNAL_IP: + self.pod_name = EXTERNAL_PERF_SERVER + return + if self.pod_type == PodType.SRIOV: + self.in_file_template = "./manifests/sriov-pod.yaml.j2" + self.out_file_yaml = ( + f"./manifests/yamls/sriov-pod-{self.node_name}-server.yaml" + ) + self.template_args["pod_name"] = ( + f"sriov-pod-{self.node_name}-server-{self.port}" + ) + elif self.pod_type == PodType.NORMAL: + self.in_file_template = "./manifests/pod.yaml.j2" + self.out_file_yaml = f"./manifests/yamls/pod-{self.node_name}-server.yaml" + self.template_args["pod_name"] = ( + f"normal-pod-{self.node_name}-server-{self.port}" + ) + elif self.pod_type == PodType.HOSTBACKED: + self.in_file_template = "./manifests/host-pod.yaml.j2" + self.out_file_yaml = ( + f"./manifests/yamls/host-pod-{self.node_name}-server.yaml" + ) + self.template_args["pod_name"] = ( + f"host-pod-{self.node_name}-server-{self.port}" + ) + + self.template_args["port"] = f"{self.port}" + + self.pod_name = self.template_args["pod_name"] + + common.j2_render(self.in_file_template, self.out_file_yaml, self.template_args) + logger.info(f"Generated Server Pod Yaml {self.out_file_yaml}") + + self.cluster_ip_addr = self.create_cluster_ip_service() + self.nodeport_ip_addr = self.create_node_port_service(self.port + 25000) + + def confirm_server_alive(self) -> None: + if self.connection_mode == ConnectionMode.EXTERNAL_IP: + # Podman scenario + end_time = time.monotonic() + 60 + while time.monotonic() < end_time: + r = self.lh.run( + f"podman ps --filter status=running --filter name={self.pod_name} --format '{{{{.Names}}}}'" + ) + if self.pod_name in r.out: + break + time.sleep(5) + else: + # Kubernetes/OpenShift scenario + r = self.run_oc( + f"wait --for=condition=ready pod/{self.pod_name} --timeout=1m" + ) + if not r or r.returncode != 0: + logger.error(f"Failed to start server: {r.err}") + sys.exit(-1) + SyncManager.set_server_alive() + + def run(self, duration: int) -> None: + pass + + def output(self, out: common.TftAggregateOutput) -> None: + pass + + def generate_output(self, data: str) -> common.BaseOutput: + return common.BaseOutput("", {}) + + +class PerfClient(Task): + def __init__(self, tc: TestConfig, ts: TestSettings, server: PerfServer): + Task.__init__( + self, tc, ts.client_index, ts.node_client_name, ts.client_is_tenant + ) + self.server = server + self.port = self.server.port + self.pod_type = ts.client_pod_type + self.connection_mode = ts.connection_mode + self.test_type = ts.test_type + self.test_case_id = ts.test_case_id + self.ts = ts + self.reverse = ts.reverse + self.cmd = "" + + self.template_args["default_network"] = ts.client_default_network + if self.pod_type == PodType.SRIOV: + self.in_file_template = "./manifests/sriov-pod.yaml.j2" + self.out_file_yaml = ( + f"./manifests/yamls/sriov-pod-{self.node_name}-client.yaml" + ) + self.template_args["pod_name"] = ( + f"sriov-pod-{self.node_name}-client-{self.port}" + ) + elif self.pod_type == PodType.NORMAL: + self.in_file_template = "./manifests/pod.yaml.j2" + self.out_file_yaml = f"./manifests/yamls/pod-{self.node_name}-client.yaml" + self.template_args["pod_name"] = ( + f"normal-pod-{self.node_name}-client-{self.port}" + ) + elif self.pod_type == PodType.HOSTBACKED: + self.in_file_template = "./manifests/host-pod.yaml.j2" + self.out_file_yaml = ( + f"./manifests/yamls/host-pod-{self.node_name}-client.yaml" + ) + self.template_args["pod_name"] = ( + f"host-pod-{self.node_name}-client-{self.port}" + ) + + self.pod_name = self.template_args["pod_name"] + + common.j2_render(self.in_file_template, self.out_file_yaml, self.template_args) + logger.info(f"Generated Client Pod Yaml {self.out_file_yaml}") + + def get_target_ip(self) -> str: + if self.connection_mode == ConnectionMode.CLUSTER_IP: + logger.debug( + f"get_target_ip() ClusterIP connection to {self.server.cluster_ip_addr}" + ) + return self.server.cluster_ip_addr + elif self.connection_mode == ConnectionMode.NODE_PORT_IP: + logger.debug( + f"get_target_ip() NodePortIP connection to {self.server.nodeport_ip_addr}" + ) + return self.server.nodeport_ip_addr + elif self.connection_mode == ConnectionMode.EXTERNAL_IP: + external_pod_ip = self.get_podman_ip(self.server.pod_name) + logger.debug(f"get_target_ip() External connection to {external_pod_ip}") + return external_pod_ip + server_ip = self.server.get_pod_ip() + logger.debug(f"get_target_ip() Connection to server at {server_ip}") + return server_ip + + def get_podman_ip(self, pod_name: str) -> str: + cmd = "podman inspect --format '{{.NetworkSettings.IPAddress}}' " + pod_name + + for _ in range(5): + ret = self.lh.run(cmd) + if ret.returncode == 0: + ip_address = ret.out.strip() + if ip_address: + logger.debug(f"get_podman_ip({pod_name}) found: {ip_address}") + return ip_address + + time.sleep(2) + + raise Exception( + f"get_podman_ip(): failed to get {pod_name} ip after 5 attempts" + ) diff --git a/trafficFlowTests.py b/trafficFlowTests.py index 075e279a..45383bb0 100644 --- a/trafficFlowTests.py +++ b/trafficFlowTests.py @@ -15,6 +15,7 @@ import iperf from task import Task from iperf import IperfServer, IperfClient +import perf from validateOffload import ValidateOffload from measureCpu import MeasureCPU from measurePower import MeasurePower @@ -77,9 +78,9 @@ def _cleanup_previous_testspace(self, namespace: str) -> None: raise Exception(f"cleanup_previous_testspace(): Failed to delete services") logger.info(f"Cleaned services with label tft-tests in namespace {namespace}") logger.info( - f"Cleaning external containers {iperf.EXTERNAL_IPERF3_SERVER} (if present)" + f"Cleaning external containers {perf.EXTERNAL_PERF_SERVER} (if present)" ) - cmd = f"podman stop --time 10 {iperf.EXTERNAL_IPERF3_SERVER}; podman rm --time 10 {iperf.EXTERNAL_IPERF3_SERVER}" + cmd = f"podman stop --time 10 {perf.EXTERNAL_PERF_SERVER}; podman rm --time 10 {perf.EXTERNAL_PERF_SERVER}" self.lh.run(cmd) def _enable_measure_cpu_plugin( diff --git a/validateOffload.py b/validateOffload.py index e52570b5..87bf91e5 100644 --- a/validateOffload.py +++ b/validateOffload.py @@ -11,7 +11,8 @@ from logger import logger import time from testConfig import TestConfig -from iperf import IperfServer, IperfClient, EXTERNAL_IPERF3_SERVER +from iperf import IperfServer, IperfClient +import perf from thread import ReturnValueThread from task import Task from typing import Optional, Union, Tuple @@ -50,7 +51,7 @@ def extract_vf_rep(self) -> str: logger.info(f"The VF representor is: ovn-k8s-mp0") return "ovn-k8s-mp0" - if self.iperf_pod_name == EXTERNAL_IPERF3_SERVER: + if self.iperf_pod_name == perf.EXTERNAL_PERF_SERVER: logger.info(f"There is no VF on an external server") return "external"