1e7e9171eSGeorge Keishing#!/usr/bin/env python3 2ffee58a1SMichael Walsh 3ffee58a1SMichael Walshr""" 4410b1787SMichael WalshThis module provides functions which are useful for running plug-ins from a robot program. 5ffee58a1SMichael Walsh""" 6ffee58a1SMichael Walsh 7e635ddc0SGeorge Keishingimport os 8*20f38712SPatrick Williamsimport subprocess 9*20f38712SPatrick Williamsimport sys 10ffee58a1SMichael Walshimport tempfile 11ffee58a1SMichael Walsh 12e635ddc0SGeorge Keishingimport gen_cmd as gc 13*20f38712SPatrick Williamsimport gen_misc as gm 14*20f38712SPatrick Williamsimport gen_print as gp 15*20f38712SPatrick Williamsfrom robot.libraries.BuiltIn import BuiltIn 16ffee58a1SMichael Walsh 17ffee58a1SMichael Walsh 18*20f38712SPatrick Williamsdef rvalidate_plug_ins(plug_in_dir_paths, quiet=1): 19ffee58a1SMichael Walsh r""" 20410b1787SMichael Walsh Call the external validate_plug_ins.py program which validates the plug-in dir paths given to it. Return 21410b1787SMichael Walsh a list containing a normalized path for each plug-in selected. 22ffee58a1SMichael Walsh 23ffee58a1SMichael Walsh Description of arguments: 24410b1787SMichael Walsh plug_in_dir_paths A colon-separated list of plug-in directory paths. 25410b1787SMichael Walsh quiet If quiet is set to 1, this function will NOT write status messages to 26410b1787SMichael Walsh stdout. 27ffee58a1SMichael Walsh """ 28ffee58a1SMichael Walsh 29*20f38712SPatrick Williams cmd_buf = 'validate_plug_ins.py "' + plug_in_dir_paths + '"' 3036efbc04SGeorge Keishing rc, out_buf = gc.shell_cmd(cmd_buf, print_output=0) 31ffee58a1SMichael Walsh if rc != 0: 32*20f38712SPatrick Williams BuiltIn().fail( 33*20f38712SPatrick Williams gp.sprint_error( 34*20f38712SPatrick Williams "Validate plug ins call failed. See" 35*20f38712SPatrick Williams + " stderr text for details.\n" 36*20f38712SPatrick Williams ) 37*20f38712SPatrick Williams ) 38ffee58a1SMichael Walsh 3936efbc04SGeorge Keishing # plug_in_packages_list = out_buf.split("\n") 4036efbc04SGeorge Keishing plug_in_packages_list = list(filter(None, out_buf.split("\n"))) 41ffee58a1SMichael Walsh if len(plug_in_packages_list) == 1 and plug_in_packages_list[0] == "": 42ffee58a1SMichael Walsh return [] 43ffee58a1SMichael Walsh 44ffee58a1SMichael Walsh return plug_in_packages_list 45ffee58a1SMichael Walsh 46ffee58a1SMichael Walsh 47*20f38712SPatrick Williamsdef rprocess_plug_in_packages( 48*20f38712SPatrick Williams plug_in_packages_list=None, 49ffee58a1SMichael Walsh call_point="setup", 50ffee58a1SMichael Walsh shell_rc="0x00000000", 51ffee58a1SMichael Walsh stop_on_plug_in_failure=1, 52ffee58a1SMichael Walsh stop_on_non_zero_rc=0, 53ffee58a1SMichael Walsh release_type="obmc", 54ffee58a1SMichael Walsh quiet=None, 55fa74bbbaSMichael Walsh debug=None, 56*20f38712SPatrick Williams return_history=False, 57*20f38712SPatrick Williams): 58ffee58a1SMichael Walsh r""" 59410b1787SMichael Walsh Call the external process_plug_in_packages.py to process the plug-in packages. Return the following: 60ffee58a1SMichael Walsh rc The return code - 0 = PASS, 1 = FAIL. 61410b1787SMichael Walsh shell_rc The shell return code returned by process_plug_in_packages.py. 62ffee58a1SMichael Walsh failed_plug_in_name The failed plug in name (if any). 63ffee58a1SMichael Walsh 64ffee58a1SMichael Walsh Description of arguments: 65ffee58a1SMichael Walsh plug_in_packages_list A python list of plug-in directory paths. 66410b1787SMichael Walsh call_point The call point program to be called for each plug-in package (e.g. 67410b1787SMichael Walsh post_boot). This name should not include the "cp_" prefix. 68410b1787SMichael Walsh shell_rc The user may supply a value other than zero to indicate an acceptable 69410b1787SMichael Walsh non-zero return code. For example, if this value equals 0x00000200, it 70410b1787SMichael Walsh means that for each plug-in call point that runs, a 0x00000200 will not 71410b1787SMichael Walsh be counted as a failure. 72410b1787SMichael Walsh stop_on_plug_in_failure If this parameter is set to 1, this program will stop and return non-zero 73410b1787SMichael Walsh if the call point program from any plug-in directory fails. Conversely, 74410b1787SMichael Walsh if it is set to false, this program will run the call point program from 75410b1787SMichael Walsh each and every plug-in directory regardless of their return values. 76410b1787SMichael Walsh Typical example cases where you'd want to run all plug-in call points 77410b1787SMichael Walsh regardless of success or failure would be "cleanup" or "ffdc" call points. 78410b1787SMichael Walsh stop_on_non_zero_rc If this parm is set to 1 and a plug-in call point program returns a valid 79410b1787SMichael Walsh non-zero return code (see "shell_rc" parm above), this program will stop 80410b1787SMichael Walsh processing and return 0 (success). Since this constitutes a successful 81410b1787SMichael Walsh exit, this would normally be used where the caller wishes to stop 82410b1787SMichael Walsh processing if one of the plug-in directory call point programs returns a 83410b1787SMichael Walsh special value indicating that some special case has been found. An 84410b1787SMichael Walsh example might be in calling some kind of "check_errl" call point program. 85410b1787SMichael Walsh Such a call point program might return a 2 (i.e. 0x00000200) to indicate 86410b1787SMichael Walsh that a given error log entry was found in an "ignore" list and is 87410b1787SMichael Walsh therefore to be ignored. That being the case, no other "check_errl" call 88410b1787SMichael Walsh point program would need to be called. 89410b1787SMichael Walsh release_type The type of release being tested (e.g. "obmc", "op", "fips"). This 90410b1787SMichael Walsh influences which integrated plug-ins are selected. 91410b1787SMichael Walsh quiet If quiet is set to 1, this function will NOT write status messages to 92410b1787SMichael Walsh stdout. This will default to the global quiet program parm or to 0. 93410b1787SMichael Walsh debug If this parameter is set to 1, this function will print additional debug 94410b1787SMichael Walsh information. This is mainly to be used by the developer of this 95410b1787SMichael Walsh function. This will default to the global quiet program parm or to 0. 96410b1787SMichael Walsh return_history In addition to rc, shell_rc and failed_plug_in_name, return a list 97410b1787SMichael Walsh containing historical output that looks like the following: 98fa74bbbaSMichael Walsh 99fa74bbbaSMichael Walsh history: 100410b1787SMichael Walsh history[0]: #(CDT) 2018/10/30 12:25:49 - Running OBMC_Sample/cp_post_stack 101ffee58a1SMichael Walsh """ 102ffee58a1SMichael Walsh 103ffee58a1SMichael Walsh rc = 0 104ffee58a1SMichael Walsh 105fa74bbbaSMichael Walsh plug_in_packages_list = gp.get_var_value(plug_in_packages_list, []) 106ffee58a1SMichael Walsh 107ffee58a1SMichael Walsh # If there are no plug-in packages to process, return successfully. 108ffee58a1SMichael Walsh if len(plug_in_packages_list) == 0: 109fa74bbbaSMichael Walsh if return_history: 110fa74bbbaSMichael Walsh return 0, 0, "", [] 111fa74bbbaSMichael Walsh else: 112ffee58a1SMichael Walsh return 0, 0, "" 113ffee58a1SMichael Walsh 114fa74bbbaSMichael Walsh quiet = int(gp.get_var_value(quiet, 0)) 115fa74bbbaSMichael Walsh debug = int(gp.get_var_value(debug, 0)) 116ffee58a1SMichael Walsh 117ffee58a1SMichael Walsh # Create string from list. 118*20f38712SPatrick Williams plug_in_dir_paths = ":".join(plug_in_packages_list) 119ffee58a1SMichael Walsh 120ffee58a1SMichael Walsh temp = tempfile.NamedTemporaryFile() 121ffee58a1SMichael Walsh temp_file_path = temp.name 122ffee58a1SMichael Walsh temp2 = tempfile.NamedTemporaryFile() 123ffee58a1SMichael Walsh temp_properties_file_path = temp2.name 124ffee58a1SMichael Walsh 125fa74bbbaSMichael Walsh if debug: 126ffee58a1SMichael Walsh os.environ["PERF_TRACE"] = "1" 127ffee58a1SMichael Walsh debug_string = " --quiet=0" 128ffee58a1SMichael Walsh else: 129ffee58a1SMichael Walsh debug_string = "" 130ffee58a1SMichael Walsh 131ffee58a1SMichael Walsh loc_shell_rc = 0 132ffee58a1SMichael Walsh 133*20f38712SPatrick Williams sub_cmd_buf = ( 134*20f38712SPatrick Williams "process_plug_in_packages.py" 135*20f38712SPatrick Williams + debug_string 136*20f38712SPatrick Williams + " --call_point=" 137*20f38712SPatrick Williams + call_point 138*20f38712SPatrick Williams + " --allow_shell_rc=" 139*20f38712SPatrick Williams + str(shell_rc) 140*20f38712SPatrick Williams + " --stop_on_plug_in_failure=" 141*20f38712SPatrick Williams + str(stop_on_plug_in_failure) 142*20f38712SPatrick Williams + " --stop_on_non_zero_rc=" 143*20f38712SPatrick Williams + str(stop_on_non_zero_rc) 144*20f38712SPatrick Williams + " " 145*20f38712SPatrick Williams + plug_in_dir_paths 146*20f38712SPatrick Williams ) 147fa74bbbaSMichael Walsh if quiet: 148ffee58a1SMichael Walsh cmd_buf = sub_cmd_buf + " > " + temp_file_path + " 2>&1" 149ffee58a1SMichael Walsh else: 150*20f38712SPatrick Williams cmd_buf = ( 151*20f38712SPatrick Williams "set -o pipefail ; " 152*20f38712SPatrick Williams + sub_cmd_buf 153*20f38712SPatrick Williams + " 2>&1 | tee " 154*20f38712SPatrick Williams + temp_file_path 155*20f38712SPatrick Williams ) 156fa74bbbaSMichael Walsh if debug: 157fa74bbbaSMichael Walsh gp.print_issuing(cmd_buf) 15809305180SMichael Walsh else: 159*20f38712SPatrick Williams gp.print_timen( 160*20f38712SPatrick Williams "Processing " + call_point + " call point programs." 161*20f38712SPatrick Williams ) 162ffee58a1SMichael Walsh 163*20f38712SPatrick Williams sub_proc = subprocess.Popen(cmd_buf, shell=True, executable="/bin/bash") 16435c4c62fSMichael Walsh sub_proc.communicate() 16535c4c62fSMichael Walsh proc_plug_pkg_rc = sub_proc.returncode 166ffee58a1SMichael Walsh 167fa74bbbaSMichael Walsh if return_history: 168fa74bbbaSMichael Walsh # Get the "Running" statements from the output. 169fa74bbbaSMichael Walsh regex = " Running [^/]+/cp_" 170fa74bbbaSMichael Walsh cmd_buf = "egrep '" + regex + "' " + temp_file_path 171*20f38712SPatrick Williams _, history = gc.shell_cmd( 172*20f38712SPatrick Williams cmd_buf, 173*20f38712SPatrick Williams quiet=(not debug), 174*20f38712SPatrick Williams print_output=0, 175*20f38712SPatrick Williams show_err=0, 176*20f38712SPatrick Williams ignore_err=1, 177*20f38712SPatrick Williams ) 178fa74bbbaSMichael Walsh history = [x + "\n" for x in filter(None, history.split("\n"))] 179fa74bbbaSMichael Walsh else: 180fa74bbbaSMichael Walsh history = [] 181fa74bbbaSMichael Walsh 182410b1787SMichael Walsh # As process_plug_in_packages.py help text states, it will print the values of failed_plug_in_name and 183410b1787SMichael Walsh # shell_rc in the following format: 184ffee58a1SMichael Walsh # failed_plug_in_name: <failed plug-in value, if any> 185410b1787SMichael Walsh # shell_rc: <shell return code value of last call point program> 186ffee58a1SMichael Walsh 187410b1787SMichael Walsh # We want to obtain those values from the output. To make the task simpler, we'll start by grepping the 188410b1787SMichael Walsh # output for lines that might fit such a format: 189fa74bbbaSMichael Walsh # A valid bash variable against the left margin followed by... 190fa74bbbaSMichael Walsh # - A colon followed by... 191ffee58a1SMichael Walsh # - Zero or more spaces 192957a2b26SMichael Walsh bash_var_regex = "[_[:alpha:]][_[:alnum:]]*" 193957a2b26SMichael Walsh regex = "^" + bash_var_regex + ":[ ]*" 194*20f38712SPatrick Williams cmd_buf = ( 195*20f38712SPatrick Williams "egrep '" 196*20f38712SPatrick Williams + regex 197*20f38712SPatrick Williams + "' " 198*20f38712SPatrick Williams + temp_file_path 199*20f38712SPatrick Williams + " > " 200*20f38712SPatrick Williams + temp_properties_file_path 201*20f38712SPatrick Williams ) 202fa74bbbaSMichael Walsh gp.dprint_issuing(cmd_buf) 203957a2b26SMichael Walsh grep_rc = os.system(cmd_buf) 204ffee58a1SMichael Walsh 205ffee58a1SMichael Walsh # Next we call my_parm_file to create a properties dictionary. 206ffee58a1SMichael Walsh properties = gm.my_parm_file(temp_properties_file_path) 207ffee58a1SMichael Walsh 208ffee58a1SMichael Walsh # Finally, we access the 2 values that we need. 209*20f38712SPatrick Williams shell_rc = int(properties.get("shell_rc", "0x0000000000000000"), 16) 210*20f38712SPatrick Williams failed_plug_in_name = properties.get("failed_plug_in_name", "") 211ffee58a1SMichael Walsh 212957a2b26SMichael Walsh if proc_plug_pkg_rc != 0: 2130a3bdb4cSMichael Walsh if quiet: 2140a3bdb4cSMichael Walsh os.system("cat " + temp_file_path + " >&2") 215fa74bbbaSMichael Walsh if grep_rc != 0: 2160d5f96a4SMichael Walsh gp.print_var(grep_rc, gp.hexa()) 2170d5f96a4SMichael Walsh gp.print_var(proc_plug_pkg_rc, gp.hexa()) 218fa74bbbaSMichael Walsh gp.print_timen("Re-cap of plug-in failures:") 219*20f38712SPatrick Williams gc.cmd_fnc_u( 220*20f38712SPatrick Williams "egrep -A 1 '^failed_plug_in_name:[ ]+' " 221*20f38712SPatrick Williams + temp_properties_file_path 222*20f38712SPatrick Williams + " | egrep -v '^\\--'", 223*20f38712SPatrick Williams quiet=1, 224*20f38712SPatrick Williams show_err=0, 225*20f38712SPatrick Williams ) 22640822372SMichael Walsh rc = 1 227ffee58a1SMichael Walsh 228fa74bbbaSMichael Walsh if return_history: 229fa74bbbaSMichael Walsh return rc, shell_rc, failed_plug_in_name, history 230fa74bbbaSMichael Walsh else: 231ffee58a1SMichael Walsh return rc, shell_rc, failed_plug_in_name 232