| #!/usr/bin/env python3 | 
 |  | 
 | r""" | 
 | This module is the python counterpart to openbmc_ffdc.robot.. | 
 | """ | 
 |  | 
 | import os | 
 |  | 
 | import gen_print as gp | 
 | import gen_robot_keyword as grk | 
 | import gen_valid as gv | 
 | import state as st | 
 | from robot.libraries.BuiltIn import BuiltIn | 
 |  | 
 | redfish_support_trans_state = int( | 
 |     os.environ.get("REDFISH_SUPPORT_TRANS_STATE", 0) | 
 | ) or int( | 
 |     BuiltIn().get_variable_value("${REDFISH_SUPPORT_TRANS_STATE}", default=0) | 
 | ) | 
 |  | 
 |  | 
 | def ffdc( | 
 |     ffdc_dir_path=None, | 
 |     ffdc_prefix=None, | 
 |     ffdc_function_list="", | 
 |     comm_check=True, | 
 | ): | 
 |     r""" | 
 |     Gather First Failure Data Capture (FFDC). | 
 |  | 
 |     This includes: | 
 |     - Set global FFDC_TIME. | 
 |     - Create FFDC work space directory. | 
 |     - Write test info details. | 
 |     - Call BMC methods to write/collect FFDC data. | 
 |  | 
 |     Description of arguments: | 
 |     ffdc_dir_path                   The dir path where FFDC data should be put. | 
 |     ffdc_prefix                     The prefix to be given to each FFDC file name generated. | 
 |     ffdc_function_list              A colon-delimited list of all the types of FFDC data you wish to have | 
 |                                     collected.  A blank value means that all possible kinds of FFDC are to be | 
 |                                     collected.  See FFDC_METHOD_CALL object in lib/openbmc_ffdc_list.py for | 
 |                                     possible choices. | 
 |     comm_check                      Do a communications check prior to collecting FFDC.  If commincation to | 
 |                                     the BMC can't be established, abort the FFDC collection. | 
 |     """ | 
 |  | 
 |     ffdc_file_list = [] | 
 |  | 
 |     # Check if Ping and SSH connection is alive | 
 |     OPENBMC_HOST = BuiltIn().get_variable_value("${OPENBMC_HOST}") | 
 |  | 
 |     if comm_check: | 
 |         if not redfish_support_trans_state: | 
 |             interface = "rest" | 
 |         else: | 
 |             interface = "redfish" | 
 |  | 
 |         state = st.get_state(req_states=["ping", "uptime", interface]) | 
 |         gp.qprint_var(state) | 
 |         if not int(state["ping"]): | 
 |             gp.print_error( | 
 |                 "BMC is not ping-able.  Terminating FFDC collection.\n" | 
 |             ) | 
 |             return ffdc_file_list | 
 |  | 
 |         if not int(state[interface]): | 
 |             gp.print_error("%s commands to the BMC are failing." % interface) | 
 |  | 
 |         if state["uptime"] == "": | 
 |             gp.print_error("BMC is not communicating via ssh.\n") | 
 |  | 
 |         # If SSH and Redfish connection doesn't works, abort. | 
 |         if not int(state[interface]) and state["uptime"] == "": | 
 |             gp.print_error( | 
 |                 "BMC is not communicating via ssh or Redfish.  Terminating" | 
 |                 " FFDC" | 
 |                 + " collection.\n" | 
 |             ) | 
 |             return ffdc_file_list | 
 |  | 
 |     gp.qprint_timen("Collecting FFDC.") | 
 |  | 
 |     # Get default values for arguments. | 
 |     ffdc_dir_path, ffdc_prefix = set_ffdc_defaults(ffdc_dir_path, ffdc_prefix) | 
 |     gp.qprint_var(ffdc_dir_path) | 
 |     gp.qprint_var(ffdc_prefix) | 
 |  | 
 |     # LOG_PREFIX is used by subordinate functions. | 
 |     LOG_PREFIX = ffdc_dir_path + ffdc_prefix | 
 |     BuiltIn().set_global_variable("${LOG_PREFIX}", LOG_PREFIX) | 
 |  | 
 |     cmd_buf = ["Create Directory", ffdc_dir_path] | 
 |     gp.qprint_issuing(cmd_buf) | 
 |     status, output = BuiltIn().run_keyword_and_ignore_error(*cmd_buf) | 
 |     if status != "PASS": | 
 |         error_message = gp.sprint_error_report( | 
 |             "Create Directory failed" | 
 |             + " with the following" | 
 |             + " error:\n" | 
 |             + output | 
 |         ) | 
 |         BuiltIn().fail(error_message) | 
 |  | 
 |     # FFDC_FILE_PATH is used by Header Message. | 
 |     FFDC_FILE_PATH = ffdc_dir_path + ffdc_prefix + "BMC_general.txt" | 
 |     BuiltIn().set_global_variable("${FFDC_FILE_PATH}", FFDC_FILE_PATH) | 
 |  | 
 |     status, ffdc_file_list = grk.run_key_u("Header Message") | 
 |     status, ffdc_file_sub_list = grk.run_key_u( | 
 |         "Call FFDC Methods  ffdc_function_list=" + ffdc_function_list | 
 |     ) | 
 |  | 
 |     # Combine lists, remove duplicates and sort. | 
 |     ffdc_file_list = sorted(set(ffdc_file_list + ffdc_file_sub_list)) | 
 |  | 
 |     gp.qprint_timen("Finished collecting FFDC.") | 
 |  | 
 |     return ffdc_file_list | 
 |  | 
 |  | 
 | def set_ffdc_defaults(ffdc_dir_path=None, ffdc_prefix=None): | 
 |     r""" | 
 |     Set a default value for ffdc_dir_path and ffdc_prefix if they don't | 
 |     already have values.  Return both values. | 
 |  | 
 |     Description of arguments: | 
 |     ffdc_dir_path  The dir path where FFDC data should be put. | 
 |     ffdc_prefix    The prefix to be given to each FFDC file name generated. | 
 |  | 
 |     NOTE: If global variable ffdc_dir_path_style is set to ${1}, this function | 
 |     will create default values in a newer way.  Otherwise, its behavior | 
 |     will remain unchanged. | 
 |     """ | 
 |  | 
 |     # Note: Several subordinate functions like 'Get Test Dir and Name' and | 
 |     # 'Header Message' expect global variable FFDC_TIME to be set. | 
 |     cmd_buf = ["Get Current Time Stamp"] | 
 |     gp.dprint_issuing(cmd_buf) | 
 |     FFDC_TIME = BuiltIn().run_keyword(*cmd_buf) | 
 |     BuiltIn().set_global_variable("${FFDC_TIME}", FFDC_TIME) | 
 |  | 
 |     ffdc_dir_path_style = BuiltIn().get_variable_value( | 
 |         "${ffdc_dir_path_style}" | 
 |     ) | 
 |  | 
 |     if ffdc_dir_path is None: | 
 |         if ffdc_dir_path_style: | 
 |             try: | 
 |                 ffdc_dir_path = os.environ["FFDC_DIR_PATH"] | 
 |             except KeyError: | 
 |                 ffdc_dir_path = ( | 
 |                     os.path.dirname( | 
 |                         BuiltIn().get_variable_value("${LOG_FILE}") | 
 |                     ) | 
 |                     + "/" | 
 |                 ) | 
 |         else: | 
 |             FFDC_LOG_PATH = os.getcwd() + "/logs/" | 
 |             if FFDC_LOG_PATH is None: | 
 |                 FFDC_LOG_PATH = "" | 
 |             if FFDC_LOG_PATH == "": | 
 |                 FFDC_LOG_PATH = ( | 
 |                     os.path.dirname( | 
 |                         BuiltIn().get_variable_value("${LOG_FILE}") | 
 |                     ) | 
 |                     + "/" | 
 |                 ) | 
 |             error_message = gv.valid_value( | 
 |                 FFDC_LOG_PATH, var_name="FFDC_LOG_PATH" | 
 |             ) | 
 |             if error_message != "": | 
 |                 error_message = gp.sprint_error_report(error_message) | 
 |                 BuiltIn().fail(error_message) | 
 |             FFDC_LOG_PATH = os.path.normpath(FFDC_LOG_PATH) + os.sep | 
 |  | 
 |             cmd_buf = ["Get Test Dir and Name"] | 
 |             gp.print_issuing(cmd_buf) | 
 |             suitename, testname = BuiltIn().run_keyword(*cmd_buf) | 
 |  | 
 |             ffdc_dir_path = FFDC_LOG_PATH + suitename + "/" + testname + "/" | 
 |  | 
 |     # Add trailing slash. | 
 |     ffdc_dir_path = os.path.normpath(ffdc_dir_path) + os.sep | 
 |  | 
 |     if ffdc_prefix is None: | 
 |         FFDC_TIME = BuiltIn().get_variable_value("${FFDC_TIME}") | 
 |         if ffdc_prefix is None: | 
 |             if ffdc_dir_path_style: | 
 |                 OPENBMC_HOST = BuiltIn().get_variable_value("${OPENBMC_HOST}") | 
 |                 OPENBMC_NICKNAME = BuiltIn().get_variable_value( | 
 |                     "${OPENBMC_NICKNAME}", default=OPENBMC_HOST | 
 |                 ) | 
 |                 ffdc_prefix = ( | 
 |                     OPENBMC_NICKNAME | 
 |                     + "." | 
 |                     + FFDC_TIME[2:8] | 
 |                     + "." | 
 |                     + FFDC_TIME[8:14] | 
 |                     + "." | 
 |                 ) | 
 |             else: | 
 |                 ffdc_prefix = FFDC_TIME + "_" | 
 |  | 
 |     BuiltIn().set_global_variable("${FFDC_DIR_PATH}", ffdc_dir_path) | 
 |     BuiltIn().set_global_variable("${FFDC_PREFIX}", ffdc_prefix) | 
 |  | 
 |     return ffdc_dir_path, ffdc_prefix |