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