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