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