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