1*** Settings ***
2Documentation      Methods to execute commands on BMC and collect
3...                data to a list of FFDC files
4
5Resource           openbmc_ffdc_utils.robot
6Resource           rest_client.robot
7Resource           utils.robot
8Library            SSHLibrary
9Library            OperatingSystem
10Library            Collections
11Library            String
12Library            gen_robot_keyword.py
13
14*** Keywords ***
15
16################################################################
17# Method : Call FFDC Methods                                   #
18#          Execute the user define keywords from the FFDC List #
19#          Unlike any other keywords this will call into the   #
20#          list of keywords defined in the FFDC list at one go #
21################################################################
22
23Call FFDC Methods
24    [Documentation]   Call into FFDC Keyword index list.
25    [Arguments]  ${ffdc_function_list}=${EMPTY}
26
27    # Description of argument(s):
28    # ffdc_function_list  A colon-delimited list naming the kinds of FFDC that
29    #                     is to be collected
30    #                     (e.g. "FFDC Generic Report:BMC Specific Files").
31    #                     Acceptable values can be found in the description
32    #                     field of FFDC_METHOD_CALL in
33    #                     lib/openbmc_ffdc_list.py.  Those values can be
34    #                     obtained via a call to 'Get FFDC Method Desc' (also
35    #                     from lib/openbmc_ffdc_list.py).
36
37    @{entries}=  Get FFDC Method Index
38    :FOR  ${index}  IN  @{entries}
39    \    Method Call Keyword List  ${index}  ${ffdc_function_list}
40    SSHLibrary.Close All Connections
41
42Method Call Keyword List
43    [Documentation]  Iterate the list through keyword index.
44    [Arguments]  ${index}  ${ffdc_function_list}=${EMPTY}
45
46    # Description of argument(s):
47    # index               The index into the FFDC_METHOD_CALL dictionary (e.g.
48    #                     'BMC LOGS').
49    # ffdc_function_list  See ffdc_function_list description in
50    #                     "Call FFDC Methods" (above).
51
52    @{method_list}=  Get ffdc method call  ${index}
53
54    # If function list is empty assign default (i.e. a list of all allowable
55    # values).  In either case, convert ffdc_function_list from a string to
56    # a list.
57    @{ffdc_function_list}=
58    ...  Run Keyword If  '${ffdc_function_list}' == '${EMPTY}'
59    ...    Get FFDC Method Desc  ${index}
60    ...  ELSE
61    ...    Split String  ${ffdc_function_list}  separator=:
62
63    :FOR  ${method}  IN  @{method_list}
64    \    Execute Keyword Method  ${method[0]}  ${method[1]}
65    ...      @{ffdc_function_list}
66
67Execute Keyword Method
68    [Documentation]  Call into BMC method keywords. Don't let one
69    ...              failure skip the remaining. Get whatever data
70    ...              it could gather at worse case scenario.
71    [Arguments]  ${description}  ${keyword_name}  @{ffdc_function_list}
72
73    # Description of argument(s):
74    # description         The description of the FFDC to be collected.  This
75    #                     would be any value returned by
76    #                     'Get FFDC Method Desc' (e.g. "FFDC Generic Report").
77    # keyword_name        The name of the keyword to call to collect the FFDC
78    #                     data (again, see FFDC_METHOD_CALL).
79    # ffdc_function_list  See ffdc_function_list description in
80    #                     "Call FFDC Methods" (above).  The only difference is
81    #                     in this case, it should be a list rather than a
82    #                     colon-delimited value.
83
84    ${status}  ${ret_values}=  Run Keyword And Ignore Error
85    ...  List Should Contain Value  ${ffdc_function_list}  ${description}
86    Run Keyword If  '${status}' != 'PASS'  Return from Keyword
87
88    Run Key  ${keyword_name}  ignore=1
89
90################################################################
91# Method : BMC FFDC Manifest                                   #
92#          Execute command on BMC and write to ffdc_report.txt #
93################################################################
94
95BMC FFDC Manifest
96    [Documentation]    Get the commands index for the FFDC_BMC_CMD,
97    ...                login to BMC and execute commands.
98    Open Connection And Log In
99
100    @{entries}=     Get ffdc cmd index
101    :FOR  ${index}  IN   @{entries}
102    \     Iterate BMC Command List Pairs   ${index}
103
104
105Iterate BMC Command List Pairs
106    [Documentation]    Feed in key pair list from dictionary to execute
107    [Arguments]        ${key_index}
108
109    @{cmd_list}=      Get ffdc bmc cmd    ${key_index}
110    Set Suite Variable   ${ENTRY_INDEX}   ${key_index}
111    :FOR  ${cmd}  IN  @{cmd_list}
112    \    Execute Command and Write FFDC    ${cmd[0]}  ${cmd[1]}
113
114
115Execute Command and Write FFDC
116    [Documentation]    Execute command on BMC or OS and write to ffdc
117    ...                By default to ffdc_report.txt file else to
118    ...                specified file path.
119    [Arguments]        ${key_index}
120    ...                ${cmd}
121    ...                ${logpath}=${FFDC_FILE_PATH}
122
123    Run Keyword If   '${logpath}' == '${FFDC_FILE_PATH}'
124    ...    Write Cmd Output to FFDC File   ${key_index}  ${cmd}
125
126    ${stdout}  ${stderr}=
127    ...   Execute Command    ${cmd}   return_stderr=True
128
129    # Write stdout on success and stderr/stdout to the file on failure.
130    Run Keyword If  $stderr == '${EMPTY}'
131    ...    Write Data To File  ${stdout}${\n}  ${logpath}
132    ...  ELSE  Write Data To File
133    ...    ERROR output:${\n}${stderr}${\n}Output:${\n}${stdout}${\n}
134    ...    ${logpath}
135
136
137################################################################
138# Method : BMC FFDC Files                                      #
139#          Execute command on BMC and write to individual file #
140#          based on the file name pre-defined in the list      #
141################################################################
142
143BMC FFDC Files
144    [Documentation]    Get the command list and iterate
145    Open Connection And Log In
146    @{entries}=     Get ffdc file index
147    :FOR  ${index}  IN   @{entries}
148    \     Create File and Write Data   ${index}
149
150
151Create File and Write Data
152    [Documentation]    Create files to current FFDC log directory,
153    ...                executes command and write to corresponding
154    ...                file name in the current FFDC directory.
155    [Arguments]        ${key_index}
156
157    # To build IP address in searchable form eg: dummy\.domain\.com
158    ${OPENBMC_HOST_REGEX}=  Run  echo ${OPENBMC_HOST} | sed 's/\(\.\)/\\\1/g'
159    @{cmd_list}=      Get ffdc bmc file   ${key_index}
160    :FOR  ${cmd}  IN  @{cmd_list}
161    \   ${logpath}=  Catenate  SEPARATOR=   ${LOG_PREFIX}   ${cmd[0]}.txt
162    \   Execute Command and Write FFDC  ${cmd[0]}  ${cmd[1]}   ${logpath}
163    # Rename OPENBMC_HOST IP address from given file to DUMMYIP
164    \   Run  sed -i 's/'${OPENBMC_HOST_REGEX}'/DUMMYIP/g' ${logpath}
165
166
167
168################################################################
169# Method : Log Test Case Status                                #
170#          Creates test result history footprint for reference #
171################################################################
172
173Log Test Case Status
174    [Documentation]  Test case execution result history.
175    ...  Create once and append to this file
176    ...  logs/test_history.txt
177    ...  Format   Date:Test suite:Test case:Status
178    ...  20160909214053719992:Test Warmreset:Test WarmReset via REST:FAIL
179
180    ${FFDC_DIR_PATH_STYLE}=  Get Variable Value  ${FFDC_DIR_PATH_STYLE}
181    ...  ${EMPTY}
182    ${FFDC_DIR_PATH}=  Get Variable Value  ${FFDC_DIR_PATH}  ${EMPTY}
183
184    Run Keyword If  '${FFDC_DIR_PATH}' == '${EMPTY}'  Set FFDC Defaults
185
186    Run Keyword If  '${FFDC_DIR_PATH_STYLE}' == '${1}'  Run Keywords
187    ...  Set Global Variable  ${FFDC_LOG_PATH}  ${FFDC_DIR_PATH}  AND
188    ...  Set Global Variable  ${TEST_HISTORY}  ${FFDC_DIR_PATH}test_history.txt
189
190    Create Directory   ${FFDC_LOG_PATH}
191
192    ${exist}=   Run Keyword and Return Status
193    ...   OperatingSystem.File Should Exist   ${TEST_HISTORY}
194
195    Run Keyword If  '${exist}' == '${False}'
196    ...   Create File  ${TEST_HISTORY}
197
198    Rpvars  TEST_HISTORY
199
200    ${cur_time}=      Get Current Time Stamp
201
202    Append To File    ${TEST_HISTORY}
203    ...   ${cur_time}:${SUITE_NAME}:${TEST_NAME}:${TEST_STATUS}${\n}
204
205
206Log FFDC Get Requests
207    [Documentation]    Create file in current FFDC log directory.
208    ...                Do openbmc get request and write to
209    ...                corresponding file name.
210    ...                JSON pretty print for logging to file.
211    [Arguments]        ${key_index}
212
213    @{cmd_list}=  Get ffdc get request  ${key_index}
214    :FOR  ${cmd}  IN  @{cmd_list}
215    \   ${logpath}=  Catenate  SEPARATOR=  ${LOG_PREFIX}  ${cmd[0]}.txt
216    \   ${resp}=  OpenBMC Get Request  ${cmd[1]}  quiet=${1}
217    \   ${status}=    Run Keyword and Return Status
218    ...   Should Be Equal As Strings    ${resp.status_code}    ${HTTP_OK}
219    \   Run Keyword If   '${status}' == '${False}'  Continue For Loop
220    \   ${jsondata}=  to json  ${resp.content}    pretty_print=True
221    \   Write Data To File  ${\n}${jsondata}${\n}  ${logpath}
222
223
224BMC FFDC Get Requests
225    [Documentation]    Get the command list and iterate
226    Open Connection And Log In
227    @{entries}=  Get ffdc get request index
228    :FOR  ${index}  IN  @{entries}
229    \   Log FFDC Get Requests   ${index}
230
231
232Log OS ALL DISTROS FFDC
233    [Documentation]    Create file in current FFDC log directory.
234    ...                Executes OS command and write to
235    ...                corresponding file name.
236    [Arguments]        ${key_index}
237
238    @{cmd_list}=  get ffdc os all distros call  ${key_index}
239    :FOR  ${cmd}  IN  @{cmd_list}
240    \   ${logpath}=  Catenate  SEPARATOR=  ${LOG_PREFIX}  ${cmd[0]}.txt
241    \   Execute Command and Write FFDC  ${cmd[0]}  ${cmd[1]}   ${logpath}
242
243
244Log OS SPECIFIC DISTRO FFDC
245    [Documentation]    Create file in current FFDC log directory.
246    ...                Executes OS command and write to
247    ...                corresponding file name.
248    [Arguments]        ${key_index}  ${linux_distro}
249
250    @{cmd_list}=  get ffdc os distro call  ${key_index}  ${linux_distro}
251    :FOR  ${cmd}  IN  @{cmd_list}
252    \   ${logpath}=  Catenate  SEPARATOR=  ${LOG_PREFIX}  ${cmd[0]}.txt
253    \   Execute Command and Write FFDC  ${cmd[0]}  ${cmd[1]}   ${logpath}
254
255
256
257OS FFDC Files
258    [Documentation]    Get the command list and iterate
259    [Arguments]  ${OS_HOST}=${OS_HOST}  ${OS_USERNAME}=${OS_USERNAME}
260    ...   ${OS_PASSWORD}=${OS_PASSWORD}
261
262    Return From Keyword If  '${OS_HOST}' == '${EMPTY}'
263    ...   No OS Host Provided
264
265    # If can't ping, return
266    ${rc}=  Run Keyword and Return Status  Ping Host  ${OS_HOST}
267    Return From Keyword If  '${rc}' == '${False}'
268    ...   Could not ping OS
269
270    Open Connection And Log In  host=${OS_HOST}  username=${OS_USERNAME}
271    ...   password=${OS_PASSWORD}
272
273    ${output}  ${stderr}  ${rc}=  Execute Command  uptime  return_stderr=True
274    ...   return_rc=True
275
276    # If the return code returned by "Execute Command" is non-zero, return
277    Return From Keyword If  '${rc}' != '${0}'
278    ...   Could not connect to OS
279
280    @{entries}=  Get ffdc os all distros index
281    :FOR  ${index}  IN  @{entries}
282    \   Log OS ALL DISTROS FFDC  ${index}
283
284    ${linux_distro}=  Execute Command
285    ...   . /etc/os-release; echo $ID
286    ...   return_stdout=True  return_stderr=False  return_rc=False
287
288    Return From Keyword If
289    ...  '${linux_distro}' == '${EMPTY}' or '${linux_distro}' == 'None'
290    ...  Could not determine Linux Distribution
291
292    @{entries}=  Get ffdc os distro index  ${linux_distro}
293    :FOR  ${index}  IN  @{entries}
294    \   Log OS SPECIFIC DISTRO FFDC  ${index}  ${linux_distro}
295
296
297##############################################################################
298SCP Coredump Files
299    [Documentation]  Copy core dump file from BMC to local system.
300    # Check if core dump exist in the /tmp
301    Open Connection And Log In
302    ${core_files}=  Execute Command  ls /tmp/core_*
303    @{core_list} =  Split String    ${core_files}
304    # Copy the core files
305    Open Connection for SCP
306    :FOR  ${index}  IN  @{core_list}
307    \  scp.Get File  ${index}  ${LOG_PREFIX}${index.lstrip("/tmp/")}
308    # Remove the file from remote to avoid re-copying on next FFDC call
309    \  Execute Command On BMC  rm ${index}
310
311
312##############################################################################
313Collect eSEL Log
314    [Documentation]  Collect eSEL log from logging entry and convert eSEL data
315    ...              to elog formated string text file.
316    ${resp}=  OpenBMC Get Request  ${BMC_LOGGING_ENTRY}/enumerate  quiet=${1}
317    ${status}=  Run Keyword And Return Status
318    ...  Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
319    Return From Keyword If  '${status}' == '${False}'
320
321    ${content}=  To Json  ${resp.content}
322    # Grab the list of entries from logging/entry/
323    # The data shown below is the result of the "Get Dictionary Keys".
324    # Example:
325    # /xyz/openbmc_project/logging/entry/1
326    # /xyz/openbmc_project/logging/entry/2
327    ${esel_list}=  Get Dictionary Keys  ${content['data']}
328
329    ${logpath}=  Catenate  SEPARATOR=  ${LOG_PREFIX}  esel
330    Create File  ${logpath}
331    # Fetch data from /xyz/openbmc_project/logging/entry/1/attr/AdditionalData
332    #  "ESEL=00 00 df 00 00 00 00 20 00 04 12 35 6f aa 00 00 "
333    # Sample eSEL entry:
334    #  "/xyz/openbmc_project/logging/entry/1": {
335    #    "Timestamp": 1487744317025,
336    #    "AdditionalData": [
337    #        "ESEL=00 00 df 00 00 00 00 20 00 04 12 35 6f aa 00 00 "
338    #    ],
339    #    "Message": "org.open_power.Error.Host.Event.Event",
340    #    "Id": 1,
341    #    "Severity": "xyz.openbmc_project.Logging.Entry.Level.Emergency"
342    # }
343
344    :FOR  ${entry_path}  IN  @{esel_list}
345    \  ${esel_data}=  Read Attribute  ${entry_path}  AdditionalData  quiet=${1}
346    \  ${length}=  Get Length  ${esel_data}
347    # Skip writting to file if eSEL AdditionalData is empty
348    \  Continue For Loop If  ${length} == ${0}
349    \  Write Data To File  "${esel_data[0]}"  ${logpath}
350    \  Write Data To File  ${\n}  ${logpath}
351
352    ${out}=  Run  which eSEL.pl
353    ${status}=  Run Keyword And Return Status
354    ...  Should Contain  ${out}  eSEL.pl
355    Return From Keyword If  '${status}' == '${False}'
356
357    Convert eSEL To Elog Format  ${logpath}
358
359
360##############################################################################
361Convert eSEL To Elog Format
362    [Documentation]  Execute parser tool on the eSEL data file to generate
363    ...              formatted error log.
364    [Arguments]  ${esel_file_path}
365    # Desription of arguments:
366    # esel_file_path  Absolute path of the eSEL data (e.g.
367    #                 /tmp/w55.170404.154820.esel).
368
369    # Note: The only way to get eSEL.pl to put the output in a particular
370    # directory is to cd to that directory.
371    ${cmd_buf}=  Catenate  cd $(dirname ${esel_file_path}) ; eSEL.pl -l
372    ...  ${esel_file_path} -p decode_obmc_data
373    Run  ${cmd_buf}
374
375##############################################################################
376