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 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 431