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