Add multithreading while installing salt-minions
PROD-37096

Change-Id: Ia6126fb0cb3cc9a286ecf802516b49550175b759
diff --git a/tcp_tests/managers/execute_commands.py b/tcp_tests/managers/execute_commands.py
index 6dcf615..314c641 100644
--- a/tcp_tests/managers/execute_commands.py
+++ b/tcp_tests/managers/execute_commands.py
@@ -1,8 +1,9 @@
 
 import time
 
-from tcp_tests import logger
+from tcp_tests import logger, settings
 from tcp_tests.helpers.log_helpers import pretty_repr
+from tcp_tests.helpers.utils import Worker
 
 LOG = logger.logger
 
@@ -36,6 +37,8 @@
                 'node_name': 'name of the node to run the command(s)',
                 # Optional:
                 'description': 'string with a readable command description',
+                'parallel': 'bool (True of False) to enable executing these
+                            type of command in multithreading'
                 'retry': {
                     'count': int,  # How many times should be run the command
                                    # until success
@@ -49,6 +52,7 @@
             ...
         ]
         """
+        worker = Worker(limit=settings.THREADS, timeout=3*60)
         for n, step in enumerate(commands):
             # Required fields
             action_cmd = step.get('cmd')
@@ -67,7 +71,19 @@
             log_msg = "\n\n{0}\n{1}".format(msg, '=' * len(msg))
 
             if action_cmd:
-                self.execute_command(step, msg)
+                if step.get('parallel'):
+                    name = description + " on " + step.get("node_name")
+                    worker.start(func=self.execute_command,
+                                 args=(step, msg),
+                                 name=name
+                                 )
+                else:
+                    while not worker.are_completed():
+                        LOG.info("Waiting {}".format(worker.pool))
+                    if worker.all_tasks_successfully_completed():
+                        worker.clean_pool()
+                    self.execute_command(step, msg)
+
             elif action_do:
                 self.command2(step, msg)
             elif action_upload:
@@ -77,6 +93,12 @@
                 LOG.info(log_msg)
                 self.action_download(step)
 
+        while not worker.are_completed():
+            LOG.info("Waiting {}".format(worker.pool))
+
+        assert worker.all_tasks_successfully_completed(), \
+            worker.print_failed_tasks()
+
     def execute_command(self, step, msg, return_res=None):
         # Required fields
         cmd = step.get('cmd')
@@ -90,7 +112,6 @@
         timeout = step.get('timeout', None)
 
         with self.__underlay.remote(node_name=node_name) as remote:
-
             for x in range(retry_count, 0, -1):
                 time.sleep(3)