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 select_boot():
480
481    r"""
482    Select a boot test to be run based on our current state and return the
483    chosen boot type.
484
485    Description of arguments:
486    state  The state of the machine.
487    """
488
489    global boot_stack
490
491    gp.qprint_timen("Selecting a boot test.")
492
493    my_get_state()
494
495    stack_popped = 0
496    if len(boot_stack) > 0:
497        stack_popped = 1
498        gp.qprint_dashes()
499        gp.qprint_var(boot_stack)
500        gp.qprint_dashes()
501        skip_boot_printed = 0
502        while len(boot_stack) > 0:
503            boot_candidate = boot_stack.pop()
504            if stack_mode == 'normal':
505                break
506            else:
507                if st.compare_states(state, boot_table[boot_candidate]['end']):
508                    if not skip_boot_printed:
509                        gp.qprint_var(stack_mode)
510                        gp.qprintn()
511                        gp.qprint_timen("Skipping the following boot tests" +
512                                        " which are unnecessary since their" +
513                                        " required end states match the" +
514                                        " current machine state:")
515                        skip_boot_printed = 1
516                    gp.qprint_var(boot_candidate)
517                    boot_candidate = ""
518        if boot_candidate == "":
519            gp.qprint_dashes()
520            gp.qprint_var(boot_stack)
521            gp.qprint_dashes()
522            return boot_candidate
523        if st.compare_states(state, boot_table[boot_candidate]['start']):
524            gp.qprint_timen("The machine state is valid for a '" +
525                            boot_candidate + "' boot test.")
526            gp.qprint_dashes()
527            gp.qprint_var(boot_stack)
528            gp.qprint_dashes()
529            return boot_candidate
530        else:
531            gp.qprint_timen("The machine state does not match the required" +
532                            " starting state for a '" + boot_candidate +
533                            "' boot test:")
534            gp.qprint_varx("boot_table[" + boot_candidate + "][start]",
535                           boot_table[boot_candidate]['start'], 1)
536            boot_stack.append(boot_candidate)
537            popped_boot = boot_candidate
538
539    # Loop through your list selecting a boot_candidates
540    boot_candidates = []
541    for boot_candidate in boot_list:
542        if st.compare_states(state, boot_table[boot_candidate]['start']):
543            if stack_popped:
544                if st.compare_states(boot_table[boot_candidate]['end'],
545                   boot_table[popped_boot]['start']):
546                    boot_candidates.append(boot_candidate)
547            else:
548                boot_candidates.append(boot_candidate)
549
550    if len(boot_candidates) == 0:
551        gp.qprint_timen("The user's boot list contained no boot tests" +
552                        " which are valid for the current machine state.")
553        boot_candidate = default_power_on
554        if not st.compare_states(state, boot_table[default_power_on]['start']):
555            boot_candidate = default_power_off
556        boot_candidates.append(boot_candidate)
557        gp.qprint_timen("Using default '" + boot_candidate +
558                        "' boot type to transition to valid state.")
559
560    gp.dprint_var(boot_candidates)
561
562    # Randomly select a boot from the candidate list.
563    boot = random.choice(boot_candidates)
564
565    return boot
566
567###############################################################################
568
569
570###############################################################################
571def print_last_boots():
572
573    r"""
574    Print the last ten boots done with their time stamps.
575    """
576
577    # indent 0, 90 chars wide, linefeed, char is "="
578    gp.qprint_dashes(0, 90)
579    gp.qprintn("Last 10 boots:\n")
580
581    for boot_entry in last_ten:
582        grp.rqprint(boot_entry)
583    gp.qprint_dashes(0, 90)
584
585###############################################################################
586
587
588###############################################################################
589def print_defect_report():
590
591    r"""
592    Print a defect report.
593    """
594
595    # Making deliberate choice to NOT run plug_in_setup().  We don't want
596    # ffdc_prefix updated.
597    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
598        call_point='ffdc_report', stop_on_plug_in_failure=0)
599
600    # At some point I'd like to have the 'Call FFDC Methods' return a list
601    # of files it has collected.  In that case, the following "ls" command
602    # would no longer be needed.  For now, however, glob shows the files
603    # named in FFDC_LIST_FILE_PATH so I will refrain from printing those
604    # out (so we don't see duplicates in the list).
605
606    # Get additional header data which may have been created by ffdc plug-ins.
607    # Also, delete the individual header files to cleanup.
608    cmd_buf = "file_list=$(cat " + ffdc_report_list_path + " 2>/dev/null)" +\
609              " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
610              " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
611    shell_rc, more_header_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
612                                              show_err=0)
613
614    # Get additional header data which may have been created by ffdc plug-ins.
615    # Also, delete the individual header files to cleanup.
616    cmd_buf = "file_list=$(cat " + ffdc_summary_list_path + " 2>/dev/null)" +\
617              " ; [ ! -z \"${file_list}\" ] && cat ${file_list}" +\
618              " 2>/dev/null ; rm -rf ${file_list} 2>/dev/null || :"
619    shell_rc, ffdc_summary_info = gc.cmd_fnc_u(cmd_buf, print_output=0,
620                                               show_err=0)
621
622    LOG_PREFIX = BuiltIn().get_variable_value("${LOG_PREFIX}")
623
624    output = '\n'.join(sorted(glob.glob(LOG_PREFIX + '*')))
625    try:
626        ffdc_list = open(ffdc_list_file_path, 'r')
627    except IOError:
628        ffdc_list = ""
629
630    # Open ffdc_file_list for writing.  We will write a complete list of
631    # FFDC files to it for possible use by plug-ins like cp_stop_check.
632    ffdc_list_file = open(ffdc_list_file_path, 'w')
633
634    gp.qprintn()
635    # indent=0, width=90, linefeed=1, char="="
636    gp.qprint_dashes(0, 90, 1, "=")
637    gp.qprintn("Copy this data to the defect:\n")
638
639    if len(more_header_info) > 0:
640        gp.qprintn(more_header_info)
641    gp.qpvars(host_name, host_ip, openbmc_nickname, openbmc_host,
642              openbmc_host_name, openbmc_ip, openbmc_username,
643              openbmc_password, os_host, os_host_name, os_ip, os_username,
644              os_password, pdu_host, pdu_host_name, pdu_ip, pdu_username,
645              pdu_password, pdu_slot_no, openbmc_serial_host,
646              openbmc_serial_host_name, openbmc_serial_ip, openbmc_serial_port)
647
648    gp.qprintn()
649
650    print_last_boots()
651    gp.qprintn()
652    gp.qprint_var(state)
653
654    gp.qprintn()
655    gp.qprintn("FFDC data files:")
656    if status_file_path != "":
657        gp.qprintn(status_file_path)
658        ffdc_list_file.write(status_file_path + "\n")
659
660    gp.qprintn(output)
661    # gp.qprintn(ffdc_list)
662    gp.qprintn()
663
664    if len(ffdc_summary_info) > 0:
665        gp.qprintn(ffdc_summary_info)
666
667    gp.qprint_dashes(0, 90, 1, "=")
668
669    ffdc_list_file.write(output + "\n")
670    ffdc_list_file.close()
671
672###############################################################################
673
674
675###############################################################################
676def my_ffdc():
677
678    r"""
679    Collect FFDC data.
680    """
681
682    global state
683
684    plug_in_setup()
685    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
686        call_point='ffdc', stop_on_plug_in_failure=0)
687
688    AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
689    status, ret_values = grk.run_key_u("FFDC  ffdc_prefix=" +
690                                       AUTOBOOT_FFDC_PREFIX +
691                                       "  ffdc_function_list=" +
692                                       ffdc_function_list, ignore=1)
693    if status != 'PASS':
694        gp.qprint_error("Call to ffdc failed.\n")
695
696    my_get_state()
697
698    print_defect_report()
699
700###############################################################################
701
702
703###############################################################################
704def print_test_start_message(boot_keyword):
705
706    r"""
707    Print a message indicating what boot test is about to run.
708
709    Description of arguments:
710    boot_keyword  The name of the boot which is to be run
711                  (e.g. "BMC Power On").
712    """
713
714    global last_ten
715    global boot_start_time
716
717    doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
718
719    # Set boot_start_time for use by plug-ins.
720    boot_start_time = doing_msg[1:33]
721    gp.qprint_var(boot_start_time)
722
723    gp.qprint(doing_msg)
724
725    last_ten.append(doing_msg)
726
727    if len(last_ten) > 10:
728        del last_ten[0]
729
730###############################################################################
731
732
733###############################################################################
734def run_boot(boot):
735
736    r"""
737    Run the specified boot.
738
739    Description of arguments:
740    boot  The name of the boot test to be performed.
741    """
742
743    global state
744
745    print_test_start_message(boot)
746
747    plug_in_setup()
748    rc, shell_rc, failed_plug_in_name = \
749        grpi.rprocess_plug_in_packages(call_point="pre_boot")
750    if rc != 0:
751        error_message = "Plug-in failed with non-zero return code.\n" +\
752            gp.sprint_var(rc, 1)
753        BuiltIn().fail(gp.sprint_error(error_message))
754
755    if test_mode:
756        # In test mode, we'll pretend the boot worked by assigning its
757        # required end state to the default state value.
758        state = st.strip_anchor_state(boot_table[boot]['end'])
759    else:
760        # Assertion:  We trust that the state data was made fresh by the
761        # caller.
762
763        gp.qprintn()
764
765        if boot_table[boot]['method_type'] == "keyword":
766            rk.my_run_keywords(boot_table[boot].get('lib_file_path', ''),
767                               boot_table[boot]['method'],
768                               quiet=quiet)
769
770        if boot_table[boot]['bmc_reboot']:
771            st.wait_for_comm_cycle(int(state['epoch_seconds']))
772            plug_in_setup()
773            rc, shell_rc, failed_plug_in_name = \
774                grpi.rprocess_plug_in_packages(call_point="post_reboot")
775            if rc != 0:
776                error_message = "Plug-in failed with non-zero return code.\n"
777                error_message += gp.sprint_var(rc, 1)
778                BuiltIn().fail(gp.sprint_error(error_message))
779        else:
780            match_state = st.anchor_state(state)
781            del match_state['epoch_seconds']
782            # Wait for the state to change in any way.
783            st.wait_state(match_state, wait_time=state_change_timeout,
784                          interval="10 seconds", invert=1)
785
786        gp.qprintn()
787        if boot_table[boot]['end']['chassis'] == "Off":
788            boot_timeout = power_off_timeout
789        else:
790            boot_timeout = power_on_timeout
791        st.wait_state(boot_table[boot]['end'], wait_time=boot_timeout,
792                      interval="10 seconds")
793
794    plug_in_setup()
795    rc, shell_rc, failed_plug_in_name = \
796        grpi.rprocess_plug_in_packages(call_point="post_boot")
797    if rc != 0:
798        error_message = "Plug-in failed with non-zero return code.\n" +\
799            gp.sprint_var(rc, 1)
800        BuiltIn().fail(gp.sprint_error(error_message))
801
802###############################################################################
803
804
805###############################################################################
806def test_loop_body():
807
808    r"""
809    The main loop body for the loop in main_py.
810
811    Description of arguments:
812    boot_count  The iteration number (starts at 1).
813    """
814
815    global boot_count
816    global state
817    global next_boot
818    global boot_success
819    global boot_end_time
820
821    gp.qprintn()
822
823    next_boot = select_boot()
824    if next_boot == "":
825        return True
826
827    boot_count += 1
828    gp.qprint_timen("Starting boot " + str(boot_count) + ".")
829
830    pre_boot_plug_in_setup()
831
832    cmd_buf = ["run_boot", next_boot]
833    boot_status, msg = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
834    if boot_status == "FAIL":
835        gp.qprint(msg)
836
837    gp.qprintn()
838    if boot_status == "PASS":
839        boot_success = 1
840        completion_msg = gp.sprint_timen("BOOT_SUCCESS: \"" + next_boot +
841                                         "\" succeeded.")
842    else:
843        boot_success = 0
844        completion_msg = gp.sprint_timen("BOOT_FAILED: \"" + next_boot +
845                                         "\" failed.")
846
847    # Set boot_end_time for use by plug-ins.
848    boot_end_time = completion_msg[1:33]
849    gp.qprint_var(boot_end_time)
850
851    gp.qprint(completion_msg)
852
853    boot_results.update(next_boot, boot_status)
854
855    plug_in_setup()
856    # NOTE: A post_test_case call point failure is NOT counted as a boot
857    # failure.
858    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
859        call_point='post_test_case', stop_on_plug_in_failure=0)
860
861    plug_in_setup()
862    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
863        call_point='ffdc_check', shell_rc=0x00000200,
864        stop_on_plug_in_failure=1, stop_on_non_zero_rc=1)
865    if boot_status != "PASS" or ffdc_check == "All" or shell_rc == 0x00000200:
866        status, ret_values = grk.run_key_u("my_ffdc", ignore=1)
867        if status != 'PASS':
868            gp.qprint_error("Call to my_ffdc failed.\n")
869
870    # We need to purge error logs between boots or they build up.
871    grk.run_key("Delete Error logs", ignore=1)
872
873    boot_results.print_report()
874    gp.qprint_timen("Finished boot " + str(boot_count) + ".")
875
876    plug_in_setup()
877    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
878        call_point='stop_check')
879    if rc != 0:
880        error_message = "Stopping as requested by user.\n"
881        grp.rprint_error_report(error_message)
882        BuiltIn().fail(error_message)
883
884    # This should help prevent ConnectionErrors.
885    grk.run_key_u("Close All Connections")
886
887    return True
888
889###############################################################################
890
891
892###############################################################################
893def obmc_boot_test_teardown():
894
895    r"""
896    Clean up after the Main keyword.
897    """
898
899    if cp_setup_called:
900        plug_in_setup()
901        rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
902            call_point='cleanup', stop_on_plug_in_failure=0)
903
904    if 'boot_results_file_path' in globals():
905        # Save boot_results object to a file in case it is needed again.
906        gp.qprint_timen("Saving boot_results to the following path.")
907        gp.qprint_var(boot_results_file_path)
908        pickle.dump(boot_results, open(boot_results_file_path, 'wb'),
909                    pickle.HIGHEST_PROTOCOL)
910
911    global save_stack
912    # Restore any global values saved on the save_stack.
913    for parm_name in main_func_parm_list:
914        # Get the parm_value if it was saved on the stack.
915        try:
916            parm_value = save_stack.pop(parm_name)
917        except:
918            # If it was not saved, no further action is required.
919            continue
920
921        # Restore the saved value.
922        cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
923            "}\", parm_value)"
924        gp.dpissuing(cmd_buf)
925        exec(cmd_buf)
926
927    gp.dprintn(save_stack.sprint_obj())
928
929###############################################################################
930
931
932###############################################################################
933def test_teardown():
934
935    r"""
936    Clean up after this test case.
937    """
938
939    gp.qprintn()
940    cmd_buf = ["Print Error",
941               "A keyword timeout occurred ending this program.\n"]
942    BuiltIn().run_keyword_if_timeout_occurred(*cmd_buf)
943
944    grp.rqprint_pgm_footer()
945
946###############################################################################
947
948
949###############################################################################
950def obmc_boot_test_py(loc_boot_stack=None,
951                      loc_stack_mode=None,
952                      loc_quiet=None):
953
954    r"""
955    Do main program processing.
956    """
957
958    global save_stack
959
960    # Process function parms.
961    for parm_name in main_func_parm_list:
962        # Get parm's value.
963        cmd_buf = "parm_value = loc_" + parm_name
964        exec(cmd_buf)
965        gp.dpvar(parm_name)
966        gp.dpvar(parm_value)
967
968        if parm_value is None:
969            # Parm was not specified by the calling function so set it to its
970            # corresponding global value.
971            cmd_buf = "loc_" + parm_name + " = BuiltIn().get_variable_value" +\
972                "(\"${" + parm_name + "}\")"
973            gp.dpissuing(cmd_buf)
974            exec(cmd_buf)
975        else:
976            # Save the global value on a stack.
977            cmd_buf = "save_stack.push(BuiltIn().get_variable_value(\"${" +\
978                parm_name + "}\"), \"" + parm_name + "\")"
979            gp.dpissuing(cmd_buf)
980            exec(cmd_buf)
981
982            # Set the global value to the passed value.
983            cmd_buf = "BuiltIn().set_global_variable(\"${" + parm_name +\
984                "}\", loc_" + parm_name + ")"
985            gp.dpissuing(cmd_buf)
986            exec(cmd_buf)
987
988    gp.dprintn(save_stack.sprint_obj())
989
990    setup()
991
992    if ffdc_only:
993        gp.qprint_timen("Caller requested ffdc_only.")
994        pre_boot_plug_in_setup()
995        grk.run_key_u("my_ffdc")
996        return
997
998    # Process caller's boot_stack.
999    while (len(boot_stack) > 0):
1000        test_loop_body()
1001
1002    gp.qprint_timen("Finished processing stack.")
1003
1004    # Process caller's boot_list.
1005    if len(boot_list) > 0:
1006        for ix in range(1, max_num_tests + 1):
1007            test_loop_body()
1008
1009    gp.qprint_timen("Completed all requested boot tests.")
1010
1011    boot_pass, boot_fail = boot_results.return_total_pass_fail()
1012    if boot_fail > boot_fail_threshold:
1013        error_message = "Boot failures exceed the boot failure" +\
1014                        " threshold:\n" +\
1015                        gp.sprint_var(boot_fail) +\
1016                        gp.sprint_var(boot_fail_threshold)
1017        BuiltIn().fail(gp.sprint_error(error_message))
1018
1019###############################################################################
1020