blob: 77a1f35b96282bac92408843b73f1deffb0ab6ac [file] [log] [blame]
George Keishinge7e91712021-09-03 11:28:44 -05001#!/usr/bin/env python3
Michael Walshffee58a2016-11-22 11:28:33 -06002
3r"""
Michael Walsh410b1782019-10-22 15:56:18 -05004This module provides functions which are useful for running plug-ins from a robot program.
Michael Walshffee58a2016-11-22 11:28:33 -06005"""
6
George Keishinge635ddc2022-12-08 07:38:02 -06007import os
Patrick Williams20f38712022-12-08 06:18:26 -06008import subprocess
9import sys
Michael Walshffee58a2016-11-22 11:28:33 -060010import tempfile
11
George Keishinge635ddc2022-12-08 07:38:02 -060012import gen_cmd as gc
Patrick Williams20f38712022-12-08 06:18:26 -060013import gen_misc as gm
14import gen_print as gp
15from robot.libraries.BuiltIn import BuiltIn
Michael Walshffee58a2016-11-22 11:28:33 -060016
17
Patrick Williams20f38712022-12-08 06:18:26 -060018def rvalidate_plug_ins(plug_in_dir_paths, quiet=1):
Michael Walshffee58a2016-11-22 11:28:33 -060019 r"""
Michael Walsh410b1782019-10-22 15:56:18 -050020 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 Walshffee58a2016-11-22 11:28:33 -060022
23 Description of arguments:
Michael Walsh410b1782019-10-22 15:56:18 -050024 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 Walshffee58a2016-11-22 11:28:33 -060027 """
28
Patrick Williams20f38712022-12-08 06:18:26 -060029 cmd_buf = 'validate_plug_ins.py "' + plug_in_dir_paths + '"'
George Keishing36efbc02018-12-12 10:18:23 -060030 rc, out_buf = gc.shell_cmd(cmd_buf, print_output=0)
Michael Walshffee58a2016-11-22 11:28:33 -060031 if rc != 0:
Patrick Williams20f38712022-12-08 06:18:26 -060032 BuiltIn().fail(
33 gp.sprint_error(
34 "Validate plug ins call failed. See"
35 + " stderr text for details.\n"
36 )
37 )
Michael Walshffee58a2016-11-22 11:28:33 -060038
George Keishing36efbc02018-12-12 10:18:23 -060039 # plug_in_packages_list = out_buf.split("\n")
40 plug_in_packages_list = list(filter(None, out_buf.split("\n")))
Michael Walshffee58a2016-11-22 11:28:33 -060041 if len(plug_in_packages_list) == 1 and plug_in_packages_list[0] == "":
42 return []
43
44 return plug_in_packages_list
45
Michael Walshffee58a2016-11-22 11:28:33 -060046
Patrick Williams20f38712022-12-08 06:18:26 -060047def 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 Walshffee58a2016-11-22 11:28:33 -060058 r"""
Michael Walsh410b1782019-10-22 15:56:18 -050059 Call the external process_plug_in_packages.py to process the plug-in packages. Return the following:
Michael Walshffee58a2016-11-22 11:28:33 -060060 rc The return code - 0 = PASS, 1 = FAIL.
Michael Walsh410b1782019-10-22 15:56:18 -050061 shell_rc The shell return code returned by process_plug_in_packages.py.
Michael Walshffee58a2016-11-22 11:28:33 -060062 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 Walsh410b1782019-10-22 15:56:18 -050066 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 Walshfa74bbb2018-10-30 13:21:03 -050098
99 history:
Michael Walsh410b1782019-10-22 15:56:18 -0500100 history[0]: #(CDT) 2018/10/30 12:25:49 - Running OBMC_Sample/cp_post_stack
Michael Walshffee58a2016-11-22 11:28:33 -0600101 """
102
103 rc = 0
104
Michael Walshfa74bbb2018-10-30 13:21:03 -0500105 plug_in_packages_list = gp.get_var_value(plug_in_packages_list, [])
Michael Walshffee58a2016-11-22 11:28:33 -0600106
107 # If there are no plug-in packages to process, return successfully.
108 if len(plug_in_packages_list) == 0:
Michael Walshfa74bbb2018-10-30 13:21:03 -0500109 if return_history:
110 return 0, 0, "", []
111 else:
112 return 0, 0, ""
Michael Walshffee58a2016-11-22 11:28:33 -0600113
Michael Walshfa74bbb2018-10-30 13:21:03 -0500114 quiet = int(gp.get_var_value(quiet, 0))
115 debug = int(gp.get_var_value(debug, 0))
Michael Walshffee58a2016-11-22 11:28:33 -0600116
117 # Create string from list.
Patrick Williams20f38712022-12-08 06:18:26 -0600118 plug_in_dir_paths = ":".join(plug_in_packages_list)
Michael Walshffee58a2016-11-22 11:28:33 -0600119
120 temp = tempfile.NamedTemporaryFile()
121 temp_file_path = temp.name
122 temp2 = tempfile.NamedTemporaryFile()
123 temp_properties_file_path = temp2.name
124
Michael Walshfa74bbb2018-10-30 13:21:03 -0500125 if debug:
Michael Walshffee58a2016-11-22 11:28:33 -0600126 os.environ["PERF_TRACE"] = "1"
127 debug_string = " --quiet=0"
128 else:
129 debug_string = ""
130
131 loc_shell_rc = 0
132
Patrick Williams20f38712022-12-08 06:18:26 -0600133 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 Walshfa74bbb2018-10-30 13:21:03 -0500147 if quiet:
Michael Walshffee58a2016-11-22 11:28:33 -0600148 cmd_buf = sub_cmd_buf + " > " + temp_file_path + " 2>&1"
149 else:
Patrick Williams20f38712022-12-08 06:18:26 -0600150 cmd_buf = (
151 "set -o pipefail ; "
152 + sub_cmd_buf
153 + " 2>&1 | tee "
154 + temp_file_path
155 )
Michael Walshfa74bbb2018-10-30 13:21:03 -0500156 if debug:
157 gp.print_issuing(cmd_buf)
Michael Walsh09305182017-02-20 16:10:03 -0600158 else:
Patrick Williams20f38712022-12-08 06:18:26 -0600159 gp.print_timen(
160 "Processing " + call_point + " call point programs."
161 )
Michael Walshffee58a2016-11-22 11:28:33 -0600162
Patrick Williams20f38712022-12-08 06:18:26 -0600163 sub_proc = subprocess.Popen(cmd_buf, shell=True, executable="/bin/bash")
Michael Walsh35c4c622019-12-05 16:57:12 -0600164 sub_proc.communicate()
165 proc_plug_pkg_rc = sub_proc.returncode
Michael Walshffee58a2016-11-22 11:28:33 -0600166
Michael Walshfa74bbb2018-10-30 13:21:03 -0500167 if return_history:
168 # Get the "Running" statements from the output.
169 regex = " Running [^/]+/cp_"
170 cmd_buf = "egrep '" + regex + "' " + temp_file_path
Patrick Williams20f38712022-12-08 06:18:26 -0600171 _, 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 Walshfa74bbb2018-10-30 13:21:03 -0500178 history = [x + "\n" for x in filter(None, history.split("\n"))]
179 else:
180 history = []
181
Michael Walsh410b1782019-10-22 15:56:18 -0500182 # 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 Walshffee58a2016-11-22 11:28:33 -0600184 # failed_plug_in_name: <failed plug-in value, if any>
Michael Walsh410b1782019-10-22 15:56:18 -0500185 # shell_rc: <shell return code value of last call point program>
Michael Walshffee58a2016-11-22 11:28:33 -0600186
Michael Walsh410b1782019-10-22 15:56:18 -0500187 # 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 Walshfa74bbb2018-10-30 13:21:03 -0500189 # A valid bash variable against the left margin followed by...
190 # - A colon followed by...
Michael Walshffee58a2016-11-22 11:28:33 -0600191 # - Zero or more spaces
Michael Walsh957a2b22017-05-30 17:56:13 -0500192 bash_var_regex = "[_[:alpha:]][_[:alnum:]]*"
193 regex = "^" + bash_var_regex + ":[ ]*"
Patrick Williams20f38712022-12-08 06:18:26 -0600194 cmd_buf = (
195 "egrep '"
196 + regex
197 + "' "
198 + temp_file_path
199 + " > "
200 + temp_properties_file_path
201 )
Michael Walshfa74bbb2018-10-30 13:21:03 -0500202 gp.dprint_issuing(cmd_buf)
Michael Walsh957a2b22017-05-30 17:56:13 -0500203 grep_rc = os.system(cmd_buf)
Michael Walshffee58a2016-11-22 11:28:33 -0600204
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 Williams20f38712022-12-08 06:18:26 -0600209 shell_rc = int(properties.get("shell_rc", "0x0000000000000000"), 16)
210 failed_plug_in_name = properties.get("failed_plug_in_name", "")
Michael Walshffee58a2016-11-22 11:28:33 -0600211
Michael Walsh957a2b22017-05-30 17:56:13 -0500212 if proc_plug_pkg_rc != 0:
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000213 if quiet:
214 os.system("cat " + temp_file_path + " >&2")
Michael Walshfa74bbb2018-10-30 13:21:03 -0500215 if grep_rc != 0:
Michael Walsh0d5f96a2019-05-20 10:09:57 -0500216 gp.print_var(grep_rc, gp.hexa())
217 gp.print_var(proc_plug_pkg_rc, gp.hexa())
Michael Walshfa74bbb2018-10-30 13:21:03 -0500218 gp.print_timen("Re-cap of plug-in failures:")
Patrick Williams20f38712022-12-08 06:18:26 -0600219 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 Walsh40822372017-01-10 11:33:08 -0600226 rc = 1
Michael Walshffee58a2016-11-22 11:28:33 -0600227
Michael Walshfa74bbb2018-10-30 13:21:03 -0500228 if return_history:
229 return rc, shell_rc, failed_plug_in_name, history
230 else:
231 return rc, shell_rc, failed_plug_in_name