1#!/usr/bin/env python
2
3r"""
4This module is the python counterpart to obmc_boot_test.
5"""
6
7from tally_sheet import *
8import gen_robot_print as grp
9import gen_robot_plug_in as grpi
10import state as st
11
12import os
13import time
14import subprocess
15import glob
16
17from robot.utils import DotDict
18from robot.libraries.BuiltIn import BuiltIn
19from robot.libraries.OperatingSystem import OperatingSystem
20
21# Create boot_results_fields for use in creating boot_results.
22boot_results_fields = DotDict([('total', 0), ('pass', 0), ('fail', 0)])
23# Create boot_results which is global to this module.
24boot_results = tally_sheet('boot type',
25                           boot_results_fields,
26                           'boot_test_results')
27
28boot_results.set_sum_fields(['total', 'pass', 'fail'])
29boot_results.set_calc_fields(['total=pass+fail'])
30
31
32###############################################################################
33def plug_in_setup():
34
35    r"""
36    Initialize all plug-in environment variables for use by the plug-in
37    programs.
38    """
39
40    boot_pass = int(BuiltIn().get_variable_value("${boot_pass}"))
41    if boot_pass > 1:
42        test_really_running = 1
43    else:
44        test_really_running = 0
45
46    BuiltIn().set_global_variable("${test_really_running}",
47                                  test_really_running)
48
49    next_boot = BuiltIn().get_variable_value("${next_boot}")
50    BuiltIn().set_global_variable("${boot_type_desc}", next_boot)
51
52    # Setting master_pid correctly influences the behavior of plug-ins like
53    # DB_Logging
54    program_pid = BuiltIn().get_variable_value("${program_pid}")
55    try:
56        master_pid = OperatingSystem().get_environment_variable(
57            "AUTOBOOT_MASTER_PID")
58    except RuntimeError:
59        master_pid = program_pid
60    if master_pid == "":
61        master_pid = program_pid
62
63    BuiltIn().set_global_variable("${master_pid}", master_pid)
64
65    seconds = time.time()
66    loc_time = time.localtime(seconds)
67    time_string = time.strftime("%y%m%d.%H%M%S.", loc_time)
68
69    openbmc_nickname = BuiltIn().get_variable_value("${openbmc_nickname}")
70    openbmc_host = BuiltIn().get_variable_value("${openbmc_host}")
71    if openbmc_nickname == "":
72        openbmc_nickname = openbmc_host
73    ffdc_prefix = openbmc_nickname
74
75    ffdc_prefix += "." + time_string
76
77    try:
78        ffdc_dir_path = os.environ['FFDC_DIR_PATH']
79        # Add trailing slash.
80        ffdc_dir_path = os.path.normpath(ffdc_dir_path) + os.sep
81    except KeyError:
82        ffdc_dir_path = ""
83    BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
84
85    status_dir_path = os.environ.get('STATUS_DIR_PATH', "")
86    if status_dir_path != "":
87        # Add trailing slash.
88        status_dir_path = os.path.normpath(status_dir_path) + os.sep
89    BuiltIn().set_global_variable("${STATUS_DIR_PATH}", status_dir_path)
90
91    base_tool_dir_path = os.environ.get('AUTOBOOT_BASE_TOOL_DIR_PATH', "/tmp")
92    base_tool_dir_path = os.path.normpath(base_tool_dir_path) + os.sep
93    BuiltIn().set_global_variable("${BASE_TOOL_DIR_PATH}", base_tool_dir_path)
94
95    ffdc_list_file_path = base_tool_dir_path + openbmc_nickname +\
96        "/FFDC_FILE_LIST"
97
98    BuiltIn().set_global_variable("${FFDC_LIST_FILE_PATH}",
99                                  ffdc_list_file_path)
100
101    # For each program parameter, set the corresponding AUTOBOOT_ environment
102    # variable value.  Also, set an AUTOBOOT_ environment variable for every
103    # element in additional_values.
104    additional_values = ["boot_type_desc", "boot_success", "boot_pass",
105                         "boot_fail", "test_really_running", "program_pid",
106                         "master_pid", "ffdc_prefix", "ffdc_dir_path",
107                         "status_dir_path", "base_tool_dir_path",
108                         "ffdc_list_file_path"]
109    BuiltIn().set_global_variable("${ffdc_prefix}", ffdc_prefix)
110
111    parm_list = BuiltIn().get_variable_value("@{parm_list}")
112
113    plug_in_vars = parm_list + additional_values
114
115    for var_name in plug_in_vars:
116        var_value = BuiltIn().get_variable_value("${" + var_name + "}")
117        var_name = var_name.upper()
118        if var_value is None:
119            var_value = ""
120        OperatingSystem().set_environment_variable(
121            "AUTOBOOT_" + var_name, var_value)
122
123    debug = int(BuiltIn().get_variable_value("${debug}"))
124    if debug:
125        cmd_buf = "printenv | egrep AUTOBOOT_ | sort -u"
126        grp.rpissuing(cmd_buf)
127        sub_proc = subprocess.Popen(cmd_buf, shell=True,
128                                    stdout=subprocess.PIPE,
129                                    stderr=subprocess.STDOUT)
130        out_buf, err_buf = sub_proc.communicate()
131        shell_rc = sub_proc.returncode
132        grp.rprint(out_buf)
133
134###############################################################################
135
136
137###############################################################################
138def create_boot_results_table():
139
140    r"""
141    Create our boot_results_table.
142    """
143
144    # At some point we'll want to change to reading in our boot types from
145    # some external source (e.g. file).
146
147    boot_results.add_row('BMC Power On')
148    boot_results.add_row('BMC Power Off')
149
150###############################################################################
151
152
153###############################################################################
154def update_boot_results_table(boot_type,
155                              boot_status):
156
157    r"""
158    Update our boot_results_table.  This includes:
159    - Updating the record for the given boot_type by incrementing the pass or
160      fail field.
161    - Calling the calc method to have the totals, etc. calculated.
162    - Updating global variables boot_pass/boot_fail.
163
164    Description of arguments:
165    boot_type    The type of boot just done (e.g. "BMC Power On").
166    boot_status  The status of the boot just done.  This should be equal to
167                 either "pass" or "fail" (case-insensitive).
168    """
169
170    boot_results.inc_row_field(boot_type, boot_status.lower())
171    totals_line = boot_results.calc()
172
173    # The caller of obmc_boot_test can pass boot_pass/boot_fail values because
174    # the caller may have already done some testing (e.g. "BMC OOB").  For the
175    # sake of DB logging done by plug-ins, we want to include these in our
176    # overall totals.
177    initial_boot_pass = int(BuiltIn().get_variable_value(
178        "${initial_boot_pass}"))
179    initial_boot_fail = int(BuiltIn().get_variable_value(
180        "${initial_boot_fail}"))
181
182    BuiltIn().set_global_variable("${boot_pass}",
183                                  totals_line['pass'] + initial_boot_pass)
184    BuiltIn().set_global_variable("${boot_fail}",
185                                  totals_line['fail'] + initial_boot_fail)
186
187###############################################################################
188
189
190###############################################################################
191def print_boot_results_table(header_footer="\n"):
192
193    r"""
194    Print the formatted boot_resuls_table to the console.
195    """
196
197    grp.rqprint(header_footer)
198    grp.rqprint(boot_results.sprint_report())
199    grp.rqprint(header_footer)
200
201###############################################################################
202
203
204###############################################################################
205def select_boot(state):
206
207    r"""
208    Select a boot test to be run based on our current state and return the
209    chosen boot type.
210
211    Description of arguments:
212    state  The state of the machine, which will include the power state..
213    """
214
215    if 'chassis' in state:
216        # New style state.
217        if state['chassis'] == 'Off':
218            boot = 'BMC Power On'
219        else:
220            boot = 'BMC Power Off'
221    else:
222        # Old style state.
223        if state['power'] == 0:
224            boot = 'BMC Power On'
225        else:
226            boot = 'BMC Power Off'
227
228    return boot
229
230###############################################################################
231
232
233###############################################################################
234def my_ffdc():
235
236    r"""
237    Collect FFDC data.
238    """
239
240    plug_in_setup()
241    rc, shell_rc, failed_plug_in_name = grpi.rprocess_plug_in_packages(
242        call_point='ffdc', stop_on_plug_in_failure=1)
243
244    AUTOBOOT_FFDC_PREFIX = os.environ['AUTOBOOT_FFDC_PREFIX']
245
246    # FFDC_LOG_PATH is used by "FFDC" keyword.
247    FFDC_DIR_PATH = BuiltIn().get_variable_value("${FFDC_DIR_PATH}")
248    BuiltIn().set_global_variable("${FFDC_LOG_PATH}",
249                                  FFDC_DIR_PATH)
250
251    cmd_buf = ["FFDC", "ffdc_prefix=" + AUTOBOOT_FFDC_PREFIX]
252    grp.rpissuing_keyword(cmd_buf)
253    BuiltIn().run_keyword(*cmd_buf)
254
255    state = st.get_state()
256    BuiltIn().set_global_variable("${state}",
257                                  state)
258
259    cmd_buf = ["Print Defect Report"]
260    grp.rpissuing_keyword(cmd_buf)
261    BuiltIn().run_keyword(*cmd_buf)
262
263###############################################################################
264
265
266###############################################################################
267def print_last_boots():
268
269    r"""
270    Print the last ten boots done with their time stamps.
271    """
272
273    # indent 0, 90 chars wide, linefeed, char is "="
274    grp.rqprint_dashes(0, 90)
275    grp.rqprintn("Last 10 boots:\n")
276    last_ten = BuiltIn().get_variable_value("${LAST_TEN}")
277
278    for boot_entry in last_ten:
279        grp.rqprint(boot_entry)
280    grp.rqprint_dashes(0, 90)
281
282###############################################################################
283
284
285###############################################################################
286def print_test_start_message(boot_keyword):
287
288    r"""
289    Print a message indicating what boot test is about to run.
290
291    Description of arguments:
292    boot_keyword  The name of the boot which is to be run
293                  (e.g. "BMC Power On").
294    """
295
296    doing_msg = gp.sprint_timen("Doing \"" + boot_keyword + "\".")
297    grp.rqprint(doing_msg)
298
299    last_ten = BuiltIn().get_variable_value("${LAST_TEN}")
300    last_ten.append(doing_msg)
301
302    if len(last_ten) > 10:
303        del last_ten[0]
304
305###############################################################################
306
307
308###############################################################################
309def print_defect_report():
310
311    r"""
312    Print a defect report.
313    """
314
315    grp.rqprintn()
316    # indent=0, width=90, linefeed=1, char="="
317    grp.rqprint_dashes(0, 90, 1, "=")
318    grp.rqprintn("Copy this data to the defect:\n")
319
320    parm_list = BuiltIn().get_variable_value("${parm_list}")
321
322    grp.rqpvars(*parm_list)
323
324    grp.rqprintn()
325
326    print_last_boots()
327    grp.rqprintn()
328    state = BuiltIn().get_variable_value("${state}")
329    grp.rqpvar(state)
330
331    # At some point I'd like to have the 'Call FFDC Methods' return a list
332    # of files it has collected.  In that case, the following "ls" command
333    # would no longer be needed.  For now, however, glob shows the files
334    # named in FFDC_LIST_FILE_PATH so I will refrain from printing those
335    # out (so we don't see duplicates in the list).
336
337    LOG_PREFIX = BuiltIn().get_variable_value("${LOG_PREFIX}")
338
339    output = '\n'.join(glob.glob(LOG_PREFIX + '*'))
340
341    FFDC_LIST_FILE_PATH = \
342        BuiltIn().get_variable_value("${FFDC_LIST_FILE_PATH}")
343
344    try:
345        ffdc_list = open(FFDC_LIST_FILE_PATH, 'r')
346    except IOError:
347        ffdc_list = ""
348
349    status_file_path = BuiltIn().get_variable_value("${status_file_path}")
350
351    grp.rqprintn()
352    grp.rqprintn("FFDC data files:")
353    if status_file_path != "":
354        grp.rqprintn(status_file_path)
355
356    grp.rqprintn(output)
357    # grp.rqprintn(ffdc_list)
358    grp.rqprintn()
359
360    grp.rqprint_dashes(0, 90, 1, "=")
361
362###############################################################################
363