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