1#!/usr/bin/env python 2 3r""" 4This module is the python counterpart to obmc_boot_test. 5""" 6 7import os 8import imp 9import time 10import glob 11import random 12import re 13import cPickle as pickle 14import socket 15 16from robot.utils import DotDict 17from robot.libraries.BuiltIn import BuiltIn 18 19from boot_data import * 20import gen_print as gp 21import gen_robot_print as grp 22import gen_robot_plug_in as grpi 23import gen_robot_valid as grv 24import gen_misc as gm 25import gen_cmd as gc 26import gen_robot_keyword as grk 27import state as st 28import var_stack as vs 29 30base_path = os.path.dirname(os.path.dirname( 31 imp.find_module("gen_robot_print")[1])) +\ 32 os.sep 33sys.path.append(base_path + "extended/") 34import run_keyword as rk 35 36# Setting master_pid correctly influences the behavior of plug-ins like 37# DB_Logging 38program_pid = os.getpid() 39master_pid = os.environ.get('AUTOBOOT_MASTER_PID', program_pid) 40 41# Set up boot data structures. 42boot_table = create_boot_table() 43valid_boot_types = create_valid_boot_list(boot_table) 44 45boot_lists = read_boot_lists() 46last_ten = [] 47 48state = st.return_default_state() 49cp_setup_called = 0 50next_boot = "" 51base_tool_dir_path = os.path.normpath(os.environ.get( 52 'AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")) + os.sep 53 54ffdc_dir_path = os.path.normpath(os.environ.get('FFDC_DIR_PATH', '')) + os.sep 55boot_success = 0 56status_dir_path = os.environ.get('STATUS_DIR_PATH', "") 57if status_dir_path != "": 58 status_dir_path = os.path.normpath(status_dir_path) + os.sep 59default_power_on = "REST Power On" 60default_power_off = "REST Power Off" 61boot_count = 0 62 63LOG_LEVEL = BuiltIn().get_variable_value("${LOG_LEVEL}") 64ffdc_prefix = "" 65boot_start_time = "" 66boot_end_time = "" 67save_stack = vs.var_stack('save_stack') 68main_func_parm_list = ['boot_stack', 'stack_mode', 'quiet'] 69 70 71############################################################################### 72def process_host(host, 73 host_var_name=""): 74 75 r""" 76 Process a host by getting the associated host name and IP address and 77 setting them in global variables. 78 79 If the caller does not pass the host_var_name, this function will try to 80 figure out the name of the variable used by the caller for the host parm. 81 Callers are advised to explicitly specify the host_var_name when calling 82 with an exec command. In such cases, the get_arg_name cannot figure out 83 the host variable name. 84 85 This function will then create similar global variable names by 86 removing "_host" and appending "_host_name" or "_ip" to the host variable 87 name. 88 89 Example: 90 91 If a call is made like this: 92 process_host(openbmc_host) 93 94 Global variables openbmc_host_name and openbmc_ip will be set. 95 96 Description of argument(s): 97 host A host name or IP. The name of the variable used should 98 have a suffix of "_host". 99 host_var_name The name of the variable being used as the host parm. 100 """ 101 102 if host_var_name == "": 103 host_var_name = gp.get_arg_name(0, 1, stack_frame_ix=2) 104 105 host_name_var_name = re.sub("host", "host_name", host_var_name) 106 ip_var_name = re.sub("host", "ip", host_var_name) 107 cmd_buf = "global " + host_name_var_name + ", " + ip_var_name + " ; " +\ 108 host_name_var_name + ", " + ip_var_name + " = gm.get_host_name_ip('" +\ 109 host + "')" 110 exec(cmd_buf) 111 112############################################################################### 113 114 115############################################################################### 116def process_pgm_parms(): 117 118 r""" 119 Process the program parameters by assigning them all to corresponding 120 globals. Also, set some global values that depend on program parameters. 121 """ 122 123 # Program parameter processing. 124 # Assign all program parms to python variables which are global to this 125 # module. 126 127 global parm_list 128 parm_list = BuiltIn().get_variable_value("${parm_list}") 129 # The following subset of parms should be processed as integers. 130 int_list = ['max_num_tests', 'boot_pass', 'boot_fail', 'ffdc_only', 131 'boot_fail_threshold', 'quiet', 'test_mode', 'debug'] 132 for parm in parm_list: 133 if parm in int_list: 134 sub_cmd = "int(BuiltIn().get_variable_value(\"${" + parm +\ 135 "}\", \"0\"))" 136 else: 137 sub_cmd = "BuiltIn().get_variable_value(\"${" + parm + "}\")" 138 cmd_buf = "global " + parm + " ; " + parm + " = " + sub_cmd 139 gp.dpissuing(cmd_buf) 140 exec(cmd_buf) 141 if re.match(r".*_host$", parm): 142 cmd_buf = "process_host(" + parm + ", '" + parm + "')" 143 exec(cmd_buf) 144 if re.match(r".*_password$", parm): 145 # Register the value of any parm whose name ends in _password. 146 # This will cause the print functions to replace passwords with 147 # asterisks in the output. 148 cmd_buf = "gp.register_passwords(" + parm + ")" 149 exec(cmd_buf) 150 151 global ffdc_dir_path_style 152 global boot_list 153 global boot_stack 154 global boot_results_file_path 155 global boot_results 156 global ffdc_list_file_path 157 global ffdc_report_list_path 158 global ffdc_summary_list_path 159 160 if ffdc_dir_path_style == "": 161 ffdc_dir_path_style = int(os.environ.get('FFDC_DIR_PATH_STYLE', '0')) 162 163 # Convert these program parms to lists for easier processing.. 164 boot_list = filter(None, boot_list.split(":")) 165 boot_stack = filter(None, boot_stack.split(":")) 166 167 boot_results_file_path = "/tmp/" + openbmc_nickname + ":pid_" +\ 168 str(master_pid) + ":boot_results" 169 170 if os.path.isfile(boot_results_file_path): 171 # We've been called before in this run so we'll load the saved 172 # boot_results object. 173 boot_results = pickle.load(open(boot_results_file_path, 'rb')) 174 else: 175 boot_results = boot_results(boot_table, boot_pass, boot_fail) 176 177 ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\ 178 "/FFDC_FILE_LIST" 179 ffdc_report_list_path = base_tool_dir_path + openbmc_nickname +\ 180 "/FFDC_REPORT_FILE_LIST" 181 182 ffdc_summary_list_path = base_tool_dir_path + openbmc_nickname +\ 183 "/FFDC_SUMMARY_FILE_LIST" 184 185############################################################################### 186 187 188############################################################################### 189def initial_plug_in_setup(): 190 191 r""" 192 Initialize all plug-in environment variables which do not change for the 193 duration of the program. 194 195 """ 196 197 global LOG_LEVEL 198 BuiltIn().set_log_level("NONE") 199 200 BuiltIn().set_global_variable("${master_pid}", master_pid) 201 BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path) 202 BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path) 203 BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path) 204 BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}", 205 ffdc_list_file_path) 206 BuiltIn().set_global_variable("${FFDC_REPORT_LIST_PATH}", 207 ffdc_report_list_path) 208 BuiltIn().set_global_variable("${FFDC_SUMMARY_LIST_PATH}", 209 ffdc_summary_list_path) 210 211 BuiltIn().set_global_variable("${FFDC_DIR_PATH_STYLE}", 212 ffdc_dir_path_style) 213 BuiltIn().set_global_variable("${FFDC_CHECK}", 214 ffdc_check) 215 216 # For each program parameter, set the corresponding AUTOBOOT_ environment 217 # variable value. Also, set an AUTOBOOT_ environment variable for every 218 # element in additional_values. 219 additional_values = ["program_pid", "master_pid", "ffdc_dir_path", 220 "status_dir_path", "base_tool_dir_path", 221 "ffdc_list_file_path", "ffdc_report_list_path", 222 "ffdc_summary_list_path"] 223 224 plug_in_vars = parm_list + additional_values 225 226 for var_name in plug_in_vars: 227 var_value = BuiltIn().get_variable_value("${" + var_name + "}") 228 var_name = var_name.upper() 229 if var_value is None: 230 var_value = "" 231 os.environ["AUTOBOOT_" + var_name] = str(var_value) 232 233 BuiltIn().set_log_level(LOG_LEVEL) 234 235 # Make sure the ffdc list directory exists. 236 ffdc_list_dir_path = os.path.dirname(ffdc_list_file_path) + os.sep 237 if not os.path.exists(ffdc_list_dir_path): 238 os.makedirs(ffdc_list_dir_path) 239 240############################################################################### 241 242 243############################################################################### 244def plug_in_setup(): 245 246 r""" 247 Initialize all changing plug-in environment variables for use by the 248 plug-in programs. 249 """ 250 251 global LOG_LEVEL 252 global test_really_running 253 254 BuiltIn().set_log_level("NONE") 255 256 boot_pass, boot_fail = boot_results.return_total_pass_fail() 257 if boot_pass > 1: 258 test_really_running = 1 259 else: 260 test_really_running = 0 261 262 BuiltIn().set_global_variable("${test_really_running}", 263 test_really_running) 264 BuiltIn().set_global_variable("${boot_type_desc}", next_boot) 265 BuiltIn().set_global_variable("${boot_pass}", boot_pass) 266 BuiltIn().set_global_variable("${boot_fail}", boot_fail) 267 BuiltIn().set_global_variable("${boot_success}", boot_success) 268 BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix) 269 BuiltIn().set_global_variable("${boot_start_time}", boot_start_time) 270 BuiltIn().set_global_variable("${boot_end_time}", boot_end_time) 271 272 # For each program parameter, set the corresponding AUTOBOOT_ environment 273 # variable value. Also, set an AUTOBOOT_ environment variable for every 274 # element in additional_values. 275 additional_values = ["boot_type_desc", "boot_success", "boot_pass", 276 "boot_fail", "test_really_running", "ffdc_prefix", 277 "boot_start_time", "boot_end_time"] 278 279 plug_in_vars = additional_values 280 281 for var_name in plug_in_vars: 282 var_value = BuiltIn().get_variable_value("${" + var_name + "}") 283 var_name = var_name.upper() 284 if var_value is None: 285 var_value = "" 286 os.environ["AUTOBOOT_" + var_name] = str(var_value) 287 288 if debug: 289 shell_rc, out_buf = \ 290 gc.cmd_fnc_u("printenv | egrep AUTOBOOT_ | sort -u") 291 292 BuiltIn().set_log_level(LOG_LEVEL) 293 294############################################################################### 295 296 297############################################################################### 298def pre_boot_plug_in_setup(): 299 300 # Clear the ffdc_list_file_path file. Plug-ins may now write to it. 301 try: 302 os.remove(ffdc_list_file_path) 303 except OSError: 304 pass 305 306 # Clear the ffdc_report_list_path file. Plug-ins may now write to it. 307 try: 308 os.remove(ffdc_report_list_path) 309 except OSError: 310 pass 311 312 # Clear the ffdc_summary_list_path file. Plug-ins may now write to it. 313 try: 314 os.remove(ffdc_summary_list_path) 315 except OSError: 316 pass 317 318 global ffdc_prefix 319 320 seconds = time.time() 321 loc_time = time.localtime(seconds) 322 time_string = time.strftime("%y%m%d.%H%M%S.", loc_time) 323 324 ffdc_prefix = openbmc_nickname + "." + time_string 325 326############################################################################### 327 328 329############################################################################### 330def setup(): 331 332 r""" 333 Do general program setup tasks. 334 """ 335 336 global cp_setup_called 337 338 gp.qprintn() 339 340 robot_pgm_dir_path = os.path.dirname(__file__) + os.sep 341 repo_bin_path = robot_pgm_dir_path.replace("/lib/", "/bin/") 342 # If we can't find process_plug_in_packages.py, ssh_pw or 343 # validate_plug_ins.py, then we don't have our repo bin in PATH. 344 shell_rc, out_buf = gc.cmd_fnc_u("which process_plug_in_packages.py" + 345 " ssh_pw validate_plug_ins.py", quiet=1, 346 print_output=0, show_err=0) 347 if shell_rc != 0: 348 os.environ['PATH'] = repo_bin_path + ":" + os.environ.get('PATH', "") 349 # Likewise, our repo lib subdir needs to be in sys.path and PYTHONPATH. 350 if robot_pgm_dir_path not in sys.path: 351 sys.path.append(robot_pgm_dir_path) 352 PYTHONPATH = os.environ.get("PYTHONPATH", "") 353 if PYTHONPATH == "": 354 os.environ['PYTHONPATH'] = robot_pgm_dir_path 355 else: 356 os.environ['PYTHONPATH'] = robot_pgm_dir_path + ":" + PYTHONPATH 357 358 validate_parms() 359 360 grp.rqprint_pgm_header() 361 362 grk.run_key("Set BMC Power Policy RESTORE_LAST_STATE") 363 364 initial_plug_in_setup() 365 366 plug_in_setup() 367 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages( 368 call_point='setup') 369 if rc != 0: 370 error_message = "Plug-in setup failed.\n" 371 grp.rprint_error_report(error_message) 372 BuiltIn().fail(error_message) 373 # Setting cp_setup_called lets our Teardown know that it needs to call 374 # the cleanup plug-in call point. 375 cp_setup_called = 1 376 377 # Keyword "FFDC" will fail if TEST_MESSAGE is not set. 378 BuiltIn().set_global_variable("${TEST_MESSAGE}", "${EMPTY}") 379 # FFDC_LOG_PATH is used by "FFDC" keyword. 380 BuiltIn().set_global_variable("${FFDC_LOG_PATH}", ffdc_dir_path) 381 382 # Also printed by FFDC. 383 global host_name 384 global host_ip 385 host = socket.gethostname() 386 host_name, host_ip = gm.get_host_name_ip(host) 387 388 gp.dprint_var(boot_table, 1) 389 gp.dprint_var(boot_lists) 390 391############################################################################### 392 393 394############################################################################### 395def validate_parms(): 396 397 r""" 398 Validate all program parameters. 399 """ 400 401 process_pgm_parms() 402 403 gp.qprintn() 404 405 global openbmc_model 406 grv.rvalid_value("openbmc_host") 407 grv.rvalid_value("openbmc_username") 408 grv.rvalid_value("openbmc_password") 409 if os_host != "": 410 grv.rvalid_value("os_username") 411 grv.rvalid_value("os_password") 412 413 if pdu_host != "": 414 grv.rvalid_value("pdu_username") 415 grv.rvalid_value("pdu_password") 416 grv.rvalid_integer("pdu_slot_no") 417 if openbmc_serial_host != "": 418 grv.rvalid_integer("openbmc_serial_port") 419 if openbmc_model == "": 420 status, ret_values =\ 421 grk.run_key_u("Get BMC System Model") 422 openbmc_model = ret_values 423 BuiltIn().set_global_variable("${openbmc_model}", openbmc_model) 424 grv.rvalid_value("openbmc_model") 425 grv.rvalid_integer("max_num_tests") 426 grv.rvalid_integer("boot_pass") 427 grv.rvalid_integer("boot_fail") 428 429 plug_in_packages_list = grpi.rvalidate_plug_ins(plug_in_dir_paths) 430 BuiltIn().set_global_variable("${plug_in_packages_list}", 431 plug_in_packages_list) 432 433 grv.rvalid_value("stack_mode", valid_values=['normal', 'skip']) 434 if len(boot_list) == 0 and len(boot_stack) == 0 and not ffdc_only: 435 error_message = "You must provide either a value for either the" +\ 436 " boot_list or the boot_stack parm.\n" 437 BuiltIn().fail(gp.sprint_error(error_message)) 438 439 valid_boot_list(boot_list, valid_boot_types) 440 valid_boot_list(boot_stack, valid_boot_types) 441 442 selected_PDU_boots = list(set(boot_list + boot_stack) & 443 set(boot_lists['PDU_reboot'])) 444 445 if len(selected_PDU_boots) > 0 and pdu_host == "": 446 error_message = "You have selected the following boots which" +\ 447 " require a PDU host but no value for pdu_host:\n" 448 error_message += gp.sprint_var(selected_PDU_boots) 449 error_message += gp.sprint_var(pdu_host, 2) 450 BuiltIn().fail(gp.sprint_error(error_message)) 451 452 return 453 454############################################################################### 455 456 457############################################################################### 458def my_get_state(): 459 460 r""" 461 Get the system state plus a little bit of wrapping. 462 """ 463 464 global state 465 466 req_states = ['epoch_seconds'] + st.default_req_states 467 468 gp.qprint_timen("Getting system state.") 469 if test_mode: 470 state['epoch_seconds'] = int(time.time()) 471 else: 472 state = st.get_state(req_states=req_states, quiet=quiet) 473 gp.qprint_var(state) 474 475############################################################################### 476 477 478############################################################################### 479def valid_state(): 480 481 r""" 482 Verify that our state dictionary contains no blank values. If we don't get 483 valid state data, we cannot continue to work. 484 """ 485 486 if st.compare_states(state, st.invalid_state_match, 'or'): 487 error_message = "The state dictionary contains blank fields which" +\ 488 " is illegal.\n" + gp.sprint_var(state) 489 BuiltIn().fail(gp.sprint_error(error_message)) 490 491############################################################################### 492 493 494############################################################################### 495def select_boot(): 496 497 r""" 498 Select a boot test to be run based on our current state and return the 499 chosen boot type. 500 501 Description of arguments: 502 state The state of the machine. 503 """ 504 505 global boot_stack 506 507 gp.qprint_timen("Selecting a boot test.") 508 509 my_get_state() 510 valid_state() 511 512 stack_popped = 0 513 if len(boot_stack) > 0: 514 stack_popped = 1 515 gp.qprint_dashes() 516 gp.qprint_var(boot_stack) 517 gp.qprint_dashes() 518 skip_boot_printed = 0 519 while len(boot_stack) > 0: 520 boot_candidate = boot_stack.pop() 521 if stack_mode == 'normal': 522 break 523 else: 524 if st.compare_states(state, boot_table[boot_candidate]['end']): 525 if not skip_boot_printed: 526 gp.qprint_var(stack_mode) 527 gp.qprintn() 528 gp.qprint_timen("Skipping the following boot tests" + 529 " which are unnecessary since their" + 530 " required end states match the" + 531 " current machine state:") 532 skip_boot_printed = 1 533 gp.qprint_var(boot_candidate) 534 boot_candidate = "" 535 if boot_candidate == "": 536 gp.qprint_dashes() 537 gp.qprint_var(boot_stack) 538 gp.qprint_dashes() 539 return boot_candidate 540 if st.compare_states(state, boot_table[boot_candidate]['start']): 541 gp.qprint_timen("The machine state is valid for a '" + 542 boot_candidate + "' boot test.") 543 gp.qprint_dashes() 544 gp.qprint_var(boot_stack) 545 gp.qprint_dashes() 546 return boot_candidate 547 else: 548 gp.qprint_timen("The machine state does not match the required" + 549 " starting state for a '" + boot_candidate + 550 "' boot test:") 551 gp.qprint_varx("boot_table[" + boot_candidate + "][start]", 552 boot_table[boot_candidate]['start'], 1) 553 boot_stack.append(boot_candidate) 554 popped_boot = boot_candidate 555 556 # Loop through your list selecting a boot_candidates 557 boot_candidates = [] 558 for boot_candidate in boot_list: 559 if st.compare_states(state, boot_table[boot_candidate]['start']): 560 if stack_popped: 561 if st.compare_states(boot_table[boot_candidate]['end'], 562 boot_table[popped_boot]['start']): 563 boot_candidates.append(boot_candidate) 564 else: 565 boot_candidates.append(boot_candidate) 566 567 if len(boot_candidates) == 0: 568 gp.qprint_timen("The user's boot list contained no boot tests" + 569 " which are valid for the current machine state.") 570 boot_candidate = default_power_on 571 if not st.compare_states(state, boot_table[default_power_on]['start']): 572 boot_candidate = default_power_off 573 boot_candidates.append(boot_candidate) 574 gp.qprint_timen("Using default '" + boot_candidate + 575 "' boot type to transition to valid state.") 576 577 gp.dprint_var(boot_candidates) 578 579 # Randomly select a boot from the candidate list. 580 boot = random.choice(boot_candidates) 581 582 return boot 583 584############################################################################### 585 586 587############################################################################### 588def print_last_boots(): 589 590 r""" 591 Print the last ten boots done with their time stamps. 592 """ 593 594 # indent 0, 90 chars wide, linefeed, char is "=" 595 gp.qprint_dashes(0, 90) 596 gp.qprintn("Last 10 boots:\n") 597 598 for boot_entry in last_ten: 599 grp.rqprint(boot_entry) 600 gp.qprint_dashes(0, 90) 601 602############################################################################### 603 604 605############################################################################### 606def print_defect_report(): 607 608 r""" 609 Print a defect report. 610 """ 611 612 # Making deliberate choice to NOT run plug_in_setup(). We don't want 613 # ffdc_prefix updated. 614 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages( 615 call_point='ffdc_report', stop_on_plug_in_failure=0) 616 617 # At some point I'd like to have the 'Call FFDC Methods' return a list 618 # of files it has collected. In that case, the following "ls" command 619 # would no longer be needed. For now, however, glob shows the files 620 # named in FFDC_LIST_FILE_PATH so I will refrain from printing those 621 # out (so we don't see duplicates in the list). 622 623 # Get additional header data which may have been created by ffdc plug-ins. 624 # Also, delete the individual header files to cleanup. 625 cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\ 626 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\ 627 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :" 628 shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0, 629 show_err=0) 630 631 # Get additional header data which may have been created by ffdc plug-ins. 632 # Also, delete the individual header files to cleanup. 633 cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\ 634 " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\ 635 " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :" 636 shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0, 637 show_err=0) 638 639 LOG_PREFIX = BuiltIn().get_variable_value("${LOG_PREFIX}") 640 641 output = '\n'.join(sorted(glob.glob(LOG_PREFIX + '*'))) 642 try: 643 ffdc_list = open(ffdc_list_file_path, 'r') 644 except IOError: 645 ffdc_list = "" 646 647 # Open ffdc_file_list for writing. We will write a complete list of 648 # FFDC files to it for possible use by plug-ins like cp_stop_check. 649 ffdc_list_file = open(ffdc_list_file_path, 'w') 650 651 gp.qprintn() 652 # indent=0, width=90, linefeed=1, char="=" 653 gp.qprint_dashes(0, 90, 1, "=") 654 gp.qprintn("Copy this data to the defect:\n") 655 656 if len(more_header_info) > 0: 657 gp.qprintn(more_header_info) 658 gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host, 659 openbmc_host_name, openbmc_ip, openbmc_username, 660 openbmc_password, os_host, os_host_name, os_ip, os_username, 661 os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username, 662 pdu_password, pdu_slot_no, openbmc_serial_host, 663 openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port) 664 665 gp.qprintn() 666 667 print_last_boots() 668 gp.qprintn() 669 gp.qprint_var(state) 670 671 gp.qprintn() 672 gp.qprintn("FFDC data files:") 673 if status_file_path != "": 674 gp.qprintn(status_file_path) 675 ffdc_list_file.write(status_file_path + "\n") 676 677 gp.qprintn(output) 678 # gp.qprintn(ffdc_list) 679 gp.qprintn() 680 681 if len(ffdc_summary_info) > 0: 682 gp.qprintn(ffdc_summary_info) 683 684 gp.qprint_dashes(0, 90, 1, "=") 685 686 ffdc_list_file.write(output + "\n") 687 ffdc_list_file.close() 688 689############################################################################### 690 691 692############################################################################### 693def my_ffdc(): 694 695 r""" 696 Collect FFDC data. 697 """ 698 699 global state 700 701 plug_in_setup() 702 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages( 703 call_point='ffdc', stop_on_plug_in_failure=0) 704 705 AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX'] 706 status, ret_values = grk.run_key_u("FFDC ffdc_prefix=" + 707 AUTOBOOT_FFDC_PREFIX + 708 " ffdc_function_list=" + 709 ffdc_function_list, ignore=1) 710 if status != 'PASS': 711 gp.qprint_error("Call to ffdc failed.\n") 712 713 my_get_state() 714 715 print_defect_report() 716 717############################################################################### 718 719 720############################################################################### 721def print_test_start_message(boot_keyword): 722 723 r""" 724 Print a message indicating what boot test is about to run. 725 726 Description of arguments: 727 boot_keyword The name of the boot which is to be run 728 (e.g. "BMC Power On"). 729 """ 730 731 global last_ten 732 global boot_start_time 733 734 doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".") 735 736 # Set boot_start_time for use by plug-ins. 737 boot_start_time = doing_msg[1:33] 738 gp.qprint_var(boot_start_time) 739 740 gp.qprint(doing_msg) 741 742 last_ten.append(doing_msg) 743 744 if len(last_ten) > 10: 745 del last_ten[0] 746 747############################################################################### 748 749 750############################################################################### 751def run_boot(boot): 752 753 r""" 754 Run the specified boot. 755 756 Description of arguments: 757 boot The name of the boot test to be performed. 758 """ 759 760 global state 761 762 print_test_start_message(boot) 763 764 plug_in_setup() 765 rc, shell_rc, failed_plug_in_name = \ 766 grpi.rprocess_plug_in_packages(call_point="pre_boot") 767 if rc != 0: 768 error_message = "Plug-in failed with non-zero return code.\n" +\ 769 gp.sprint_var(rc, 1) 770 BuiltIn().fail(gp.sprint_error(error_message)) 771 772 if test_mode: 773 # In test mode, we'll pretend the boot worked by assigning its 774 # required end state to the default state value. 775 state = st.strip_anchor_state(boot_table[boot]['end']) 776 else: 777 # Assertion: We trust that the state data was made fresh by the 778 # caller. 779 780 gp.qprintn() 781 782 if boot_table[boot]['method_type'] == "keyword": 783 rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''), 784 boot_table[boot]['method'], 785 quiet=quiet) 786 787 if boot_table[boot]['bmc_reboot']: 788 st.wait_for_comm_cycle(int(state['epoch_seconds'])) 789 plug_in_setup() 790 rc, shell_rc, failed_plug_in_name = \ 791 grpi.rprocess_plug_in_packages(call_point="post_reboot") 792 if rc != 0: 793 error_message = "Plug-in failed with non-zero return code.\n" 794 error_message += gp.sprint_var(rc, 1) 795 BuiltIn().fail(gp.sprint_error(error_message)) 796 else: 797 match_state = st.anchor_state(state) 798 del match_state['epoch_seconds'] 799 # Wait for the state to change in any way. 800 st.wait_state(match_state, wait_time=state_change_timeout, 801 interval="10 seconds", invert=1) 802 803 gp.qprintn() 804 if boot_table[boot]['end']['chassis'] == "Off": 805 boot_timeout = power_off_timeout 806 else: 807 boot_timeout = power_on_timeout 808 st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout, 809 interval="10 seconds") 810 811 plug_in_setup() 812 rc, shell_rc, failed_plug_in_name = \ 813 grpi.rprocess_plug_in_packages(call_point="post_boot") 814 if rc != 0: 815 error_message = "Plug-in failed with non-zero return code.\n" +\ 816 gp.sprint_var(rc, 1) 817 BuiltIn().fail(gp.sprint_error(error_message)) 818 819############################################################################### 820 821 822############################################################################### 823def test_loop_body(): 824 825 r""" 826 The main loop body for the loop in main_py. 827 828 Description of arguments: 829 boot_count The iteration number (starts at 1). 830 """ 831 832 global boot_count 833 global state 834 global next_boot 835 global boot_success 836 global boot_end_time 837 838 gp.qprintn() 839 840 next_boot = select_boot() 841 if next_boot == "": 842 return True 843 844 boot_count += 1 845 gp.qprint_timen("Starting boot " + str(boot_count) + ".") 846 847 pre_boot_plug_in_setup() 848 849 cmd_buf = ["run_boot", next_boot] 850 boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf) 851 if boot_status == "FAIL": 852 gp.qprint(msg) 853 854 gp.qprintn() 855 if boot_status == "PASS": 856 boot_success = 1 857 completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot + 858 "\" succeeded.") 859 else: 860 boot_success = 0 861 completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot + 862 "\" failed.") 863 864 # Set boot_end_time for use by plug-ins. 865 boot_end_time = completion_msg[1:33] 866 gp.qprint_var(boot_end_time) 867 868 gp.qprint(completion_msg) 869 870 boot_results.update(next_boot, boot_status) 871 872 plug_in_setup() 873 # NOTE: A post_test_case call point failure is NOT counted as a boot 874 # failure. 875 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages( 876 call_point='post_test_case', stop_on_plug_in_failure=0) 877 878 plug_in_setup() 879 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages( 880 call_point='ffdc_check', shell_rc=0x00000200, 881 stop_on_plug_in_failure=1, stop_on_non_zero_rc=1) 882 if boot_status != "PASS" or ffdc_check == "All" or shell_rc == 0x00000200: 883 status, ret_values = grk.run_key_u("my_ffdc", ignore=1) 884 if status != 'PASS': 885 gp.qprint_error("Call to my_ffdc failed.\n") 886 887 # We need to purge error logs between boots or they build up. 888 grk.run_key("Delete Error logs", ignore=1) 889 890 boot_results.print_report() 891 gp.qprint_timen("Finished boot " + str(boot_count) + ".") 892 893 plug_in_setup() 894 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages( 895 call_point='stop_check') 896 if rc != 0: 897 error_message = "Stopping as requested by user.\n" 898 grp.rprint_error_report(error_message) 899 BuiltIn().fail(error_message) 900 901 # This should help prevent ConnectionErrors. 902 grk.run_key_u("Close All Connections") 903 904 return True 905 906############################################################################### 907 908 909############################################################################### 910def obmc_boot_test_teardown(): 911 912 r""" 913 Clean up after the Main keyword. 914 """ 915 916 if cp_setup_called: 917 plug_in_setup() 918 rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages( 919 call_point='cleanup', stop_on_plug_in_failure=0) 920 921 if 'boot_results_file_path' in globals(): 922 # Save boot_results object to a file in case it is needed again. 923 gp.qprint_timen("Saving boot_results to the following path.") 924 gp.qprint_var(boot_results_file_path) 925 pickle.dump(boot_results, open(boot_results_file_path, 'wb'), 926 pickle.HIGHEST_PROTOCOL) 927 928 global save_stack 929 # Restore any global values saved on the save_stack. 930 for parm_name in main_func_parm_list: 931 # Get the parm_value if it was saved on the stack. 932 try: 933 parm_value = save_stack.pop(parm_name) 934 except: 935 # If it was not saved, no further action is required. 936 continue 937 938 # Restore the saved value. 939 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\ 940 "}\", parm_value)" 941 gp.dpissuing(cmd_buf) 942 exec(cmd_buf) 943 944 gp.dprintn(save_stack.sprint_obj()) 945 946############################################################################### 947 948 949############################################################################### 950def test_teardown(): 951 952 r""" 953 Clean up after this test case. 954 """ 955 956 gp.qprintn() 957 cmd_buf = ["Print Error", 958 "A keyword timeout occurred ending this program.\n"] 959 BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf) 960 961 grp.rqprint_pgm_footer() 962 963############################################################################### 964 965 966############################################################################### 967def obmc_boot_test_py(loc_boot_stack=None, 968 loc_stack_mode=None, 969 loc_quiet=None): 970 971 r""" 972 Do main program processing. 973 """ 974 975 global save_stack 976 977 # Process function parms. 978 for parm_name in main_func_parm_list: 979 # Get parm's value. 980 cmd_buf = "parm_value = loc_" + parm_name 981 exec(cmd_buf) 982 gp.dpvar(parm_name) 983 gp.dpvar(parm_value) 984 985 if parm_value is None: 986 # Parm was not specified by the calling function so set it to its 987 # corresponding global value. 988 cmd_buf = "loc_" + parm_name + " = BuiltIn().get_variable_value" +\ 989 "(\"${" + parm_name + "}\")" 990 gp.dpissuing(cmd_buf) 991 exec(cmd_buf) 992 else: 993 # Save the global value on a stack. 994 cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\ 995 parm_name + "}\"), \"" + parm_name + "\")" 996 gp.dpissuing(cmd_buf) 997 exec(cmd_buf) 998 999 # Set the global value to the passed value. 1000 cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\ 1001 "}\", loc_" + parm_name + ")" 1002 gp.dpissuing(cmd_buf) 1003 exec(cmd_buf) 1004 1005 gp.dprintn(save_stack.sprint_obj()) 1006 1007 setup() 1008 1009 if ffdc_only: 1010 gp.qprint_timen("Caller requested ffdc_only.") 1011 pre_boot_plug_in_setup() 1012 grk.run_key_u("my_ffdc") 1013 return 1014 1015 # Process caller's boot_stack. 1016 while (len(boot_stack) > 0): 1017 test_loop_body() 1018 1019 gp.qprint_timen("Finished processing stack.") 1020 1021 # Process caller's boot_list. 1022 if len(boot_list) > 0: 1023 for ix in range(1, max_num_tests + 1): 1024 test_loop_body() 1025 1026 gp.qprint_timen("Completed all requested boot tests.") 1027 1028 boot_pass, boot_fail = boot_results.return_total_pass_fail() 1029 if boot_fail > boot_fail_threshold: 1030 error_message = "Boot failures exceed the boot failure" +\ 1031 " threshold:\n" +\ 1032 gp.sprint_var(boot_fail) +\ 1033 gp.sprint_var(boot_fail_threshold) 1034 BuiltIn().fail(gp.sprint_error(error_message)) 1035 1036############################################################################### 1037