blob: 5b4b01ccefdcc6c34fd486ee1b7b68474178cf83 [file] [log] [blame]
Michael Walsh3ba8ecd2018-04-24 11:33:25 -05001#!/usr/bin/env python
2
3r"""
4This module provides functions which are useful to plug-ins call-point
5programs that wish to make external robot program calls.
6"""
7
8import sys
9import os
10import subprocess
11import re
12import time
13import imp
14
15import gen_print as gp
16import gen_valid as gv
17import gen_misc as gm
18import gen_cmd as gc
19
20auto_base_path = "/afs/rchland.ibm.com/projects/esw/dvt/autoipl/"
21
22base_path = \
23 os.path.dirname(os.path.dirname(imp.find_module("gen_robot_print")[1])) +\
24 os.sep
25
26
27def init_robot_out_parms(extra_prefix=""):
28
29 r"""
30 Initialize robot output parms such as outputdir, output, etc.
31
32 This function will set global values for the following robot output parms.
33
34 outputdir, output, log, report, loglevel
35
36 This function would typically be called prior to calling
37 create_robot_cmd_string.
38 """
39
40 AUTOBOOT_OPENBMC_NICKNAME = gm.get_mod_global("AUTOBOOT_OPENBMC_NICKNAME")
41
42 FFDC_DIR_PATH_STYLE = os.environ.get('FFDC_DIR_PATH_STYLE', '0')
43 if FFDC_DIR_PATH_STYLE == '1':
44 default_ffdc_dir_path = "/tmp/"
45 else:
46 default_ffdc_dir_path = base_path
47 # Set values for call to create_robot_cmd_string.
48 outputdir = gm.add_trailing_slash(os.environ.get("FFDC_DIR_PATH",
49 default_ffdc_dir_path))
50 seconds = time.time()
51 loc_time = time.localtime(seconds)
52 time_string = time.strftime("%y%m%d.%H%M%S", loc_time)
53 file_prefix = AUTOBOOT_OPENBMC_NICKNAME + "." + extra_prefix +\
54 time_string + "."
55 output = file_prefix + "output.xml"
56 log = file_prefix + "log.html"
57 report = file_prefix + "report.html"
58 loglevel = "TRACE"
59
60 # Make create_robot_cmd_string values global.
61 gm.set_mod_global(outputdir)
62 gm.set_mod_global(output)
63 gm.set_mod_global(log)
64 gm.set_mod_global(report)
65 gm.set_mod_global(loglevel)
66
67
68def init_robot_test_base_dir_path():
69
70 r"""
71 Initialize and validate the environment variable, ROBOT_TEST_BASE_DIR_PATH
72 and set corresponding global variable ROBOT_TEST_RUNNING_FROM_SB.
73
74 If ROBOT_TEST_BASE_DIR_PATH is already set, this function will merely
75 validate it. This function will also set environment variable
76 ROBOT_TEST_RUNNING_FROM_SB when ROBOT_TEST_BASE_DIR_PATH is not pre-set.
77 """
78
79 # ROBOT_TEST_BASE_DIR_PATH will be set as follows:
80 # This function will determine whether we are running in a user sandbox
81 # or from a standard apolloxxx environment.
82 # - User sandbox:
83 # If there is a <developer's home dir>/git/openbmc-test-automation/,
84 # ROBOT_TEST_BASE_DIR_PATH will be set to that path. Otherwise, we set it
85 # to <program dir path>/git/openbmc-test-automation/
86 # - Not in user sandbox:
87 # ROBOT_TEST_BASE_DIR_PATH will be set to <program dir
88 # path>/git/openbmc-test-automation/
89
90 ROBOT_TEST_BASE_DIR_PATH = os.environ.get('ROBOT_TEST_BASE_DIR_PATH', "")
91
92 ROBOT_TEST_RUNNING_FROM_SB = \
93 int(os.environ.get('ROBOT_TEST_RUNNING_FROM_SB', "0"))
94 if ROBOT_TEST_BASE_DIR_PATH == "":
95 # ROBOT_TEST_BASE_DIR_PATH was not set by user/caller.
96
97 AUTOIPL_VERSION = os.environ.get('AUTOIPL_VERSION', '')
98
99 if AUTOIPL_VERSION == "":
100 ROBOT_TEST_BASE_DIR_PATH = base_path
101 else:
102 suffix = "git/openbmc-test-automation/"
103
104 # Determine whether we're running out of a developer sandbox or
105 # simply out of an apolloxxx/bin path.
106 cmd_buf = 'dirname $(which gen_print.py)'
107 gp.dpissuing(cmd_buf)
108 sub_proc = \
109 subprocess.Popen(cmd_buf, shell=True, stdout=subprocess.PIPE,
110 stderr=subprocess.STDOUT)
111 out_buf, err_buf = sub_proc.communicate()
112 shell_rc = sub_proc.returncode
113 executable_base_dir_path = out_buf.rstrip() + "/"
114
115 # Strip the "land.ibm.com" for truer comparison with
116 # apollo_dir_path.
117 executable_base_dir_path = \
118 executable_base_dir_path.replace('land.ibm.com', '')
119
120 apollo_dir_path = re.sub('land\.ibm\.com', '', auto_base_path) +\
121 AUTOIPL_VERSION + "/bin/"
122
123 developer_home_dir_path = re.sub('/sandbox.*', '',
124 executable_base_dir_path)
125 developer_home_dir_path = \
126 gm.add_trailing_slash(developer_home_dir_path)
127 gp.dprint_vars(executable_base_dir_path, developer_home_dir_path,
128 apollo_dir_path)
129
130 ROBOT_TEST_RUNNING_FROM_SB = 0
131 if executable_base_dir_path != apollo_dir_path:
132 ROBOT_TEST_RUNNING_FROM_SB = 1
133 gp.dprint_vars(ROBOT_TEST_RUNNING_FROM_SB)
134 ROBOT_TEST_BASE_DIR_PATH = developer_home_dir_path + suffix
135 if not os.path.isdir(ROBOT_TEST_BASE_DIR_PATH):
136 gp.dprint_timen("NOTE: Sandbox directory" +
137 " ${ROBOT_TEST_BASE_DIR_PATH} does not" +
138 " exist.")
139 # Fall back to the apollo dir path.
140 ROBOT_TEST_BASE_DIR_PATH = apollo_dir_path + suffix
141 else:
142 # Use to the apollo dir path.
143 ROBOT_TEST_BASE_DIR_PATH = apollo_dir_path + suffix
144
145 if not gv.valid_value(ROBOT_TEST_BASE_DIR_PATH):
146 return False
147 gp.dprint_vars(ROBOT_TEST_RUNNING_FROM_SB, ROBOT_TEST_BASE_DIR_PATH)
148 if not gv.valid_dir_path(ROBOT_TEST_BASE_DIR_PATH):
149 return False
150
151 ROBOT_TEST_BASE_DIR_PATH = gm.add_trailing_slash(ROBOT_TEST_BASE_DIR_PATH)
152 gm.set_mod_global(ROBOT_TEST_BASE_DIR_PATH)
153 os.environ['ROBOT_TEST_BASE_DIR_PATH'] = ROBOT_TEST_BASE_DIR_PATH
154
155 gm.set_mod_global(ROBOT_TEST_RUNNING_FROM_SB)
156 os.environ['ROBOT_TEST_RUNNING_FROM_SB'] = str(ROBOT_TEST_RUNNING_FROM_SB)
157
158
159raw_robot_file_search_path = "${ROBOT_TEST_BASE_DIR_PATH}:" +\
160 "${ROBOT_TEST_BASE_DIR_PATH}tests:${ROBOT_TEST_BASE_DIR_PATH}extended:" +\
161 "${ROBOT_TEST_BASE_DIR_PATH}scratch:${PATH}"
162
163
164def init_robot_file_path(robot_file_path):
165
166 r"""
167 Determine full path name for the file path passed in robot_file_path and
168 return it.
169
170 If robot_file_path contains a fully qualified path name, this function
171 will verify that the file exists. If robot_file_path contains a relative
172 path, this function will search for the file and set robot_file_path so
173 that it contains the absolute path to the robot file. This function will
174 search for the robot file using the raw_robot_file_search_path (defined
175 above). Note that if ROBOT_TEST_BASE_DIR_PATH is not set, this function
176 will call init_robot_test_base_dir_path to set it.
177
178 Description of arguments:
179 robot_file_path The absolute or relative path to a robot
180 file.
181 """
182
183 if not gv.valid_value(robot_file_path):
184 raise ValueError('Programmer error.')
185
186 try:
187 if ROBOT_TEST_BASE_DIR_PATH is NONE:
188 init_robot_test_base_dir_path()
189 except NameError:
190 init_robot_test_base_dir_path()
191
192 if not re.match(r".*\.(robot|py)$", robot_file_path):
193 # No suffix so we'll assign one of "\.robot".
194 robot_file_path = robot_file_path + ".robot"
195
196 abs_path = 0
197 if robot_file_path[0:1] == "/":
198 abs_path = 1
199
200 gp.dprint_vars(abs_path, robot_file_path)
201
202 if not abs_path:
203 cmd_buf = "echo -n \"" + raw_robot_file_search_path + "\""
204 gp.dpissuing(cmd_buf)
205 sub_proc = subprocess.Popen(cmd_buf, shell=True,
206 stdout=subprocess.PIPE,
207 stderr=subprocess.STDOUT)
208 out_buf, err_buf = sub_proc.communicate()
209 shell_rc = sub_proc.returncode
210 robot_file_search_paths = out_buf
211 gp.dpvar(robot_file_search_paths)
212
213 robot_file_search_paths_list = robot_file_search_paths.split(':')
214 for search_path in robot_file_search_paths_list:
215 search_path = gm.add_trailing_slash(search_path)
216 candidate_file_path = search_path + robot_file_path
217 gp.dprint_var(candidate_file_path)
218 if os.path.isfile(candidate_file_path):
219 gp.dprint_timen("Found full path to " + robot_file_path + ".")
220 robot_file_path = candidate_file_path
221 break
222
223 gp.dprint_var(robot_file_path)
224 if not gv.valid_file_path(robot_file_path):
225 raise ValueError('Programmer error.')
226
227 return robot_file_path
228
229
230def get_robot_parm_names():
231
232 r"""
233 Return a list containing all of the long parm names (e.g. --outputdir)
234 supported by the robot program. Double dashes are not included in the
235 names returned.
236 """
237
238 cmd_buf = "robot -h | egrep " +\
239 "'^([ ]\-[a-zA-Z0-9])?[ ]+--[a-zA-Z0-9]+[ ]+' | sed -re" +\
240 " s'/.*\-\-//g' -e s'/ .*//g' | sort -u"
241 sub_proc = subprocess.Popen(cmd_buf, shell=True, stdout=subprocess.PIPE,
242 stderr=subprocess.STDOUT)
243 out_buf, err_buf = sub_proc.communicate()
244 shell_rc = sub_proc.returncode
245 if shell_rc != 0:
246 hex = 1
247 print_var(shell_rc, hex)
248 print(out_buf)
249
250 return out_buf.split("\n")
251
252
253def create_robot_cmd_string(robot_file_path, *parms):
254
255 r"""
256 Create a robot command string and return it. On failure, return an empty
257 string.
258
259 Description of arguments:
260 robot_file_path The path to the robot file to be run.
261 parms The list of parms to be included in the
262 command string. The name of each variable
263 in this list must be the same as the name
264 of the corresponding parm. This function
265 figures out that name. This function is
266 also able to distinguish robot parms (e.g.
267 --outputdir) from robot program parms (all
268 other parms which will be passed as "-v
269 PARM_NAME:parm_value")..
270
271 Example:
272
273 The following call to this function...
274 cmd_buf = create_robot_cmd_string("tools/start_sol_console.robot",
275 OPENBMC_HOST, quiet, test_mode, debug, outputdir, output, log, report)
276
277 Would return a string something like this.
278 robot -v OPENBMC_HOST:beye6 -v quiet:0 -v test_mode:1 -v debug:1
279 --outputdir=/gsa/ausgsa/projects/a/autoipl/status
280 --output=beye6.OS_Console.output.xml --log=beye6.OS_Console.log.html
281 --report=beye6.OS_Console.report.html tools/start_sol_console.robot
282 """
283
284 robot_file_path = init_robot_file_path(robot_file_path)
285
286 robot_parm_names = get_robot_parm_names()
287
288 robot_parm_list = []
289
290 stack_frame = 2
291 ix = 2
292 for arg in parms:
293 parm = arg
294 parm = gm.quote_bash_parm(gm.escape_bash_quotes(str(parm)))
295 var_name = gp.get_arg_name(None, ix, stack_frame)
296 if var_name in robot_parm_names:
297 p_string = "--" + var_name + "=" + str(parm)
298 robot_parm_list.append(p_string)
299 else:
300 p_string = "-v " + var_name + ":" + str(parm)
301 robot_parm_list.append(p_string)
302 ix += 1
303
304 robot_cmd_buf = "robot " + ' '.join(robot_parm_list) + " " +\
305 robot_file_path
306
307 return robot_cmd_buf
308
309
310def robot_cmd_fnc(robot_cmd_buf,
311 robot_jail=os.environ.get('ROBOT_JAIL', ''),
312 gzip=1):
313
314 r"""
315 Run the robot command string.
316
317 This function will set the various PATH variables correctly so that you
318 are running the proper version of all imported files, etc.
319
320 Description of argument(s):
321 robot_cmd_buf The complete robot command string.
322 robot_jail Indicates that this is to run in "robot
323 jail" meaning without visibility to any
324 apolloxxx import files, programs, etc.
325 gqip This indicates that the log, report and
326 output files produced by robot should be
327 gzipped to save space.
328 """
329
330 if not gv.valid_value(robot_cmd_buf):
331 return False
332
333 # Get globals set by init_robot_test_base_dir_path().
334 module = sys.modules["__main__"]
335 try:
336 ROBOT_TEST_BASE_DIR_PATH = getattr(module, "ROBOT_TEST_BASE_DIR_PATH")
337 except NameError:
338 init_robot_test_base_dir_path()
339 ROBOT_TEST_BASE_DIR_PATH = getattr(module, "ROBOT_TEST_BASE_DIR_PATH")
340
341 ROBOT_TEST_RUNNING_FROM_SB = \
342 gm.get_mod_global("ROBOT_TEST_RUNNING_FROM_SB")
343
344 if robot_jail == "":
345 if ROBOT_TEST_RUNNING_FROM_SB:
346 robot_jail = 0
347 else:
348 robot_jail = 1
349
350 robot_jail = int(robot_jail)
351 ROBOT_JAIL = os.environ.get('ROBOT_JAIL', '')
352 gp.dprint_vars(ROBOT_TEST_BASE_DIR_PATH, ROBOT_TEST_RUNNING_FROM_SB,
353 ROBOT_JAIL, robot_jail)
354
355 # Save PATH and PYTHONPATH to be restored later.
356 os.environ["SAVED_PYTHONPATH"] = os.environ.get("PYTHONPATH", "")
357 os.environ["SAVED_PATH"] = os.environ.get("PATH", "")
358
359 if robot_jail:
360 PYTHONPATH = ROBOT_TEST_BASE_DIR_PATH + "lib"
361 NEW_PATH_LIST = [ROBOT_TEST_BASE_DIR_PATH + "bin"]
362 # Coding special case to preserve python27_path.
363 python27_path = "/opt/rh/python27/root/usr/bin"
364 PATH_LIST = os.environ.get("PATH", "").split(":")
365 if python27_path in PATH_LIST:
366 NEW_PATH_LIST.append(python27_path)
367 NEW_PATH_LIST.extend(["/usr/local/sbin", "/usr/local/bin", "/usr/sbin",
368 "/usr/bin", "/sbin", "/bin"])
369 PATH = ":".join(NEW_PATH_LIST)
370 else:
371 PYTHONPATH = os.environ.get('PYTHONPATH', '') + ":" +\
372 ROBOT_TEST_BASE_DIR_PATH + "lib/"
373 PATH = os.environ.get('PATH', '') + ":" + ROBOT_TEST_BASE_DIR_PATH +\
374 "bin/"
375
376 os.environ['PYTHONPATH'] = PYTHONPATH
377 os.environ['PATH'] = PATH
378 gp.dprint_vars(PATH, PYTHONPATH)
379
380 os.environ['FFDC_DIR_PATH_STYLE'] = os.environ.get('FFDC_DIR_PATH_STYLE',
381 '1')
382
383 test_mode = getattr(module, "test_mode")
384
385 gp.qpissuing(robot_cmd_buf, test_mode)
386 if test_mode:
387 os.environ["PATH"] = os.environ.get("SAVED_PATH", "")
388 os.environ["PYTHONPATH"] = os.environ.get("SAVED_PYTHONPATH", "")
389 return True
390
391 if quiet:
392 DEVNULL = open(os.devnull, 'wb')
393 stdout = DEVNULL
394 else:
395 stdout = None
396 sub_proc = subprocess.Popen(robot_cmd_buf, stdout=stdout, shell=True)
397 sub_proc.communicate()
398 shell_rc = sub_proc.returncode
399 if shell_rc != 0:
400 hex = 1
401 gp.pvar(shell_rc, hex)
402 os.environ["PATH"] = os.environ.get("SAVED_PATH", "")
403 os.environ["PYTHONPATH"] = os.environ.get("SAVED_PYTHONPATH", "")
404 return False
405
406 os.environ["PATH"] = os.environ.get("SAVED_PATH", "")
407 os.environ["PYTHONPATH"] = os.environ.get("SAVED_PYTHONPATH", "")
408
409 if not gzip:
410 return True
411
412 # gzip the output files.
413 # Retrieve the parms from the robot command buffer.
414 robot_cmd_buf_dict = gc.parse_command_string(robot_cmd_buf)
415 # Get prefix from the log parm.
416 prefix = re.sub('log\.html$', '', robot_cmd_buf_dict['log'])
417 gp.qprintn()
418 rc, outbuf = gc.cmd_fnc("cd " + robot_cmd_buf_dict['outputdir'] +
419 " ; gzip " + robot_cmd_buf_dict['output'] +
420 " " + robot_cmd_buf_dict['log'] +
421 " " + robot_cmd_buf_dict['report'])
422
423 outputdir = gm.add_trailing_slash(robot_cmd_buf_dict['outputdir'])
424 Output = outputdir + robot_cmd_buf_dict['output'] + ".gz"
425 Log = outputdir + robot_cmd_buf_dict['log'] + ".gz"
426 Report = outputdir + robot_cmd_buf_dict['report'] + ".gz"
427 gp.qprintn("\ngzipped output:")
428 gp.qpvars(0, 9, Output, Log, Report)
429
430 return True