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