Add initial support for SHELL script execution in YAML

What is supported:
   - User can ONLY run script local to the collector script
     is executed.
   - User pre-append the SHELL type in YAML.

What is not supported:
   - Script has no logic to understand what type of SHELL.

How to test:
OEM:
    OEM_LOGS:
        COMMANDS:
            - sh myscript  ${hostname}
            - bash myscript  ${hostname}
        FILES:
            - 'shell_script_capture.txt'
            - 'bash_script_capture.txt'
        PROTOCOL:
            - 'SHELL'

Change-Id: Ib5adeb2c6bba5565c98d23c8e9309cd4b4c634b0
Signed-off-by: George Keishing <gkeishin@in.ibm.com>
diff --git a/ffdc/ffdc_collector.py b/ffdc/ffdc_collector.py
index a50b494..220646c 100644
--- a/ffdc/ffdc_collector.py
+++ b/ffdc/ffdc_collector.py
@@ -48,6 +48,14 @@
         self.hostname = hostname
         self.username = username
         self.password = password
+        # This is for the env vars a user can use in YAML to load it at runtime.
+        # Example YAML:
+        # -COMMANDS:
+        #    - my_command ${hostname}  ${username}   ${password}
+        os.environ['hostname'] = hostname
+        os.environ['username'] = username
+        os.environ['password'] = password
+
         self.ffdc_config = ffdc_config
         self.location = location + "/" + remote_type.upper()
         self.ssh_remoteclient = None
@@ -155,6 +163,7 @@
         self.start_time = time.time()
         working_protocol_list = []
         if self.target_is_pingable():
+            working_protocol_list.append("SHELL")
             # Check supported protocol ping,ssh, redfish are working.
             if self.ssh_to_target_system():
                 working_protocol_list.append("SSH")
@@ -276,7 +285,13 @@
                     if 'IPMI' in working_protocol_list:
                         self.protocol_ipmi(ffdc_actions, machine_type, k)
                     else:
-                        self.logger.error("\n\tERROR: IMPI is not available for %s." % self.hostname)
+                        print("\n\tERROR: IMPI is not available for %s." % self.hostname)
+
+                if ffdc_actions[machine_type][k]['PROTOCOL'][0] == 'SHELL':
+                    if 'SHELL' in working_protocol_list:
+                        self.protocol_shell_script(ffdc_actions, machine_type, k)
+                    else:
+                        self.logger.error("\n\tERROR: can't execute SHELL script")
 
         # Close network connection after collecting all files
         self.elapsed_time = time.strftime("%H:%M:%S", time.gmtime(time.time() - self.start_time))
@@ -733,3 +748,72 @@
             self.logger.error('\t\t' + result.stderr)
 
         return result.stdout
+
+    def run_shell_script(self,
+                         parms_string,
+                         quiet=False):
+        r"""
+        Run CLI shell script tool.
+
+        Description of variable:
+        parms_string         script command options.
+        quiet                do not print redfishtool error message if True
+        """
+
+        result = subprocess.run([parms_string],
+                                stdout=subprocess.PIPE,
+                                stderr=subprocess.PIPE,
+                                shell=True,
+                                universal_newlines=True)
+
+        if result.stderr and not quiet:
+            self.logger.error('\n\t\tERROR executing %s' % parms_string)
+            self.logger.error('\t\t' + result.stderr)
+
+        return result.stdout
+
+    def protocol_shell_script(self,
+                              ffdc_actions,
+                              machine_type,
+                              sub_type):
+        r"""
+        Perform SHELL script execution locally.
+
+        Description of argument(s):
+        ffdc_actions        List of actions from ffdc_config.yaml.
+        machine_type        OS Type of remote host.
+        sub_type            Group type of commands.
+        """
+
+        self.logger.info("\n\t[Run] Executing commands to %s using %s" % (self.hostname, 'SHELL'))
+        shell_files_saved = []
+        progress_counter = 0
+        list_of_cmd = self.get_command_list(ffdc_actions[machine_type][sub_type])
+        for index, each_cmd in enumerate(list_of_cmd, start=0):
+
+            result = self.run_shell_script(each_cmd)
+            if result:
+                try:
+                    targ_file = self.get_file_list(ffdc_actions[machine_type][sub_type])[index]
+                except IndexError:
+                    targ_file = each_cmd.split('/')[-1]
+                    self.logger.warning("\n\t[WARN] Missing filename to store data %s." % each_cmd)
+                    self.logger.warning("\t[WARN] Data will be stored in %s." % targ_file)
+
+                targ_file_with_path = (self.ffdc_dir_path
+                                       + self.ffdc_prefix
+                                       + targ_file)
+
+                # Creates a new file
+                with open(targ_file_with_path, 'w') as fp:
+                    fp.write(result)
+                    fp.close
+                    shell_files_saved.append(targ_file)
+
+            progress_counter += 1
+            self.print_progress(progress_counter)
+
+        self.logger.info("\n\t[Run] Commands execution completed.\t\t [OK]")
+
+        for file in shell_files_saved:
+            self.logger.info("\n\t\tSuccessfully save file " + file + ".")