1#!/usr/bin/env python 2 3r""" 4This module provides functions which are useful for running plug-ins from a robot program. 5""" 6 7import sys 8import subprocess 9from robot.libraries.BuiltIn import BuiltIn 10import os 11import tempfile 12 13import gen_print as gp 14import gen_misc as gm 15import gen_cmd as gc 16 17 18def rvalidate_plug_ins(plug_in_dir_paths, 19 quiet=1): 20 r""" 21 Call the external validate_plug_ins.py program which validates the plug-in dir paths given to it. Return 22 a list containing a normalized path for each plug-in selected. 23 24 Description of arguments: 25 plug_in_dir_paths A colon-separated list of plug-in directory paths. 26 quiet If quiet is set to 1, this function will NOT write status messages to 27 stdout. 28 """ 29 30 cmd_buf = "validate_plug_ins.py \"" + plug_in_dir_paths + "\"" 31 rc, out_buf = gc.shell_cmd(cmd_buf, print_output=0) 32 if rc != 0: 33 BuiltIn().fail(gp.sprint_error("Validate plug ins call failed. See" 34 + " stderr text for details.\n")) 35 36 # plug_in_packages_list = out_buf.split("\n") 37 plug_in_packages_list = list(filter(None, out_buf.split("\n"))) 38 if len(plug_in_packages_list) == 1 and plug_in_packages_list[0] == "": 39 return [] 40 41 return plug_in_packages_list 42 43 44def rprocess_plug_in_packages(plug_in_packages_list=None, 45 call_point="setup", 46 shell_rc="0x00000000", 47 stop_on_plug_in_failure=1, 48 stop_on_non_zero_rc=0, 49 release_type="obmc", 50 quiet=None, 51 debug=None, 52 return_history=False): 53 r""" 54 Call the external process_plug_in_packages.py to process the plug-in packages. Return the following: 55 rc The return code - 0 = PASS, 1 = FAIL. 56 shell_rc The shell return code returned by process_plug_in_packages.py. 57 failed_plug_in_name The failed plug in name (if any). 58 59 Description of arguments: 60 plug_in_packages_list A python list of plug-in directory paths. 61 call_point The call point program to be called for each plug-in package (e.g. 62 post_boot). This name should not include the "cp_" prefix. 63 shell_rc The user may supply a value other than zero to indicate an acceptable 64 non-zero return code. For example, if this value equals 0x00000200, it 65 means that for each plug-in call point that runs, a 0x00000200 will not 66 be counted as a failure. 67 stop_on_plug_in_failure If this parameter is set to 1, this program will stop and return non-zero 68 if the call point program from any plug-in directory fails. Conversely, 69 if it is set to false, this program will run the call point program from 70 each and every plug-in directory regardless of their return values. 71 Typical example cases where you'd want to run all plug-in call points 72 regardless of success or failure would be "cleanup" or "ffdc" call points. 73 stop_on_non_zero_rc If this parm is set to 1 and a plug-in call point program returns a valid 74 non-zero return code (see "shell_rc" parm above), this program will stop 75 processing and return 0 (success). Since this constitutes a successful 76 exit, this would normally be used where the caller wishes to stop 77 processing if one of the plug-in directory call point programs returns a 78 special value indicating that some special case has been found. An 79 example might be in calling some kind of "check_errl" call point program. 80 Such a call point program might return a 2 (i.e. 0x00000200) to indicate 81 that a given error log entry was found in an "ignore" list and is 82 therefore to be ignored. That being the case, no other "check_errl" call 83 point program would need to be called. 84 release_type The type of release being tested (e.g. "obmc", "op", "fips"). This 85 influences which integrated plug-ins are selected. 86 quiet If quiet is set to 1, this function will NOT write status messages to 87 stdout. This will default to the global quiet program parm or to 0. 88 debug If this parameter is set to 1, this function will print additional debug 89 information. This is mainly to be used by the developer of this 90 function. This will default to the global quiet program parm or to 0. 91 return_history In addition to rc, shell_rc and failed_plug_in_name, return a list 92 containing historical output that looks like the following: 93 94 history: 95 history[0]: #(CDT) 2018/10/30 12:25:49 - Running OBMC_Sample/cp_post_stack 96 """ 97 98 rc = 0 99 100 plug_in_packages_list = gp.get_var_value(plug_in_packages_list, []) 101 102 # If there are no plug-in packages to process, return successfully. 103 if len(plug_in_packages_list) == 0: 104 if return_history: 105 return 0, 0, "", [] 106 else: 107 return 0, 0, "" 108 109 quiet = int(gp.get_var_value(quiet, 0)) 110 debug = int(gp.get_var_value(debug, 0)) 111 112 # Create string from list. 113 plug_in_dir_paths = ':'.join(plug_in_packages_list) 114 115 temp = tempfile.NamedTemporaryFile() 116 temp_file_path = temp.name 117 temp2 = tempfile.NamedTemporaryFile() 118 temp_properties_file_path = temp2.name 119 120 if debug: 121 os.environ["PERF_TRACE"] = "1" 122 debug_string = " --quiet=0" 123 else: 124 debug_string = "" 125 126 loc_shell_rc = 0 127 128 sub_cmd_buf = "process_plug_in_packages.py" + debug_string +\ 129 " --call_point=" + call_point + " --allow_shell_rc=" +\ 130 str(shell_rc) + " --stop_on_plug_in_failure=" +\ 131 str(stop_on_plug_in_failure) + " --stop_on_non_zero_rc=" +\ 132 str(stop_on_non_zero_rc) + " " + plug_in_dir_paths 133 if quiet: 134 cmd_buf = sub_cmd_buf + " > " + temp_file_path + " 2>&1" 135 else: 136 cmd_buf = "set -o pipefail ; " + sub_cmd_buf + " 2>&1 | tee " +\ 137 temp_file_path 138 if debug: 139 gp.print_issuing(cmd_buf) 140 else: 141 gp.print_timen("Processing " + call_point 142 + " call point programs.") 143 144 proc_plug_pkg_rc = subprocess.call(cmd_buf, shell=True, 145 executable='/bin/bash') 146 147 if return_history: 148 # Get the "Running" statements from the output. 149 regex = " Running [^/]+/cp_" 150 cmd_buf = "egrep '" + regex + "' " + temp_file_path 151 _, history = gc.shell_cmd(cmd_buf, quiet=(not debug), print_output=0, 152 show_err=0, ignore_err=1) 153 history = [x + "\n" for x in filter(None, history.split("\n"))] 154 else: 155 history = [] 156 157 # As process_plug_in_packages.py help text states, it will print the values of failed_plug_in_name and 158 # shell_rc in the following format: 159 # failed_plug_in_name: <failed plug-in value, if any> 160 # shell_rc: <shell return code value of last call point program> 161 162 # We want to obtain those values from the output. To make the task simpler, we'll start by grepping the 163 # output for lines that might fit such a format: 164 # A valid bash variable against the left margin followed by... 165 # - A colon followed by... 166 # - Zero or more spaces 167 bash_var_regex = "[_[:alpha:]][_[:alnum:]]*" 168 regex = "^" + bash_var_regex + ":[ ]*" 169 cmd_buf = "egrep '" + regex + "' " + temp_file_path + " > " +\ 170 temp_properties_file_path 171 gp.dprint_issuing(cmd_buf) 172 grep_rc = os.system(cmd_buf) 173 174 # Next we call my_parm_file to create a properties dictionary. 175 properties = gm.my_parm_file(temp_properties_file_path) 176 177 # Finally, we access the 2 values that we need. 178 shell_rc = int(properties.get('shell_rc', '0x0000000000000000'), 16) 179 failed_plug_in_name = properties.get('failed_plug_in_name', '') 180 181 if proc_plug_pkg_rc != 0: 182 if quiet: 183 os.system("cat " + temp_file_path + " >&2") 184 if grep_rc != 0: 185 gp.print_var(grep_rc, gp.hexa()) 186 gp.print_var(proc_plug_pkg_rc, gp.hexa()) 187 gp.print_timen("Re-cap of plug-in failures:") 188 gc.cmd_fnc_u("egrep -A 1 '^failed_plug_in_name:[ ]+' " 189 + temp_properties_file_path + " | egrep -v '^\\--'", 190 quiet=1, show_err=0) 191 rc = 1 192 193 if return_history: 194 return rc, shell_rc, failed_plug_in_name, history 195 else: 196 return rc, shell_rc, failed_plug_in_name 197