Implemented HW2HW network performance testing
Implemented HW2HW network performance test:
- Added K8S client manager and API methods
- Added method for collecting HW compute nodes
- Improved and extended global config
- Extended requirements.txt, pinned some modules
- Extended and improved SSH methods
Added some small improvements:
- extended .gitignore
- Added some custom exceptions instead of basic ones
- Renamed some classes
- Set iperf v2 to be default for multi-threads tests
- Updated README file
Related-PROD: PROD-36943
Change-Id: I265058967ccc01d96bf3bca532a8a0ae2a26f1f2
diff --git a/tests/test_hw2hw.py b/tests/test_hw2hw.py
new file mode 100644
index 0000000..38bd58d
--- /dev/null
+++ b/tests/test_hw2hw.py
@@ -0,0 +1,126 @@
+import logging
+import sys
+
+import pytest
+from texttable import Texttable
+
+import utils
+from utils import helpers
+from utils import ssh
+from utils.k8s_client import K8SCliActions
+
+
+logger = logging.getLogger(__name__)
+
+
+def test_hw2hw(hw_pair, k8s_v1_client, request, html_report):
+ """
+ Simplified Performance Test: HW to HW test via some specific interface
+ 1. Get the nodes list from the config, or get computes from K8S nodes list
+ 2. Connect to the nodes, install iperf, iperf3 there
+ 3. Start iperf, iperf3 at some specific interface
+ 4. Measure HW to HW nodes via some interface IP, 1 thread
+ 5. Measure HW to HW nodes via some interface IP, 1 thread, multiple threads
+ (10 by default)
+ 6. Draw the table with all pairs and results
+ """
+ k8s_actions = K8SCliActions(k8s_v1_client)
+ config = utils.get_configuration()
+ node_ssh_key_path = config.get("node_ssh_key_path", "")
+ node_ssh_username = config.get("node_ssh_username", "mcc-user")
+ iperf_time = int(config.get('iperf_time', 60))
+ threads = int(config.get('multiple_threads_number', 10))
+ iperf_utility = config.get('multiple_threads_iperf_utility', 'iperf3')
+ result_table = Texttable(max_width=120)
+ network_cidr = config.get('network_cidr', '')
+ cleanup_list = []
+
+ if not node_ssh_key_path:
+ pytest.skip("No private key for the MOSK K8S nodes is provided. "
+ "Please set the ssh key path in the config option "
+ "'node_ssh_key_path'.")
+
+ if not network_cidr:
+ # TODO: implement setting several comma-separated net ranges
+ # TODO: take some default (storage or tenant) interface if not set
+ pytest.skip("No network interface is provided. Please set the "
+ "network range in the config option 'network_cidr'.")
+
+ # get K8S nodes' names and Internal IPs for the hw_pair list
+ nodes_info = k8s_actions.get_nodes_info_by_names(hw_pair)
+ # connect to the nodes and prepare iperf
+ node_connect = ssh.SSHTransport(address=nodes_info[0]["address"],
+ username=node_ssh_username,
+ private_key=node_ssh_key_path)
+ for node in nodes_info:
+ iperf_ip = node_connect.get_node_ip_addresses_from_cidr(
+ node['address'], network_cidr, user=node_ssh_username,
+ private_key=node_ssh_key_path)
+ node["iperf_ip"] = iperf_ip
+ logger.info(
+ f"Connecting to the node {node['name']}, IP {node['address']}")
+ iperf = ssh.IperfAtNode(
+ ip=node["address"], iperf_test_ip=iperf_ip,
+ user=node_ssh_username,
+ private_key=node_ssh_key_path)
+ if iperf.install_iperf:
+ cleanup_list.append(node["address"])
+
+ # Prepare the result table and run iperf3
+ table_rows = [[
+ 'Test Case', 'Node 1', 'Node 2', 'Network', 'Result'
+ ]]
+ # Do iperf3 measurement #1
+ measurement1 = f"HW to HW via {network_cidr} interface, 1 thread; iperf3"
+ logger.info("Doing '{}' measurement...".format(measurement1))
+ command1 = "iperf3 -c {} -t {} -B {} | grep sender | tail -n 1".format(
+ nodes_info[1]["iperf_ip"], iperf_time, nodes_info[0]["iperf_ip"])
+ logger.info(f"Running the command: {command1}")
+ result1 = node_connect.exec_command(command1)
+ res1 = (b" ".join(result1.split()[-4:-2:])).decode('utf-8')
+ logger.info("Result #1 is {}".format(res1))
+ table_rows.append([measurement1,
+ "{}".format(nodes_info[0]["name"]),
+ "{}".format(nodes_info[1]["name"]),
+ "{}".format(network_cidr),
+ "{}".format(res1)])
+
+ # Do iperf/iperf3 measurement #2
+ measurement2 = (f"HW to HW via {network_cidr} interface, {threads} "
+ f"threads; {iperf_utility}")
+ logger.info(f"Doing '{measurement2}' measurement...")
+ if iperf_utility == "iperf3":
+ command2 = '{} -c {} -P {} -t {} -B {} | grep sender | tail -n 1'\
+ .format(iperf_utility, nodes_info[1]["iperf_ip"],
+ threads, iperf_time, nodes_info[0]["iperf_ip"])
+ logger.info(f"Running the command: {command2}")
+ result2 = node_connect.exec_command(command2)
+ res2 = (b" ".join(result2.split()[-4:-2:])).decode('utf-8')
+ else:
+ iperf_utility = "iperf"
+ command2 = '{} -c {} -P {} -t {} -B {} | tail -n 1'.format(
+ iperf_utility, nodes_info[1]["iperf_ip"], threads, iperf_time,
+ nodes_info[0]["iperf_ip"])
+ logger.info(f"Running the command: {command2}")
+ result2 = node_connect.exec_command(command2)
+ res2 = (b" ".join(result2.split()[-2::])).decode('utf-8')
+ logger.info("Result #2 is {}".format(res2))
+ table_rows.append([measurement2,
+ "{}".format(nodes_info[0]["name"]),
+ "{}".format(nodes_info[1]["name"]),
+ "{}".format(network_cidr),
+ "{}".format(res2)])
+
+ # Draw the results table
+ logger.info("Drawing the table with iperf results...")
+ result_table.add_rows(table_rows)
+ sys.stdout.write('\n{}\n'.format(result_table.draw()))
+
+ # Send the results to CSV file at reports/ directory
+ helpers.create_test_result_table_csv_file(
+ table_rows, request.node.name)
+
+ # Delete the iperf, iperf3 packages if they were installed
+ for ip in cleanup_list:
+ ssh.IperfAtNode.remove_iperf_packages(
+ ip, node_ssh_username, node_ssh_key_path)