| #!/usr/bin/env python3 | 
 |  | 
 | r""" | 
 | This module provides functions which are useful for running plug-ins from a robot program. | 
 | """ | 
 |  | 
 | import os | 
 | import subprocess | 
 | import sys | 
 | import tempfile | 
 |  | 
 | import gen_cmd as gc | 
 | import gen_misc as gm | 
 | import gen_print as gp | 
 | from robot.libraries.BuiltIn import BuiltIn | 
 |  | 
 |  | 
 | def rvalidate_plug_ins(plug_in_dir_paths, quiet=1): | 
 |     r""" | 
 |     Call the external validate_plug_ins.py program which validates the plug-in dir paths given to it.  Return | 
 |     a list containing a normalized path for each plug-in selected. | 
 |  | 
 |     Description of arguments: | 
 |     plug_in_dir_paths               A colon-separated list of plug-in directory paths. | 
 |     quiet                           If quiet is set to 1, this function will NOT write status messages to | 
 |                                     stdout. | 
 |     """ | 
 |  | 
 |     cmd_buf = 'validate_plug_ins.py "' + plug_in_dir_paths + '"' | 
 |     rc, out_buf = gc.shell_cmd(cmd_buf, print_output=0) | 
 |     if rc != 0: | 
 |         BuiltIn().fail( | 
 |             gp.sprint_error( | 
 |                 "Validate plug ins call failed.  See" | 
 |                 + " stderr text for details.\n" | 
 |             ) | 
 |         ) | 
 |  | 
 |     # plug_in_packages_list = out_buf.split("\n") | 
 |     plug_in_packages_list = list(filter(None, out_buf.split("\n"))) | 
 |     if len(plug_in_packages_list) == 1 and plug_in_packages_list[0] == "": | 
 |         return [] | 
 |  | 
 |     return plug_in_packages_list | 
 |  | 
 |  | 
 | def rprocess_plug_in_packages( | 
 |     plug_in_packages_list=None, | 
 |     call_point="setup", | 
 |     shell_rc="0x00000000", | 
 |     stop_on_plug_in_failure=1, | 
 |     stop_on_non_zero_rc=0, | 
 |     release_type="obmc", | 
 |     quiet=None, | 
 |     debug=None, | 
 |     return_history=False, | 
 | ): | 
 |     r""" | 
 |     Call the external process_plug_in_packages.py to process the plug-in packages.  Return the following: | 
 |     rc                              The return code - 0 = PASS, 1 = FAIL. | 
 |     shell_rc                        The shell return code returned by process_plug_in_packages.py. | 
 |     failed_plug_in_name             The failed plug in name (if any). | 
 |  | 
 |     Description of arguments: | 
 |     plug_in_packages_list           A python list of plug-in directory paths. | 
 |     call_point                      The call point program to be called for each plug-in package (e.g. | 
 |                                     post_boot).  This name should not include the "cp_" prefix. | 
 |     shell_rc                        The user may supply a value other than zero to indicate an acceptable | 
 |                                     non-zero return code.  For example, if this value equals 0x00000200, it | 
 |                                     means that for each plug-in call point that runs, a 0x00000200 will not | 
 |                                     be counted as a failure. | 
 |     stop_on_plug_in_failure         If this parameter is set to 1, this program will stop and return non-zero | 
 |                                     if the call point program from any plug-in directory fails.  Conversely, | 
 |                                     if it is set to false, this program will run the call point program from | 
 |                                     each and every plug-in directory regardless of their return values. | 
 |                                     Typical example cases where you'd want to run all plug-in call points | 
 |                                     regardless of success or failure would be "cleanup" or "ffdc" call points. | 
 |     stop_on_non_zero_rc             If this parm is set to 1 and a plug-in call point program returns a valid | 
 |                                     non-zero return code (see "shell_rc" parm above), this program will stop | 
 |                                     processing and return 0 (success).  Since this constitutes a successful | 
 |                                     exit, this would normally be used where the caller wishes to stop | 
 |                                     processing if one of the plug-in directory call point programs returns a | 
 |                                     special value indicating that some special case has been found.  An | 
 |                                     example might be in calling some kind of "check_errl" call point program. | 
 |                                     Such a call point program might return a 2 (i.e. 0x00000200) to indicate | 
 |                                     that a given error log entry was found in an "ignore" list and is | 
 |                                     therefore to be ignored.  That being the case, no other "check_errl" call | 
 |                                     point program would need to be called. | 
 |     release_type                    The type of release being tested (e.g. "obmc", "op", "fips").  This | 
 |                                     influences which integrated plug-ins are selected. | 
 |     quiet                           If quiet is set to 1, this function will NOT write status messages to | 
 |                                     stdout.  This will default to the global quiet program parm or to 0. | 
 |     debug                           If this parameter is set to 1, this function will print additional debug | 
 |                                     information.  This is mainly to be used by the developer of this | 
 |                                     function.  This will default to the global quiet program parm or to 0. | 
 |     return_history                  In addition to rc, shell_rc and failed_plug_in_name, return a list | 
 |                                     containing historical output that looks like the following: | 
 |  | 
 |     history: | 
 |       history[0]:                   #(CDT) 2018/10/30 12:25:49 - Running OBMC_Sample/cp_post_stack | 
 |     """ | 
 |  | 
 |     rc = 0 | 
 |  | 
 |     plug_in_packages_list = gp.get_var_value(plug_in_packages_list, []) | 
 |  | 
 |     # If there are no plug-in packages to process, return successfully. | 
 |     if len(plug_in_packages_list) == 0: | 
 |         if return_history: | 
 |             return 0, 0, "", [] | 
 |         else: | 
 |             return 0, 0, "" | 
 |  | 
 |     quiet = int(gp.get_var_value(quiet, 0)) | 
 |     debug = int(gp.get_var_value(debug, 0)) | 
 |  | 
 |     # Create string from list. | 
 |     plug_in_dir_paths = ":".join(plug_in_packages_list) | 
 |  | 
 |     temp = tempfile.NamedTemporaryFile() | 
 |     temp_file_path = temp.name | 
 |     temp2 = tempfile.NamedTemporaryFile() | 
 |     temp_properties_file_path = temp2.name | 
 |  | 
 |     if debug: | 
 |         os.environ["PERF_TRACE"] = "1" | 
 |         debug_string = " --quiet=0" | 
 |     else: | 
 |         debug_string = "" | 
 |  | 
 |     loc_shell_rc = 0 | 
 |  | 
 |     sub_cmd_buf = ( | 
 |         "process_plug_in_packages.py" | 
 |         + debug_string | 
 |         + " --call_point=" | 
 |         + call_point | 
 |         + " --allow_shell_rc=" | 
 |         + str(shell_rc) | 
 |         + " --stop_on_plug_in_failure=" | 
 |         + str(stop_on_plug_in_failure) | 
 |         + " --stop_on_non_zero_rc=" | 
 |         + str(stop_on_non_zero_rc) | 
 |         + " " | 
 |         + plug_in_dir_paths | 
 |     ) | 
 |     if quiet: | 
 |         cmd_buf = sub_cmd_buf + " > " + temp_file_path + " 2>&1" | 
 |     else: | 
 |         cmd_buf = ( | 
 |             "set -o pipefail ; " | 
 |             + sub_cmd_buf | 
 |             + " 2>&1 | tee " | 
 |             + temp_file_path | 
 |         ) | 
 |         if debug: | 
 |             gp.print_issuing(cmd_buf) | 
 |         else: | 
 |             gp.print_timen( | 
 |                 "Processing " + call_point + " call point programs." | 
 |             ) | 
 |  | 
 |     sub_proc = subprocess.Popen(cmd_buf, shell=True, executable="/bin/bash") | 
 |     sub_proc.communicate() | 
 |     proc_plug_pkg_rc = sub_proc.returncode | 
 |  | 
 |     if return_history: | 
 |         # Get the "Running" statements from the output. | 
 |         regex = " Running [^/]+/cp_" | 
 |         cmd_buf = "egrep '" + regex + "' " + temp_file_path | 
 |         _, history = gc.shell_cmd( | 
 |             cmd_buf, | 
 |             quiet=(not debug), | 
 |             print_output=0, | 
 |             show_err=0, | 
 |             ignore_err=1, | 
 |         ) | 
 |         history = [x + "\n" for x in filter(None, history.split("\n"))] | 
 |     else: | 
 |         history = [] | 
 |  | 
 |     # As process_plug_in_packages.py help text states, it will print the values of failed_plug_in_name and | 
 |     # shell_rc in the following format: | 
 |     # failed_plug_in_name:               <failed plug-in value, if any> | 
 |     # shell_rc:                          <shell return code value of last call point program> | 
 |  | 
 |     # We want to obtain those values from the output.  To make the task simpler, we'll start by grepping the | 
 |     # output for lines that might fit such a format: | 
 |     # A valid bash variable against the left margin followed by... | 
 |     # - A colon followed by... | 
 |     # - Zero or more spaces | 
 |     bash_var_regex = "[_[:alpha:]][_[:alnum:]]*" | 
 |     regex = "^" + bash_var_regex + ":[ ]*" | 
 |     cmd_buf = ( | 
 |         "egrep '" | 
 |         + regex | 
 |         + "' " | 
 |         + temp_file_path | 
 |         + " > " | 
 |         + temp_properties_file_path | 
 |     ) | 
 |     gp.dprint_issuing(cmd_buf) | 
 |     grep_rc = os.system(cmd_buf) | 
 |  | 
 |     # Next we call my_parm_file to create a properties dictionary. | 
 |     properties = gm.my_parm_file(temp_properties_file_path) | 
 |  | 
 |     # Finally, we access the 2 values that we need. | 
 |     shell_rc = int(properties.get("shell_rc", "0x0000000000000000"), 16) | 
 |     failed_plug_in_name = properties.get("failed_plug_in_name", "") | 
 |  | 
 |     if proc_plug_pkg_rc != 0: | 
 |         if quiet: | 
 |             os.system("cat " + temp_file_path + " >&2") | 
 |         if grep_rc != 0: | 
 |             gp.print_var(grep_rc, gp.hexa()) | 
 |         gp.print_var(proc_plug_pkg_rc, gp.hexa()) | 
 |         gp.print_timen("Re-cap of plug-in failures:") | 
 |         gc.cmd_fnc_u( | 
 |             "egrep -A 1 '^failed_plug_in_name:[ ]+' " | 
 |             + temp_properties_file_path | 
 |             + " | egrep -v '^\\--'", | 
 |             quiet=1, | 
 |             show_err=0, | 
 |         ) | 
 |         rc = 1 | 
 |  | 
 |     if return_history: | 
 |         return rc, shell_rc, failed_plug_in_name, history | 
 |     else: | 
 |         return rc, shell_rc, failed_plug_in_name |