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