*** Settings *** Documentation Methods to execute commands on BMC and collect ... data to a list of FFDC files Resource openbmc_ffdc_utils.robot Resource rest_client.robot Resource utils.robot Resource list_utils.robot Library SSHLibrary Library OperatingSystem Library Collections Library String Library gen_print.py Library gen_robot_keyword.py *** Keywords *** # Method : Call FFDC Methods # # Execute the user define keywords from the FFDC List # # Unlike any other keywords this will call into the # # list of keywords defined in the FFDC list at one go # Call FFDC Methods [Documentation] Call into FFDC Keyword index list. [Arguments] ${ffdc_function_list}=${EMPTY} # Description of argument(s): # ffdc_function_list A colon-delimited list naming the kinds of FFDC that # are to be collected # (e.g. "FFDC Generic Report:BMC Specific Files"). # Acceptable values can be found in the description # field of FFDC_METHOD_CALL in # lib/openbmc_ffdc_list.py. Those values can be # obtained via a call to 'Get FFDC Method Desc' (also # from lib/openbmc_ffdc_list.py). @{entries}= Get FFDC Method Index # Example entries: # entries: # entries[0]: BMC LOGS @{ffdc_file_list}= Create List :FOR ${index} IN @{entries} \ ${ffdc_file_sub_list}= Method Call Keyword List ${index} ... ${ffdc_function_list} \ ${ffdc_file_list}= Smart Combine Lists ${ffdc_file_list} ... ${ffdc_file_sub_list} Run Key U SSHLibrary.Close All Connections [Return] ${ffdc_file_list} Method Call Keyword List [Documentation] Process FFDC request and return a list of generated files. [Arguments] ${index} ${ffdc_function_list}=${EMPTY} # Description of argument(s): # index The index into the FFDC_METHOD_CALL dictionary (e.g. # 'BMC LOGS'). # ffdc_function_list See ffdc_function_list description in # "Call FFDC Methods" (above). @{method_list}= Get FFDC Method Call ${index} # Example method_list: # method_list: # method_list[0]: # method_list[0][0]: FFDC Generic Report # method_list[0][1]: BMC FFDC Manifest # method_list[1]: # method_list[1][0]: Get Request FFDC # method_list[1][1]: BMC FFDC Get Requests # (etc.) # If function list is empty assign default (i.e. a list of all allowable # values). In either case, convert ffdc_function_list from a string to # a list. @{ffdc_function_list}= ... Run Keyword If '${ffdc_function_list}' == '${EMPTY}' ... Get FFDC Method Desc ${index} ... ELSE ... Split String ${ffdc_function_list} separator=: @{ffdc_file_list}= Create List :FOR ${method} IN @{method_list} \ ${ffdc_file_sub_list}= Execute Keyword Method ${method[0]} ... ${method[1]} @{ffdc_function_list} \ ${ffdc_file_list}= Smart Combine Lists ${ffdc_file_list} ... ${ffdc_file_sub_list} [Return] ${ffdc_file_list} Execute Keyword Method [Documentation] Call into BMC method keywords. Don't let one ... failure skip the remaining. Get whatever data ... it could gather at worse case scenario. [Arguments] ${description} ${keyword_name} @{ffdc_function_list} # Description of argument(s): # description The description of the FFDC to be collected. This # would be any value returned by # 'Get FFDC Method Desc' (e.g. "FFDC Generic Report"). # keyword_name The name of the keyword to call to collect the FFDC # data (again, see FFDC_METHOD_CALL). # ffdc_function_list See ffdc_function_list description in # "Call FFDC Methods" (above). The only difference is # in this case, it should be a list rather than a # colon-delimited value. @{ffdc_file_list}= Create List ${index}= Get Index From List ${ffdc_function_list} ${description} Run Keyword If '${index}' == '${-1}' Return from Keyword ... ${ffdc_file_list} ${status} ${ffdc_file_list}= Run Key ${keyword_name} ignore=1 [Return] ${ffdc_file_list} # Method : BMC FFDC Manifest # # Execute command on BMC and write to ffdc_report.txt # BMC FFDC Manifest [Documentation] Run the ssh commands from FFDC_BMC_CMD and return a list ... of generated files. @{ffdc_file_list}= Create List ${FFDC_FILE_PATH} @{entries}= Get FFDC Cmd Index :FOR ${index} IN @{entries} \ Iterate BMC Command List Pairs ${index} [Return] ${ffdc_file_list} Iterate BMC Command List Pairs [Documentation] Feed in key pair list from dictionary to execute [Arguments] ${key_index} @{cmd_list}= Get ffdc bmc cmd ${key_index} Set Suite Variable ${ENTRY_INDEX} ${key_index} :FOR ${cmd} IN @{cmd_list} \ Execute Command and Write FFDC ${cmd[0]} ${cmd[1]} Execute Command and Write FFDC [Documentation] Run a command on the BMC or OS, write the output to the ... specified file and return a list of generated files. [Arguments] ${key_index} ${cmd} ${logpath}=${FFDC_FILE_PATH} ... ${target}=BMC Run Keyword If '${logpath}' == '${FFDC_FILE_PATH}' ... Write Cmd Output to FFDC File ${key_index} ${cmd} @{ffdc_file_list}= Create List ${log_path} ${cmd_buf}= Catenate ${target} Execute Command \ ${cmd} \ ignore_err=${1} ${status} ${ret_values}= Run Key ${cmd_buf} ignore=${1} ${stdout}= Set Variable @{ret_values}[0] ${stderr}= Set Variable @{ret_values}[1] # Write stdout on success and stderr/stdout to the file on failure. Run Keyword If $stderr == '${EMPTY}' ... Write Data To File ${stdout}${\n} ${logpath} ... ELSE Write Data To File ... ERROR output:${\n}${stderr}${\n}Output:${\n}${stdout}${\n} ... ${logpath} [Return] ${ffdc_file_list} # Method : BMC FFDC Files # # Execute command on BMC and write to individual file # # based on the file name pre-defined in the list # BMC FFDC Files [Documentation] Run the commands from FFDC_BMC_FILE and return a list of ... generated files. @{entries}= Get FFDC File Index # Example of entries: # entries: # entries[0]: BMC FILES @{ffdc_file_list}= Create List :FOR ${index} IN @{entries} \ ${ffdc_file_sub_list}= Create File and Write Data ${index} \ ${ffdc_file_list}= Smart Combine Lists ${ffdc_file_list} ... ${ffdc_file_sub_list} [Return] ${ffdc_file_list} Create File and Write Data [Documentation] Run commands from FFDC_BMC_FILE to create FFDC files and ... return a list of generated files. [Arguments] ${key_index} # Description of argument(s): # key_index The index into the FFDC_BMC_FILE dictionary. @{ffdc_file_list}= Create List @{cmd_list}= Get FFDC BMC File ${key_index} :FOR ${cmd} IN @{cmd_list} \ ${logpath}= Catenate SEPARATOR= ${LOG_PREFIX} ${cmd[0]}.txt \ ${ffdc_file_sub_list}= Execute Command and Write FFDC ${cmd[0]} ... ${cmd[1]} ${logpath} \ ${ffdc_file_list}= Smart Combine Lists ${ffdc_file_list} ... ${ffdc_file_sub_list} [Return] ${ffdc_file_list} # Method : Log Test Case Status # # Creates test result history footprint for reference # Log Test Case Status [Documentation] Test case execution result history. ... Create once and append to this file ... logs/test_history.txt ... Format Date:Test suite:Test case:Status ... 20160909214053719992:Test Warmreset:Test WarmReset via REST:FAIL ${FFDC_DIR_PATH_STYLE}= Get Variable Value ${FFDC_DIR_PATH_STYLE} ... ${EMPTY} ${FFDC_DIR_PATH}= Get Variable Value ${FFDC_DIR_PATH} ${EMPTY} Run Keyword If '${FFDC_DIR_PATH}' == '${EMPTY}' Set FFDC Defaults Run Keyword If '${FFDC_DIR_PATH_STYLE}' == '${1}' Run Keywords ... Set Global Variable ${FFDC_LOG_PATH} ${FFDC_DIR_PATH} AND ... Set Global Variable ${TEST_HISTORY} ${FFDC_DIR_PATH}test_history.txt Create Directory ${FFDC_LOG_PATH} ${exist}= Run Keyword and Return Status ... OperatingSystem.File Should Exist ${TEST_HISTORY} Run Keyword If '${exist}' == '${False}' ... Create File ${TEST_HISTORY} Rpvars TEST_HISTORY ${cur_time}= Get Current Time Stamp Append To File ${TEST_HISTORY} ... ${cur_time}:${SUITE_NAME}:${TEST_NAME}:${TEST_STATUS}${\n} Log FFDC Get Requests [Documentation] Run the get requests associated with the key and return a ... list of generated files. [Arguments] ${key_index} # Note: Output will be in JSON pretty_print format. # Description of argument(s): # key_index The key to the FFDC_GET_REQUEST dictionary that contains the # get requests that are to be run. @{ffdc_file_list}= Create List @{cmd_list}= Get FFDC Get Request ${key_index} :FOR ${cmd} IN @{cmd_list} \ ${logpath}= Catenate SEPARATOR= ${LOG_PREFIX} ${cmd[0]}.txt \ ${resp}= OpenBMC Get Request ${cmd[1]} quiet=${1} \ ${status}= Run Keyword and Return Status ... Should Be Equal As Strings ${resp.status_code} ${HTTP_OK} \ Run Keyword If '${status}' == '${False}' Continue For Loop \ ${jsondata}= to json ${resp.content} pretty_print=True \ Write Data To File ${\n}${jsondata}${\n} ${logpath} \ Append To List ${ffdc_file_list} ${logpath} [Return] ${ffdc_file_list} BMC FFDC Get Requests [Documentation] Iterate over get request list and return a list of ... generated files. @{ffdc_file_list}= Create List @{entries}= Get ffdc get request index # Example of entries: # entries: # entries[0]: GET REQUESTS :FOR ${index} IN @{entries} \ ${ffdc_file_sub_list}= Log FFDC Get Requests ${index} \ ${ffdc_file_list}= Smart Combine Lists ${ffdc_file_list} ... ${ffdc_file_sub_list} [Return] ${ffdc_file_list} Log OS All distros FFDC [Documentation] Run commands from FFDC_OS_ALL_DISTROS_FILE to create FFDC ... files and return a list of generated files. [Arguments] ${key_index} # Description of argument(s): # key_index The index into the FFDC_OS_ALL_DISTROS_FILE dictionary. @{ffdc_file_list}= Create List @{cmd_list}= Get FFDC OS All Distros Call ${key_index} :FOR ${cmd} IN @{cmd_list} \ ${logpath}= Catenate SEPARATOR= ${LOG_PREFIX} ${cmd[0]}.txt \ ${ffdc_file_sub_list}= Execute Command and Write FFDC ${cmd[0]} ... ${cmd[1]} ${logpath} target=OS \ ${ffdc_file_list}= Smart Combine Lists ${ffdc_file_list} ... ${ffdc_file_sub_list} [Return] ${ffdc_file_list} Log OS SPECIFIC DISTRO FFDC [Documentation] Run commands from the FFDC_OS__FILE to create FFDC ... files and return a list of generated files. [Arguments] ${key_index} ${linux_distro} # Description of argument(s): # key_index The index into the FFDC_OS__FILE dictionary. # linux_distro Your OS's linux distro (e.g. "UBUNTU", "RHEL", etc). @{ffdc_file_list}= Create List @{cmd_list}= Get FFDC OS Distro Call ${key_index} ${linux_distro} :FOR ${cmd} IN @{cmd_list} \ ${logpath}= Catenate SEPARATOR= ${LOG_PREFIX} ${cmd[0]}.txt \ ${ffdc_file_sub_list}= Execute Command and Write FFDC ${cmd[0]} ... ${cmd[1]} ${logpath} target=OS \ ${ffdc_file_list}= Smart Combine Lists ${ffdc_file_list} ... ${ffdc_file_sub_list} [Return] ${ffdc_file_list} OS FFDC Files [Documentation] Run the commands from FFDC_OS_ALL_DISTROS_FILE to create ... FFDC files and return a list of generated files. [Arguments] ${OS_HOST}=${OS_HOST} ${OS_USERNAME}=${OS_USERNAME} ... ${OS_PASSWORD}=${OS_PASSWORD} @{ffdc_file_list}= Create List Run Keyword If '${OS_HOST}' == '${EMPTY}' Run Keywords ... Print Timen No OS Host provided so no OS FFDC will be done. AND ... Return From Keyword ${ffdc_file_list} ${match_state}= Create Dictionary os_ping=^1$ os_login=^1$ ... os_run_cmd=^1$ ${status} ${ret_values}= Run Keyword and Ignore Error Check State ... ${match_state} quiet=0 Run Keyword If '${status}' == 'FAIL' Run Keywords ... Print Error The OS is not communicating so no OS FFDC will be done.\n ... AND ... Return From Keyword ${ffdc_file_list} ${stdout} ${stderr} ${rc}= OS Execute Command ... . /etc/os-release; echo $ID ignore_err=${0} Set Global Variable ${linux_distro} ${stdout} Rpvars linux_distro @{entries}= Get FFDC OS All Distros Index :FOR ${index} IN @{entries} \ ${ffdc_file_sub_list}= Log OS All distros FFDC ${index} \ ${ffdc_file_list}= Smart Combine Lists ${ffdc_file_list} ... ${ffdc_file_sub_list} Return From Keyword If ... '${linux_distro}' == '${EMPTY}' or '${linux_distro}' == 'None' ... ${ffdc_file_list} @{entries}= Get ffdc os distro index ${linux_distro} :FOR ${index} IN @{entries} \ ${ffdc_file_sub_list}= Log OS SPECIFIC DISTRO FFDC ${index} ... ${linux_distro} \ ${ffdc_file_list}= Smart Combine Lists ${ffdc_file_list} ... ${ffdc_file_sub_list} [Return] ${ffdc_file_list} System Inventory Files [Documentation] Copy systest os_inventory files and return a list of ... generated files.. # The os_inventory files are the result of running # systest/htx_hardbootme_test. If these files exist # they are copied to the FFDC directory. # Global variable ffdc_dir_path is the path name of the # directory they are copied to. @{ffdc_file_list}= Create List ${globex}= Set Variable os_inventory_*.json @{file_list}= OperatingSystem.List Files In Directory . ${globex} Copy Files ${globex} ${ffdc_dir_path} : FOR ${file_name} IN @{file_list} \ Append To List ${ffdc_file_list} ${ffdc_dir_path}${file_name} Run Keyword and Ignore Error Remove Files ${globex} [Return] ${ffdc_file_list} SCP Coredump Files [Documentation] Copy core dump files from BMC to local system and return a ... list of generated file names. @{ffdc_file_list}= Create List # Check if core dump exist in the /tmp ${core_files} ${stderr} ${rc}= BMC Execute Command ls /tmp/core_* ... ignore_err=${1} Run Keyword If '${rc}' != '${0}' Return From Keyword ${ffdc_file_list} @{core_list}= Split String ${core_files} # Copy the core files Run Key U Open Connection for SCP :FOR ${index} IN @{core_list} \ ${ffdc_file_path}= Catenate ${LOG_PREFIX}${index.lstrip("/tmp/")} \ ${status}= Run Keyword and Return Status ... scp.Get File ${index} ${ffdc_file_path} \ Run Keyword If '${status}' == '${False}' Continue For Loop \ Append To List ${ffdc_file_list} ${ffdc_file_path} # Remove the file from remote to avoid re-copying on next FFDC call \ BMC Execute Command rm ${index} ignore_err=${1} # I can't find a way to do this: scp.Close Connection [Return] ${ffdc_file_list} Collect eSEL Log [Documentation] Collect eSEL log from logging entry and convert eSEL data ... to elog formatted string text file. [Arguments] ${log_prefix_path}=${LOG_PREFIX} @{ffdc_file_list}= Create List ${resp}= OpenBMC Get Request ${BMC_LOGGING_ENTRY}/enumerate quiet=${1} ${status}= Run Keyword And Return Status ... Should Be Equal As Strings ${resp.status_code} ${HTTP_OK} Return From Keyword If '${status}' == '${False}' ${ffdc_file_list} ${content}= To Json ${resp.content} # Grab the list of entries from logging/entry/ # The data shown below is the result of the "Get Dictionary Keys". # Example: # /xyz/openbmc_project/logging/entry/1 # /xyz/openbmc_project/logging/entry/2 ${esel_list}= Get Dictionary Keys ${content['data']} ${logpath}= Catenate SEPARATOR= ${log_prefix_path} esel Create File ${logpath} # Fetch data from /xyz/openbmc_project/logging/entry/1/attr/AdditionalData # "ESEL=00 00 df 00 00 00 00 20 00 04 12 35 6f aa 00 00 " # Sample eSEL entry: # "/xyz/openbmc_project/logging/entry/1": { # "Timestamp": 1487744317025, # "AdditionalData": [ # "ESEL=00 00 df 00 00 00 00 20 00 04 12 35 6f aa 00 00 " # ], # "Message": "org.open_power.Error.Host.Event.Event", # "Id": 1, # "Severity": "xyz.openbmc_project.Logging.Entry.Level.Emergency" # } :FOR ${entry_path} IN @{esel_list} # Skip reading attribute if entry URI is a callout. # Example: /xyz/openbmc_project/logging/entry/1/callout \ Continue For Loop If '${entry_path.rsplit('/', 1)[1]}' == 'callout' \ ${esel_data}= Read Attribute ${entry_path} AdditionalData quiet=${1} \ ${status}= Run Keyword And Return Status ... Should Contain Match ${esel_data} ESEL* \ Continue For Loop If ${status} == ${False} \ ${index}= Get Esel Index ${esel_data} \ Write Data To File "${esel_data[${index}]}" ${logpath} \ Write Data To File ${\n} ${logpath} ${out}= Run which eSEL.pl ${status}= Run Keyword And Return Status ... Should Contain ${out} eSEL.pl Return From Keyword If '${status}' == '${False}' ${ffdc_file_list} Convert eSEL To Elog Format ${logpath} Append To List ${ffdc_file_list} ${logpath} [Return] ${ffdc_file_list} Convert eSEL To Elog Format [Documentation] Execute parser tool on the eSEL data file to generate ... formatted error log. [Arguments] ${esel_file_path} # Description of arguments: # esel_file_path Absolute path of the eSEL data (e.g. # /tmp/w55.170404.154820.esel). # Note: The only way to get eSEL.pl to put the output in a particular # directory is to cd to that directory. ${cmd_buf}= Catenate cd $(dirname ${esel_file_path}) ; eSEL.pl -l ... ${esel_file_path} -p decode_obmc_data Run ${cmd_buf}