|  | #!/usr/bin/env python | 
|  |  | 
|  | r""" | 
|  | This module provides functions which are useful for running plug-ins from a | 
|  | robot program. | 
|  | """ | 
|  |  | 
|  | import sys | 
|  | import subprocess | 
|  | from robot.libraries.BuiltIn import BuiltIn | 
|  | import os | 
|  | import tempfile | 
|  |  | 
|  | import gen_print as gp | 
|  | import gen_misc as gm | 
|  | import gen_cmd as gc | 
|  |  | 
|  |  | 
|  | 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.") | 
|  |  | 
|  | proc_plug_pkg_rc = subprocess.call(cmd_buf, shell=True, | 
|  | executable='/bin/bash') | 
|  |  | 
|  | 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 |