Implemented parallel iperf preparation at VMs

To reduce the time of runs, implemented parallel
iperf/iperf3 installation at VMs.

Related-PROD: PROD-36943
Change-Id: Ia789c874ae55c757ffbe8e07511433d2f694708e
diff --git a/tests/test_vm2vm.py b/tests/test_vm2vm.py
index 51dccdd..d6a4242 100644
--- a/tests/test_vm2vm.py
+++ b/tests/test_vm2vm.py
@@ -1,3 +1,4 @@
+from concurrent.futures import ThreadPoolExecutor
 import logging
 import sys
 import time
@@ -83,7 +84,7 @@
 
         # Associate FIPs and check VMs are Active
         logger.info("Creating Floating IPs and associating them...")
-        for i in range(4):
+        for i in range(len(vms)):
             fip = os_actions.create_floating_ip(os_resources['ext_net']['id'])
             fips.append(fip['id'])
             os_actions.check_vm_is_active(vms[i].id, timeout=timeout)
@@ -91,7 +92,8 @@
             private_address = vms[i].addresses[
                 list(vms[i].addresses.keys())[0]][0]['addr']
             vm_info.append({'vm': vms[i], 'fip': fip['floating_ip_address'],
-                            'private_address': private_address})
+                            'private_address': private_address,
+                            'private_key': private_key})
         # Set custom MTU if required
         if os_actions.is_cloud_tf() and (custom_mtu != "default"):
             logger.info("Setting up custom MTU at network ports...")
@@ -102,19 +104,17 @@
         # Check VMs are reachable and prepare iperf3
         transport1 = ssh.SSHTransport(vm_info[0]['fip'], 'ubuntu',
                                       password='dd', private_key=private_key)
-        logger.info("Checking VMs are reachable via SSH, getting MTU...")
-        mtus = []
-        for i in range(4):
-            if transport1.check_vm_is_reachable_ssh(
-                    floating_ip=vm_info[i]['fip'], timeout=ssh_timeout):
-                ssh.IperfAtVM(
-                    vm_info[i]['fip'], private_key=private_key)
-                mtus.append(transport1.get_mtu_from_vm(
-                    vm_info[i]['fip'], private_key=private_key))
+        logger.info("Checking VMs are reachable via SSH...")
+        for i in range(len(vms)):
+            transport1.check_vm_is_reachable_ssh(
+                floating_ip=vm_info[i]['fip'], timeout=ssh_timeout)
+        with ThreadPoolExecutor() as executor:
+            futures = [
+                executor.submit(ssh.install_iperf_at_vms_and_get_mtu, vm_info)
+                for vm_info in vm_info]
+            mtus = [future.result() for future in futures]
         logger.info("MTU at networks: {}, {}".format(
             os_resources['net1']['mtu'], os_resources['net2']['mtu']))
-        logger.info("MTU at VMs: {}".format(", ".join(mtus)))
-
         # Prepare the result table and run iperf3
         table_rows = [[
             'Test Case', 'Host 1', 'Host 2', 'MTU at VMs', 'Result'
diff --git a/tests/test_vm2vm_different_routers.py b/tests/test_vm2vm_different_routers.py
index 612e5be..8b38a4b 100644
--- a/tests/test_vm2vm_different_routers.py
+++ b/tests/test_vm2vm_different_routers.py
@@ -1,3 +1,4 @@
+from concurrent.futures import ThreadPoolExecutor
 import logging
 import sys
 import time
@@ -107,7 +108,8 @@
         vms[2].add_floating_ip(fip2['floating_ip_address'])
         for i in range(len(vms)):
             vm_info.append({'vm': vms[i],
-                            'fip': fips[i]['floating_ip_address']})
+                            'fip': fips[i]['floating_ip_address'],
+                            'private_key': private_key})
 
         # Set custom MTU if required
         if os_actions.is_cloud_tf() and (custom_mtu != "default"):
@@ -117,24 +119,21 @@
                                                                custom_mtu)
 
         # Check VMs are reachable and prepare iperf3
-        logger.info("Checking VMs are reachable via SSH, getting MTU...")
-        mtus = []
+        logger.info("Checking VMs are reachable via SSH...")
         transport1 = ssh.SSHTransport(vm_info[0]['fip'], 'ubuntu',
                                       password='dd', private_key=private_key)
-        logger.info("Checking VMs are reachable via SSH...")
         for i in range(len(vms)):
-            if transport1.check_vm_is_reachable_ssh(
-                    floating_ip=vm_info[i]['fip'], timeout=ssh_timeout):
-                ssh.IperfAtVM(
-                    vm_info[i]['fip'], private_key=private_key)
-                mtus.append(transport1.get_mtu_from_vm(
-                    vm_info[i]['fip'], private_key=private_key))
+            transport1.check_vm_is_reachable_ssh(
+                floating_ip=vm_info[i]['fip'], timeout=ssh_timeout)
+        with ThreadPoolExecutor() as executor:
+            futures = [
+                executor.submit(ssh.install_iperf_at_vms_and_get_mtu, vm_info)
+                for vm_info in vm_info]
+            mtus = [future.result() for future in futures]
         logger.info(
             "MTU at networks: {}, {}".format(
                 os_resources['net1']['mtu'],
                 os_resources_alt_project['net1']['mtu']))
-        logger.info("MTU at VMs: {}".format(", ".join(mtus)))
-
         # Prepare the result table and run iperf3
         table_rows = []
         table_rows.append(['Test Case', 'Host 1', 'Host 2',
diff --git a/utils/ssh.py b/utils/ssh.py
index caca30e..20313d0 100644
--- a/utils/ssh.py
+++ b/utils/ssh.py
@@ -14,6 +14,21 @@
 logging.getLogger("paramiko").setLevel(logging.WARNING)
 
 
+def install_iperf_at_vms_and_get_mtu(vm_info):
+    transport1 = SSHTransport(vm_info['fip'], 'ubuntu', password='dd',
+                              private_key=vm_info['private_key'])
+    try:
+        IperfAtVM(vm_info['fip'], private_key=vm_info['private_key'])
+        logger.info("Getting MTU values from VMs...")
+        mtu = transport1.get_mtu_from_vm(
+            vm_info['fip'], private_key=vm_info['private_key'])
+        logger.info(f"MTU at VM {vm_info['fip']} is {mtu}")
+        return mtu
+    except Exception as e:
+        print(f"Error on VM {vm_info['fip']}: {e}")
+        return None
+
+
 class SSHTransport(object):
     def __init__(self, address, username, password=None,
                  private_key=None, look_for_keys=False, *args, **kwargs):