blob: 0f6deda72750056acf6ddcabe2ba5e4fad332c67 [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
Patrick Williams57318182022-12-08 06:18:26 -06007import sys
George Keishinge635ddc2022-12-08 07:38:02 -06008import subprocess
9from robot.libraries.BuiltIn import BuiltIn
10import os
Michael Walshffee58a2016-11-22 11:28:33 -060011import tempfile
12
Patrick Williams57318182022-12-08 06:18:26 -060013import gen_print as gp
George Keishinge635ddc2022-12-08 07:38:02 -060014import gen_misc as gm
15import gen_cmd as gc
Michael Walshffee58a2016-11-22 11:28:33 -060016
17
George Keishinge635ddc2022-12-08 07:38:02 -060018def rvalidate_plug_ins(plug_in_dir_paths,
19 quiet=1):
Michael Walshffee58a2016-11-22 11:28:33 -060020 r"""
Michael Walsh410b1782019-10-22 15:56:18 -050021 Call the external validate_plug_ins.py program which validates the plug-in dir paths given to it. Return
22 a list containing a normalized path for each plug-in selected.
Michael Walshffee58a2016-11-22 11:28:33 -060023
24 Description of arguments:
Michael Walsh410b1782019-10-22 15:56:18 -050025 plug_in_dir_paths A colon-separated list of plug-in directory paths.
26 quiet If quiet is set to 1, this function will NOT write status messages to
27 stdout.
Michael Walshffee58a2016-11-22 11:28:33 -060028 """
29
George Keishinge635ddc2022-12-08 07:38:02 -060030 cmd_buf = "validate_plug_ins.py \"" + plug_in_dir_paths + "\""
George Keishing36efbc02018-12-12 10:18:23 -060031 rc, out_buf = gc.shell_cmd(cmd_buf, print_output=0)
Michael Walshffee58a2016-11-22 11:28:33 -060032 if rc != 0:
George Keishinge635ddc2022-12-08 07:38:02 -060033 BuiltIn().fail(gp.sprint_error("Validate plug ins call failed. See"
34 + " stderr text for details.\n"))
Michael Walshffee58a2016-11-22 11:28:33 -060035
George Keishing36efbc02018-12-12 10:18:23 -060036 # plug_in_packages_list = out_buf.split("\n")
37 plug_in_packages_list = list(filter(None, out_buf.split("\n")))
Michael Walshffee58a2016-11-22 11:28:33 -060038 if len(plug_in_packages_list) == 1 and plug_in_packages_list[0] == "":
39 return []
40
41 return plug_in_packages_list
42
Michael Walshffee58a2016-11-22 11:28:33 -060043
George Keishinge635ddc2022-12-08 07:38:02 -060044def rprocess_plug_in_packages(plug_in_packages_list=None,
45 call_point="setup",
46 shell_rc="0x00000000",
47 stop_on_plug_in_failure=1,
48 stop_on_non_zero_rc=0,
49 release_type="obmc",
50 quiet=None,
51 debug=None,
52 return_history=False):
Michael Walshffee58a2016-11-22 11:28:33 -060053 r"""
Michael Walsh410b1782019-10-22 15:56:18 -050054 Call the external process_plug_in_packages.py to process the plug-in packages. Return the following:
Michael Walshffee58a2016-11-22 11:28:33 -060055 rc The return code - 0 = PASS, 1 = FAIL.
Michael Walsh410b1782019-10-22 15:56:18 -050056 shell_rc The shell return code returned by process_plug_in_packages.py.
Michael Walshffee58a2016-11-22 11:28:33 -060057 failed_plug_in_name The failed plug in name (if any).
58
59 Description of arguments:
60 plug_in_packages_list A python list of plug-in directory paths.
Michael Walsh410b1782019-10-22 15:56:18 -050061 call_point The call point program to be called for each plug-in package (e.g.
62 post_boot). This name should not include the "cp_" prefix.
63 shell_rc The user may supply a value other than zero to indicate an acceptable
64 non-zero return code. For example, if this value equals 0x00000200, it
65 means that for each plug-in call point that runs, a 0x00000200 will not
66 be counted as a failure.
67 stop_on_plug_in_failure If this parameter is set to 1, this program will stop and return non-zero
68 if the call point program from any plug-in directory fails. Conversely,
69 if it is set to false, this program will run the call point program from
70 each and every plug-in directory regardless of their return values.
71 Typical example cases where you'd want to run all plug-in call points
72 regardless of success or failure would be "cleanup" or "ffdc" call points.
73 stop_on_non_zero_rc If this parm is set to 1 and a plug-in call point program returns a valid
74 non-zero return code (see "shell_rc" parm above), this program will stop
75 processing and return 0 (success). Since this constitutes a successful
76 exit, this would normally be used where the caller wishes to stop
77 processing if one of the plug-in directory call point programs returns a
78 special value indicating that some special case has been found. An
79 example might be in calling some kind of "check_errl" call point program.
80 Such a call point program might return a 2 (i.e. 0x00000200) to indicate
81 that a given error log entry was found in an "ignore" list and is
82 therefore to be ignored. That being the case, no other "check_errl" call
83 point program would need to be called.
84 release_type The type of release being tested (e.g. "obmc", "op", "fips"). This
85 influences which integrated plug-ins are selected.
86 quiet If quiet is set to 1, this function will NOT write status messages to
87 stdout. This will default to the global quiet program parm or to 0.
88 debug If this parameter is set to 1, this function will print additional debug
89 information. This is mainly to be used by the developer of this
90 function. This will default to the global quiet program parm or to 0.
91 return_history In addition to rc, shell_rc and failed_plug_in_name, return a list
92 containing historical output that looks like the following:
Michael Walshfa74bbb2018-10-30 13:21:03 -050093
94 history:
Michael Walsh410b1782019-10-22 15:56:18 -050095 history[0]: #(CDT) 2018/10/30 12:25:49 - Running OBMC_Sample/cp_post_stack
Michael Walshffee58a2016-11-22 11:28:33 -060096 """
97
98 rc = 0
99
Michael Walshfa74bbb2018-10-30 13:21:03 -0500100 plug_in_packages_list = gp.get_var_value(plug_in_packages_list, [])
Michael Walshffee58a2016-11-22 11:28:33 -0600101
102 # If there are no plug-in packages to process, return successfully.
103 if len(plug_in_packages_list) == 0:
Michael Walshfa74bbb2018-10-30 13:21:03 -0500104 if return_history:
105 return 0, 0, "", []
106 else:
107 return 0, 0, ""
Michael Walshffee58a2016-11-22 11:28:33 -0600108
Michael Walshfa74bbb2018-10-30 13:21:03 -0500109 quiet = int(gp.get_var_value(quiet, 0))
110 debug = int(gp.get_var_value(debug, 0))
Michael Walshffee58a2016-11-22 11:28:33 -0600111
112 # Create string from list.
George Keishinge635ddc2022-12-08 07:38:02 -0600113 plug_in_dir_paths = ':'.join(plug_in_packages_list)
Michael Walshffee58a2016-11-22 11:28:33 -0600114
115 temp = tempfile.NamedTemporaryFile()
116 temp_file_path = temp.name
117 temp2 = tempfile.NamedTemporaryFile()
118 temp_properties_file_path = temp2.name
119
Michael Walshfa74bbb2018-10-30 13:21:03 -0500120 if debug:
Michael Walshffee58a2016-11-22 11:28:33 -0600121 os.environ["PERF_TRACE"] = "1"
122 debug_string = " --quiet=0"
123 else:
124 debug_string = ""
125
126 loc_shell_rc = 0
127
George Keishinge635ddc2022-12-08 07:38:02 -0600128 sub_cmd_buf = "process_plug_in_packages.py" + debug_string +\
129 " --call_point=" + call_point + " --allow_shell_rc=" +\
130 str(shell_rc) + " --stop_on_plug_in_failure=" +\
131 str(stop_on_plug_in_failure) + " --stop_on_non_zero_rc=" +\
132 str(stop_on_non_zero_rc) + " " + plug_in_dir_paths
Michael Walshfa74bbb2018-10-30 13:21:03 -0500133 if quiet:
Michael Walshffee58a2016-11-22 11:28:33 -0600134 cmd_buf = sub_cmd_buf + " > " + temp_file_path + " 2>&1"
135 else:
George Keishinge635ddc2022-12-08 07:38:02 -0600136 cmd_buf = "set -o pipefail ; " + sub_cmd_buf + " 2>&1 | tee " +\
137 temp_file_path
Michael Walshfa74bbb2018-10-30 13:21:03 -0500138 if debug:
139 gp.print_issuing(cmd_buf)
Michael Walsh09305182017-02-20 16:10:03 -0600140 else:
George Keishinge635ddc2022-12-08 07:38:02 -0600141 gp.print_timen("Processing " + call_point
142 + " call point programs.")
Michael Walshffee58a2016-11-22 11:28:33 -0600143
George Keishinge635ddc2022-12-08 07:38:02 -0600144 sub_proc = subprocess.Popen(cmd_buf, shell=True, executable='/bin/bash')
Michael Walsh35c4c622019-12-05 16:57:12 -0600145 sub_proc.communicate()
146 proc_plug_pkg_rc = sub_proc.returncode
Michael Walshffee58a2016-11-22 11:28:33 -0600147
Michael Walshfa74bbb2018-10-30 13:21:03 -0500148 if return_history:
149 # Get the "Running" statements from the output.
150 regex = " Running [^/]+/cp_"
151 cmd_buf = "egrep '" + regex + "' " + temp_file_path
George Keishinge635ddc2022-12-08 07:38:02 -0600152 _, history = gc.shell_cmd(cmd_buf, quiet=(not debug), print_output=0,
153 show_err=0, ignore_err=1)
Michael Walshfa74bbb2018-10-30 13:21:03 -0500154 history = [x + "\n" for x in filter(None, history.split("\n"))]
155 else:
156 history = []
157
Michael Walsh410b1782019-10-22 15:56:18 -0500158 # As process_plug_in_packages.py help text states, it will print the values of failed_plug_in_name and
159 # shell_rc in the following format:
Michael Walshffee58a2016-11-22 11:28:33 -0600160 # failed_plug_in_name: <failed plug-in value, if any>
Michael Walsh410b1782019-10-22 15:56:18 -0500161 # shell_rc: <shell return code value of last call point program>
Michael Walshffee58a2016-11-22 11:28:33 -0600162
Michael Walsh410b1782019-10-22 15:56:18 -0500163 # We want to obtain those values from the output. To make the task simpler, we'll start by grepping the
164 # output for lines that might fit such a format:
Michael Walshfa74bbb2018-10-30 13:21:03 -0500165 # A valid bash variable against the left margin followed by...
166 # - A colon followed by...
Michael Walshffee58a2016-11-22 11:28:33 -0600167 # - Zero or more spaces
Michael Walsh957a2b22017-05-30 17:56:13 -0500168 bash_var_regex = "[_[:alpha:]][_[:alnum:]]*"
169 regex = "^" + bash_var_regex + ":[ ]*"
George Keishinge635ddc2022-12-08 07:38:02 -0600170 cmd_buf = "egrep '" + regex + "' " + temp_file_path + " > " +\
171 temp_properties_file_path
Michael Walshfa74bbb2018-10-30 13:21:03 -0500172 gp.dprint_issuing(cmd_buf)
Michael Walsh957a2b22017-05-30 17:56:13 -0500173 grep_rc = os.system(cmd_buf)
Michael Walshffee58a2016-11-22 11:28:33 -0600174
175 # Next we call my_parm_file to create a properties dictionary.
176 properties = gm.my_parm_file(temp_properties_file_path)
177
178 # Finally, we access the 2 values that we need.
George Keishinge635ddc2022-12-08 07:38:02 -0600179 shell_rc = int(properties.get('shell_rc', '0x0000000000000000'), 16)
180 failed_plug_in_name = properties.get('failed_plug_in_name', '')
Michael Walshffee58a2016-11-22 11:28:33 -0600181
Michael Walsh957a2b22017-05-30 17:56:13 -0500182 if proc_plug_pkg_rc != 0:
Michael Walsh0a3bdb42019-01-31 16:21:44 +0000183 if quiet:
184 os.system("cat " + temp_file_path + " >&2")
Michael Walshfa74bbb2018-10-30 13:21:03 -0500185 if grep_rc != 0:
Michael Walsh0d5f96a2019-05-20 10:09:57 -0500186 gp.print_var(grep_rc, gp.hexa())
187 gp.print_var(proc_plug_pkg_rc, gp.hexa())
Michael Walshfa74bbb2018-10-30 13:21:03 -0500188 gp.print_timen("Re-cap of plug-in failures:")
George Keishinge635ddc2022-12-08 07:38:02 -0600189 gc.cmd_fnc_u("egrep -A 1 '^failed_plug_in_name:[ ]+' "
190 + temp_properties_file_path + " | egrep -v '^\\--'",
191 quiet=1, show_err=0)
Michael Walsh40822372017-01-10 11:33:08 -0600192 rc = 1
Michael Walshffee58a2016-11-22 11:28:33 -0600193
Michael Walshfa74bbb2018-10-30 13:21:03 -0500194 if return_history:
195 return rc, shell_rc, failed_plug_in_name, history
196 else:
197 return rc, shell_rc, failed_plug_in_name