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