1#!/usr/bin/env python
2
3r"""
4This module is the python counterpart to openbmc_ffdc.robot..
5"""
6
7import os
8
9import gen_print as gp
10import gen_valid as gv
11import gen_robot_keyword as grk
12import state as st
13
14from robot.libraries.BuiltIn import BuiltIn
15
16
17def ffdc(ffdc_dir_path=None,
18         ffdc_prefix=None,
19         ffdc_function_list=""):
20    r"""
21    Gather First Failure Data Capture (FFDC).
22
23    This includes:
24    - Set global FFDC_TIME.
25    - Create FFDC work space directory.
26    - Write test info details.
27    - Call BMC methods to write/collect FFDC data.
28
29    Description of arguments:
30    ffdc_dir_path       The dir path where FFDC data should be put.
31    ffdc_prefix         The prefix to be given to each FFDC file name
32                        generated.
33    ffdc_function_list  A colon-delimited list of all the types of FFDC data
34                        you wish to have collected.  A blank value means that
35                        all possible kinds of FFDC are to be collected.  See
36                        FFDC_METHOD_CALL object in lib/openbmc_ffdc_list.py
37                        for possible choices.
38    """
39
40    ffdc_file_list = []
41
42    # Check if Ping and SSH connection is alive
43    OPENBMC_HOST = BuiltIn().get_variable_value("${OPENBMC_HOST}")
44
45    state = st.get_state(req_states=['ping', 'uptime', 'rest'])
46    gp.qprint_var(state)
47    if not int(state['ping']):
48        gp.print_error("BMC is not ping-able.  Terminating FFDC collection.\n")
49        return ffdc_file_list
50
51    if not int(state['rest']):
52        gp.print_error("REST commands to the BMC are failing."
53                       + "  Terminating FFDC collection.\n")
54        return ffdc_file_list
55
56    if state['uptime'] == "":
57        gp.print_error("BMC is not communicating via ssh.  Terminating FFDC"
58                       + " collection.\n")
59        return ffdc_file_list
60
61    gp.qprint_timen("Collecting FFDC.")
62
63    # Get default values for arguments.
64    ffdc_dir_path, ffdc_prefix = set_ffdc_defaults(ffdc_dir_path, ffdc_prefix)
65    gp.qprint_var(ffdc_dir_path)
66    gp.qprint_var(ffdc_prefix)
67
68    # LOG_PREFIX is used by subordinate functions.
69    LOG_PREFIX = ffdc_dir_path + ffdc_prefix
70    BuiltIn().set_global_variable("${LOG_PREFIX}", LOG_PREFIX)
71
72    cmd_buf = ["Create Directory", ffdc_dir_path]
73    gp.qprint_issuing(cmd_buf)
74    status, output = BuiltIn().run_keyword_and_ignore_error(*cmd_buf)
75    if status != "PASS":
76        error_message = gp.sprint_error_report("Create Directory failed"
77                                               + " with the following"
78                                               + " error:\n" + output)
79        BuiltIn().fail(error_message)
80
81    # FFDC_FILE_PATH is used by Header Message.
82    FFDC_FILE_PATH = ffdc_dir_path + ffdc_prefix + "BMC_general.txt"
83    BuiltIn().set_global_variable("${FFDC_FILE_PATH}", FFDC_FILE_PATH)
84
85    status, ffdc_file_list = grk.run_key_u("Header Message")
86    status, ffdc_file_sub_list = \
87        grk.run_key_u("Call FFDC Methods  ffdc_function_list="
88                      + ffdc_function_list)
89
90    # Combine lists, remove duplicates and sort.
91    ffdc_file_list = sorted(set(ffdc_file_list + ffdc_file_sub_list))
92
93    gp.qprint_timen("Finished collecting FFDC.")
94
95    return ffdc_file_list
96
97
98def set_ffdc_defaults(ffdc_dir_path=None,
99                      ffdc_prefix=None):
100    r"""
101    Set a default value for ffdc_dir_path and ffdc_prefix if they don't
102    already have values.  Return both values.
103
104    Description of arguments:
105    ffdc_dir_path  The dir path where FFDC data should be put.
106    ffdc_prefix    The prefix to be given to each FFDC file name generated.
107
108    NOTE: If global variable ffdc_dir_path_style is set to ${1}, this function
109    will create default values in a newer way.  Otherwise, its behavior
110    will remain unchanged.
111    """
112
113    # Note: Several subordinate functions like 'Get Test Dir and Name' and
114    # 'Header Message' expect global variable FFDC_TIME to be set.
115    cmd_buf = ["Get Current Time Stamp"]
116    gp.dprint_issuing(cmd_buf)
117    FFDC_TIME = BuiltIn().run_keyword(*cmd_buf)
118    BuiltIn().set_global_variable("${FFDC_TIME}", FFDC_TIME)
119
120    ffdc_dir_path_style = BuiltIn().get_variable_value(
121        "${ffdc_dir_path_style}")
122
123    if ffdc_dir_path is None:
124        if ffdc_dir_path_style:
125            try:
126                ffdc_dir_path = os.environ['FFDC_DIR_PATH']
127            except KeyError:
128                ffdc_dir_path = os.path.dirname(
129                    BuiltIn().get_variable_value("${LOG_FILE}")) + "/"
130        else:
131            FFDC_LOG_PATH = os.getcwd() + "/logs/"
132            if FFDC_LOG_PATH is None:
133                FFDC_LOG_PATH = ""
134            if FFDC_LOG_PATH == "":
135                FFDC_LOG_PATH = os.path.dirname(
136                    BuiltIn().get_variable_value("${LOG_FILE}")) + "/"
137            error_message = gv.valid_value(FFDC_LOG_PATH,
138                                           var_name="FFDC_LOG_PATH")
139            if error_message != "":
140                error_message = gp.sprint_error_report(error_message)
141                BuiltIn().fail(error_message)
142            FFDC_LOG_PATH = os.path.normpath(FFDC_LOG_PATH) + os.sep
143
144            cmd_buf = ["Get Test Dir and Name"]
145            gp.print_issuing(cmd_buf)
146            suitename, testname = BuiltIn().run_keyword(*cmd_buf)
147
148            ffdc_dir_path = FFDC_LOG_PATH + suitename + "/" + testname + "/"
149
150    # Add trailing slash.
151    ffdc_dir_path = os.path.normpath(ffdc_dir_path) + os.sep
152
153    if ffdc_prefix is None:
154        FFDC_TIME = BuiltIn().get_variable_value("${FFDC_TIME}")
155        if ffdc_prefix is None:
156            if ffdc_dir_path_style:
157                OPENBMC_HOST = BuiltIn().get_variable_value("${OPENBMC_HOST}")
158                OPENBMC_NICKNAME = BuiltIn().get_variable_value(
159                    "${OPENBMC_NICKNAME}", default=OPENBMC_HOST)
160                ffdc_prefix = OPENBMC_NICKNAME + "." + FFDC_TIME[2:8] + "." +\
161                    FFDC_TIME[8:14] + "."
162            else:
163                ffdc_prefix = FFDC_TIME + "_"
164
165    BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path)
166    BuiltIn().set_global_variable("${FFDC_PREFIX}", ffdc_prefix)
167
168    return ffdc_dir_path, ffdc_prefix
169