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