xref: /openbmc/openbmc-test-automation/lib/boot_data.py (revision 20f38712b324e61a94e174017c487a0af4b373e1)
1e7e9171eSGeorge Keishing#!/usr/bin/env python3
2ac29d063SMichael Walsh
3ac29d063SMichael Walshr"""
4410b1787SMichael WalshThis module has functions to support various data structures such as the boot_table, valid_boot_list and
5410b1787SMichael Walshboot_results_table.
6ac29d063SMichael Walsh"""
7ac29d063SMichael Walsh
8*20f38712SPatrick Williamsimport glob
9*20f38712SPatrick Williamsimport json
10ac29d063SMichael Walshimport os
11ac29d063SMichael Walshimport tempfile
125731818dSPatrick Williams
13e635ddc0SGeorge Keishingfrom robot.libraries.BuiltIn import BuiltIn
14*20f38712SPatrick Williamsfrom tally_sheet import *
15*20f38712SPatrick Williams
16ac29d063SMichael Walshtry:
17ac29d063SMichael Walsh    from robot.utils import DotDict
18ac29d063SMichael Walshexcept ImportError:
19ac29d063SMichael Walsh    import collections
20ac29d063SMichael Walsh
21*20f38712SPatrick Williamsimport gen_cmd as gc
22*20f38712SPatrick Williamsimport gen_misc as gm
23ac29d063SMichael Walshimport gen_print as gp
24ac29d063SMichael Walshimport gen_valid as gv
25b6e3aacdSMichael Walshimport var_funcs as vf
26ac29d063SMichael Walsh
27410b1787SMichael Walsh# The code base directory will be one level up from the directory containing this module.
28ac29d063SMichael Walshcode_base_dir_path = os.path.dirname(os.path.dirname(__file__)) + os.sep
29ac29d063SMichael Walsh
30*20f38712SPatrick Williamsredfish_support_trans_state = int(
31*20f38712SPatrick Williams    os.environ.get("REDFISH_SUPPORT_TRANS_STATE", 0)
32*20f38712SPatrick Williams) or int(
33*20f38712SPatrick Williams    BuiltIn().get_variable_value("${REDFISH_SUPPORT_TRANS_STATE}", default=0)
34*20f38712SPatrick Williams)
35da40c1d2SMichael Shepos
36*20f38712SPatrick Williamsplatform_arch_type = os.environ.get(
37*20f38712SPatrick Williams    "PLATFORM_ARCH_TYPE", ""
38*20f38712SPatrick Williams) or BuiltIn().get_variable_value("${PLATFORM_ARCH_TYPE}", default="power")
391e2fbee9SGeorge Keishing
40ac29d063SMichael Walsh
41*20f38712SPatrick Williamsdef create_boot_table(file_path=None, os_host=""):
42ac29d063SMichael Walsh    r"""
43ac29d063SMichael Walsh    Read the boot table JSON file, convert it to an object and return it.
44ac29d063SMichael Walsh
45410b1787SMichael Walsh    Note that if the user is running without a global OS_HOST robot variable specified, this function will
46410b1787SMichael Walsh    remove all of the "os_" start and end state requirements from the JSON data.
47ac29d063SMichael Walsh
486c4520c6SMichael Walsh    Description of argument(s):
49410b1787SMichael Walsh    file_path                       The path to the boot_table file.  If this value is not specified, it will
50410b1787SMichael Walsh                                    be obtained from the "BOOT_TABLE_PATH" environment variable, if set.
51410b1787SMichael Walsh                                    Otherwise, it will default to "data/boot_table.json".  If this value is a
52410b1787SMichael Walsh                                    relative path, this function will use the code_base_dir_path as the base
53410b1787SMichael Walsh                                    directory (see definition above).
54410b1787SMichael Walsh    os_host                         The host name or IP address of the host associated with the machine being
55410b1787SMichael Walsh                                    tested.  If the user is running without an OS_HOST (i.e. if this argument
56410b1787SMichael Walsh                                    is blank), we remove os starting and ending state requirements from the
57410b1787SMichael Walsh                                    boot entries.
58ac29d063SMichael Walsh    """
59ac29d063SMichael Walsh    if file_path is None:
60b51d1505SGeorge Keishing        if redfish_support_trans_state and platform_arch_type != "x86":
61*20f38712SPatrick Williams            file_path = os.environ.get(
62*20f38712SPatrick Williams                "BOOT_TABLE_PATH", "data/boot_table_redfish.json"
63*20f38712SPatrick Williams            )
641e2fbee9SGeorge Keishing        elif platform_arch_type == "x86":
65*20f38712SPatrick Williams            file_path = os.environ.get(
66*20f38712SPatrick Williams                "BOOT_TABLE_PATH", "data/boot_table_x86.json"
67*20f38712SPatrick Williams            )
68da40c1d2SMichael Shepos        else:
69*20f38712SPatrick Williams            file_path = os.environ.get(
70*20f38712SPatrick Williams                "BOOT_TABLE_PATH", "data/boot_table.json"
71*20f38712SPatrick Williams            )
72ac29d063SMichael Walsh
73ac29d063SMichael Walsh    if not file_path.startswith("/"):
74ac29d063SMichael Walsh        file_path = code_base_dir_path + file_path
75ac29d063SMichael Walsh
76ac29d063SMichael Walsh    # Pre-process the file by removing blank lines and comment lines.
77ac29d063SMichael Walsh    temp = tempfile.NamedTemporaryFile()
78ac29d063SMichael Walsh    temp_file_path = temp.name
79ac29d063SMichael Walsh
80ac29d063SMichael Walsh    cmd_buf = "egrep -v '^[ ]*$|^[ ]*#' " + file_path + " > " + temp_file_path
81ac29d063SMichael Walsh    gc.cmd_fnc_u(cmd_buf, quiet=1)
82ac29d063SMichael Walsh
83ac29d063SMichael Walsh    boot_file = open(temp_file_path)
84ac29d063SMichael Walsh    boot_table = json.load(boot_file, object_hook=DotDict)
85ac29d063SMichael Walsh
86410b1787SMichael Walsh    # If the user is running without an OS_HOST, we remove os starting and ending state requirements from
87410b1787SMichael Walsh    # the boot entries.
88ac29d063SMichael Walsh    if os_host == "":
89ac29d063SMichael Walsh        for boot in boot_table:
90*20f38712SPatrick Williams            state_keys = ["start", "end"]
91ac29d063SMichael Walsh            for state_key in state_keys:
9237f833d0SMichael Walsh                for sub_state in list(boot_table[boot][state_key]):
93ac29d063SMichael Walsh                    if sub_state.startswith("os_"):
94ac29d063SMichael Walsh                        boot_table[boot][state_key].pop(sub_state, None)
95ac29d063SMichael Walsh
9607a01ef6SMichael Walsh    # For every boot_type we should have a corresponding mfg mode boot type.
9707a01ef6SMichael Walsh    enhanced_boot_table = DotDict()
9836efbc04SGeorge Keishing    for key, value in boot_table.items():
9907a01ef6SMichael Walsh        enhanced_boot_table[key] = value
10007a01ef6SMichael Walsh        enhanced_boot_table[key + " (mfg)"] = value
10107a01ef6SMichael Walsh
10207a01ef6SMichael Walsh    return enhanced_boot_table
103ac29d063SMichael Walsh
104ac29d063SMichael Walsh
105ac29d063SMichael Walshdef create_valid_boot_list(boot_table):
106ac29d063SMichael Walsh    r"""
107410b1787SMichael Walsh    Return a list of all of the valid boot types (e.g. ['REST Power On', 'REST Power Off', ...]).
108ac29d063SMichael Walsh
1096c4520c6SMichael Walsh    Description of argument(s):
110410b1787SMichael Walsh    boot_table                      A boot table such as is returned by the create_boot_table function.
111ac29d063SMichael Walsh    """
112ac29d063SMichael Walsh
113ac29d063SMichael Walsh    return list(boot_table.keys())
114ac29d063SMichael Walsh
115ac29d063SMichael Walsh
116ac29d063SMichael Walshdef read_boot_lists(dir_path="data/boot_lists/"):
117ac29d063SMichael Walsh    r"""
118410b1787SMichael Walsh    Read the contents of all the boot lists files found in the given boot lists directory and return
119410b1787SMichael Walsh    dictionary of the lists.
120ac29d063SMichael Walsh
121410b1787SMichael Walsh    Boot lists are simply files containing a boot test name on each line.  These files are useful for
122410b1787SMichael Walsh    categorizing and organizing boot tests.  For example, there may be a "Power_on" list, a "Power_off" list,
123410b1787SMichael Walsh    etc.
124ac29d063SMichael Walsh
125410b1787SMichael Walsh    The names of the boot list files will be the keys to the top level dictionary.  Each dictionary entry is
126410b1787SMichael Walsh    a list of all the boot tests found in the corresponding file.
127ac29d063SMichael Walsh
128ac29d063SMichael Walsh    Here is an abbreviated look at the resulting boot_lists dictionary.
129ac29d063SMichael Walsh
130ac29d063SMichael Walsh    boot_lists:
131ac29d063SMichael Walsh      boot_lists[All]:
1326c4520c6SMichael Walsh        boot_lists[All][0]:                           REST Power On
1336c4520c6SMichael Walsh        boot_lists[All][1]:                           REST Power Off
134ac29d063SMichael Walsh    ...
135ac29d063SMichael Walsh      boot_lists[Code_update]:
136ac29d063SMichael Walsh        boot_lists[Code_update][0]:                   BMC oob hpm
137ac29d063SMichael Walsh        boot_lists[Code_update][1]:                   BMC ib hpm
138ac29d063SMichael Walsh    ...
139ac29d063SMichael Walsh
1406c4520c6SMichael Walsh    Description of argument(s):
141410b1787SMichael Walsh    dir_path                        The path to the directory containing the boot list files.  If this value
142410b1787SMichael Walsh                                    is a relative path, this function will use the code_base_dir_path as the
143410b1787SMichael Walsh                                    base directory (see definition above).
144ac29d063SMichael Walsh    """
145ac29d063SMichael Walsh
146ac29d063SMichael Walsh    if not dir_path.startswith("/"):
147ac29d063SMichael Walsh        # Dir path is relative.
148ac29d063SMichael Walsh        dir_path = code_base_dir_path + dir_path
149ac29d063SMichael Walsh
150ac29d063SMichael Walsh    # Get a list of all file names in the directory.
151ac29d063SMichael Walsh    boot_file_names = os.listdir(dir_path)
152ac29d063SMichael Walsh
153ac29d063SMichael Walsh    boot_lists = DotDict()
154ac29d063SMichael Walsh    for boot_category in boot_file_names:
155ac29d063SMichael Walsh        file_path = gm.which(dir_path + boot_category)
156ac29d063SMichael Walsh        boot_list = gm.file_to_list(file_path, newlines=0, comments=0, trim=1)
157ac29d063SMichael Walsh        boot_lists[boot_category] = boot_list
158ac29d063SMichael Walsh
159ac29d063SMichael Walsh    return boot_lists
160ac29d063SMichael Walsh
161ac29d063SMichael Walsh
162*20f38712SPatrick Williamsdef valid_boot_list(boot_list, valid_boot_types):
163ac29d063SMichael Walsh    r"""
164ac29d063SMichael Walsh    Verify that each entry in boot_list is a supported boot test.
165ac29d063SMichael Walsh
1666c4520c6SMichael Walsh    Description of argument(s):
167410b1787SMichael Walsh    boot_list                       An array (i.e. list) of boot test types (e.g. "REST Power On").
168410b1787SMichael Walsh    valid_boot_types                A list of valid boot types such as that returned by
169410b1787SMichael Walsh                                    create_valid_boot_list.
170ac29d063SMichael Walsh    """
171ac29d063SMichael Walsh
172ac29d063SMichael Walsh    for boot_name in boot_list:
173ac29d063SMichael Walsh        boot_name = boot_name.strip(" ")
174*20f38712SPatrick Williams        error_message = gv.valid_value(
175*20f38712SPatrick Williams            boot_name, valid_values=valid_boot_types, var_name="boot_name"
176*20f38712SPatrick Williams        )
177ac29d063SMichael Walsh        if error_message != "":
178ac29d063SMichael Walsh            BuiltIn().fail(gp.sprint_error(error_message))
179ac29d063SMichael Walsh
180ac29d063SMichael Walsh
181ac29d063SMichael Walshclass boot_results:
182ac29d063SMichael Walsh    r"""
183ac29d063SMichael Walsh    This class defines a boot_results table.
184ac29d063SMichael Walsh    """
185ac29d063SMichael Walsh
186*20f38712SPatrick Williams    def __init__(
187*20f38712SPatrick Williams        self, boot_table, boot_pass=0, boot_fail=0, obj_name="boot_results"
188*20f38712SPatrick Williams    ):
189ac29d063SMichael Walsh        r"""
190ac29d063SMichael Walsh        Initialize the boot results object.
191ac29d063SMichael Walsh
1926c4520c6SMichael Walsh        Description of argument(s):
193410b1787SMichael Walsh        boot_table                  Boot table object (see definition above).  The boot table contains all of
194410b1787SMichael Walsh                                    the valid boot test types.  It can be created with the create_boot_table
195410b1787SMichael Walsh                                    function.
196410b1787SMichael Walsh        boot_pass                   An initial boot_pass value.  This program may be called as part of a
197410b1787SMichael Walsh                                    larger test suite.  As such there may already have been some successful
198410b1787SMichael Walsh                                    boot tests that we need to keep track of.
199410b1787SMichael Walsh        boot_fail                   An initial boot_fail value.  This program may be called as part of a
200410b1787SMichael Walsh                                    larger test suite.  As such there may already have been some unsuccessful
201410b1787SMichael Walsh                                    boot tests that we need to keep track of.
202ac29d063SMichael Walsh        obj_name                    The name of this object.
203ac29d063SMichael Walsh        """
204ac29d063SMichael Walsh
205ac29d063SMichael Walsh        # Store the method parms as class data.
206ac29d063SMichael Walsh        self.__obj_name = obj_name
207ac29d063SMichael Walsh        self.__initial_boot_pass = boot_pass
208ac29d063SMichael Walsh        self.__initial_boot_fail = boot_fail
209ac29d063SMichael Walsh
210ac29d063SMichael Walsh        # Create boot_results_fields for use in creating boot_results table.
211*20f38712SPatrick Williams        boot_results_fields = DotDict([("total", 0), ("pass", 0), ("fail", 0)])
212ac29d063SMichael Walsh        # Create boot_results table.
213*20f38712SPatrick Williams        self.__boot_results = tally_sheet(
214*20f38712SPatrick Williams            "boot type", boot_results_fields, "boot_test_results"
215*20f38712SPatrick Williams        )
216*20f38712SPatrick Williams        self.__boot_results.set_sum_fields(["total", "pass", "fail"])
217*20f38712SPatrick Williams        self.__boot_results.set_calc_fields(["total=pass+fail"])
218410b1787SMichael Walsh        # Create one row in the result table for each kind of boot test in the boot_table (i.e. for all
219410b1787SMichael Walsh        # supported boot tests).
220ac29d063SMichael Walsh        for boot_name in list(boot_table.keys()):
221ac29d063SMichael Walsh            self.__boot_results.add_row(boot_name)
222ac29d063SMichael Walsh
2236c4520c6SMichael Walsh    def add_row(self, *args, **kwargs):
2246c4520c6SMichael Walsh        r"""
2256c4520c6SMichael Walsh        Add row to tally_sheet class object.
2266c4520c6SMichael Walsh
2276c4520c6SMichael Walsh        Description of argument(s):
228410b1787SMichael Walsh        See add_row method in tally_sheet.py for a description of all arguments.
2296c4520c6SMichael Walsh        """
2306c4520c6SMichael Walsh        self.__boot_results.add_row(*args, **kwargs)
2316c4520c6SMichael Walsh
232ac29d063SMichael Walsh    def return_total_pass_fail(self):
233ac29d063SMichael Walsh        r"""
234410b1787SMichael Walsh        Return the total boot_pass and boot_fail values.  This information is comprised of the pass/fail
235410b1787SMichael Walsh        values from the table plus the initial pass/fail values.
236ac29d063SMichael Walsh        """
237ac29d063SMichael Walsh
238ac29d063SMichael Walsh        totals_line = self.__boot_results.calc()
239*20f38712SPatrick Williams        return (
240*20f38712SPatrick Williams            totals_line["pass"] + self.__initial_boot_pass,
241*20f38712SPatrick Williams            totals_line["fail"] + self.__initial_boot_fail,
242*20f38712SPatrick Williams        )
243ac29d063SMichael Walsh
244*20f38712SPatrick Williams    def update(self, boot_type, boot_status):
245ac29d063SMichael Walsh        r"""
246ac29d063SMichael Walsh        Update our boot_results_table.  This includes:
247410b1787SMichael Walsh        - Updating the record for the given boot_type by incrementing the pass or fail field.
248ac29d063SMichael Walsh        - Calling the calc method to have the totals calculated.
249ac29d063SMichael Walsh
2506c4520c6SMichael Walsh        Description of argument(s):
251410b1787SMichael Walsh        boot_type                   The type of boot test just done (e.g. "REST Power On").
252410b1787SMichael Walsh        boot_status                 The status of the boot just done.  This should be equal to either "pass"
253410b1787SMichael Walsh                                    or "fail" (case-insensitive).
254ac29d063SMichael Walsh        """
255ac29d063SMichael Walsh
256ac29d063SMichael Walsh        self.__boot_results.inc_row_field(boot_type, boot_status.lower())
2578f1ef9eaSMichael Walsh        self.__boot_results.calc()
258ac29d063SMichael Walsh
259*20f38712SPatrick Williams    def sprint_report(self, header_footer="\n"):
260ac29d063SMichael Walsh        r"""
261ac29d063SMichael Walsh        String-print the formatted boot_resuls_table and return them.
262ac29d063SMichael Walsh
2636c4520c6SMichael Walsh        Description of argument(s):
264410b1787SMichael Walsh        header_footer               This indicates whether a header and footer are to be included in the
265410b1787SMichael Walsh                                    report.
266ac29d063SMichael Walsh        """
267ac29d063SMichael Walsh
268ac29d063SMichael Walsh        buffer = ""
269ac29d063SMichael Walsh
270ac29d063SMichael Walsh        buffer += gp.sprint(header_footer)
271ac29d063SMichael Walsh        buffer += self.__boot_results.sprint_report()
272ac29d063SMichael Walsh        buffer += gp.sprint(header_footer)
273ac29d063SMichael Walsh
274ac29d063SMichael Walsh        return buffer
275ac29d063SMichael Walsh
276*20f38712SPatrick Williams    def print_report(self, header_footer="\n", quiet=None):
277ac29d063SMichael Walsh        r"""
278ac29d063SMichael Walsh        Print the formatted boot_resuls_table to the console.
279ac29d063SMichael Walsh
2806c4520c6SMichael Walsh        Description of argument(s):
281ac29d063SMichael Walsh        See sprint_report for details.
282410b1787SMichael Walsh        quiet                       Only print if this value is 0.  This function will search upward in the
283410b1787SMichael Walsh                                    stack to get the default value.
284ac29d063SMichael Walsh        """
285ac29d063SMichael Walsh
286*20f38712SPatrick Williams        quiet = int(gm.dft(quiet, gp.get_stack_var("quiet", 0)))
2876c4520c6SMichael Walsh
288c108e429SMichael Walsh        gp.qprint(self.sprint_report(header_footer))
289ac29d063SMichael Walsh
290ac29d063SMichael Walsh    def sprint_obj(self):
291ac29d063SMichael Walsh        r"""
292410b1787SMichael Walsh        sprint the fields of this object.  This would normally be for debug purposes only.
293ac29d063SMichael Walsh        """
294ac29d063SMichael Walsh
295ac29d063SMichael Walsh        buffer = ""
296ac29d063SMichael Walsh
297ac29d063SMichael Walsh        buffer += "class name: " + self.__class__.__name__ + "\n"
298ac29d063SMichael Walsh        buffer += gp.sprint_var(self.__obj_name)
299ac29d063SMichael Walsh        buffer += self.__boot_results.sprint_obj()
300ac29d063SMichael Walsh        buffer += gp.sprint_var(self.__initial_boot_pass)
301ac29d063SMichael Walsh        buffer += gp.sprint_var(self.__initial_boot_fail)
302ac29d063SMichael Walsh
303ac29d063SMichael Walsh        return buffer
304ac29d063SMichael Walsh
305ac29d063SMichael Walsh    def print_obj(self):
306ac29d063SMichael Walsh        r"""
307410b1787SMichael Walsh        Print the fields of this object to stdout.  This would normally be for debug purposes.
308ac29d063SMichael Walsh        """
309ac29d063SMichael Walsh
310c108e429SMichael Walsh        gp.gp_print(self.sprint_obj())
311ac29d063SMichael Walsh
312b6e3aacdSMichael Walsh
313*20f38712SPatrick Williamsdef create_boot_results_file_path(pgm_name, openbmc_nickname, master_pid):
314b6e3aacdSMichael Walsh    r"""
315b6e3aacdSMichael Walsh    Create a file path to be used to store a boot_results object.
316b6e3aacdSMichael Walsh
317b6e3aacdSMichael Walsh    Description of argument(s):
318410b1787SMichael Walsh    pgm_name                        The name of the program.  This will form part of the resulting file name.
319410b1787SMichael Walsh    openbmc_nickname                The name of the system.  This could be a nickname, a hostname, an IP,
320410b1787SMichael Walsh                                    etc.  This will form part of the resulting file name.
321410b1787SMichael Walsh    master_pid                      The master process id which will form part of the file name.
322b6e3aacdSMichael Walsh    """
323b6e3aacdSMichael Walsh
3248d7b7383SMichael Walsh    USER = os.environ.get("USER", "")
3258d7b7383SMichael Walsh    dir_path = "/tmp/" + USER + "/"
3268d7b7383SMichael Walsh    if not os.path.exists(dir_path):
3278d7b7383SMichael Walsh        os.makedirs(dir_path)
3288d7b7383SMichael Walsh
329b6e3aacdSMichael Walsh    file_name_dict = vf.create_var_dict(pgm_name, openbmc_nickname, master_pid)
330*20f38712SPatrick Williams    return vf.create_file_path(
331*20f38712SPatrick Williams        file_name_dict, dir_path=dir_path, file_suffix=":boot_results"
332*20f38712SPatrick Williams    )
333b6e3aacdSMichael Walsh
334b6e3aacdSMichael Walsh
335b6e3aacdSMichael Walshdef cleanup_boot_results_file():
336b6e3aacdSMichael Walsh    r"""
337410b1787SMichael Walsh    Delete all boot results files whose corresponding pids are no longer active.
338b6e3aacdSMichael Walsh    """
339b6e3aacdSMichael Walsh
340410b1787SMichael Walsh    # Use create_boot_results_file_path to create a globex to find all of the existing boot results files.
341b6e3aacdSMichael Walsh    globex = create_boot_results_file_path("*", "*", "*")
342b6e3aacdSMichael Walsh    file_list = sorted(glob.glob(globex))
343b6e3aacdSMichael Walsh    for file_path in file_list:
344b6e3aacdSMichael Walsh        # Use parse_file_path to extract info from the file path.
345b6e3aacdSMichael Walsh        file_dict = vf.parse_file_path(file_path)
346*20f38712SPatrick Williams        if gm.pid_active(file_dict["master_pid"]):
347b6e3aacdSMichael Walsh            gp.qprint_timen("Preserving " + file_path + ".")
348b6e3aacdSMichael Walsh        else:
349b6e3aacdSMichael Walsh            gc.cmd_fnc("rm -f " + file_path)
3506c4520c6SMichael Walsh
3516c4520c6SMichael Walsh
3526c4520c6SMichael Walshdef update_boot_history(boot_history, boot_start_message, max_boot_history=10):
3536c4520c6SMichael Walsh    r"""
354410b1787SMichael Walsh    Update the boot_history list by appending the boot_start_message and by removing all but the last n
355410b1787SMichael Walsh    entries.
3566c4520c6SMichael Walsh
3576c4520c6SMichael Walsh    Description of argument(s):
3586c4520c6SMichael Walsh    boot_history                    A list of boot start messages.
359410b1787SMichael Walsh    boot_start_message              This is typically a time-stamped line of text announcing the start of a
360410b1787SMichael Walsh                                    boot test.
361410b1787SMichael Walsh    max_boot_history                The max number of entries to be kept in the boot_history list.  The
362410b1787SMichael Walsh                                    oldest entries are deleted to achieve this list size.
3636c4520c6SMichael Walsh    """
3646c4520c6SMichael Walsh
3656c4520c6SMichael Walsh    boot_history.append(boot_start_message)
3666c4520c6SMichael Walsh
3676c4520c6SMichael Walsh    # Trim list to max number of entries.
3686c4520c6SMichael Walsh    del boot_history[: max(0, len(boot_history) - max_boot_history)]
3696c4520c6SMichael Walsh
3706c4520c6SMichael Walsh
3716c4520c6SMichael Walshdef print_boot_history(boot_history, quiet=None):
3726c4520c6SMichael Walsh    r"""
3736c4520c6SMichael Walsh    Print the last ten boots done with their time stamps.
3746c4520c6SMichael Walsh
3756c4520c6SMichael Walsh    Description of argument(s):
376410b1787SMichael Walsh    quiet                           Only print if this value is 0.  This function will search upward in the
377410b1787SMichael Walsh                                    stack to get the default value.
3786c4520c6SMichael Walsh    """
3796c4520c6SMichael Walsh
380*20f38712SPatrick Williams    quiet = int(gm.dft(quiet, gp.get_stack_var("quiet", 0)))
3816c4520c6SMichael Walsh
3826c4520c6SMichael Walsh    # indent 0, 90 chars wide, linefeed, char is "="
3836c4520c6SMichael Walsh    gp.qprint_dashes(0, 90)
3846c4520c6SMichael Walsh    gp.qprintn("Last 10 boots:\n")
3856c4520c6SMichael Walsh
3866c4520c6SMichael Walsh    for boot_entry in boot_history:
3876c4520c6SMichael Walsh        gp.qprint(boot_entry)
3886c4520c6SMichael Walsh    gp.qprint_dashes(0, 90)
389