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