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
8Resource           list_utils.robot
9Library            SSHLibrary
10Library            OperatingSystem
11Library            Collections
12Library            String
13Library            gen_print.py
14Library            gen_robot_keyword.py
15Library            dump_utils.py
16
17*** Keywords ***
18
19# Method : Call FFDC Methods                                   #
20#          Execute the user define keywords from the FFDC List #
21#          Unlike any other keywords this will call into the   #
22#          list of keywords defined in the FFDC list at one go #
23
24Call FFDC Methods
25    [Documentation]   Call into FFDC Keyword index list.
26    [Arguments]  ${ffdc_function_list}=${EMPTY}
27
28    # Description of argument(s):
29    # ffdc_function_list  A colon-delimited list naming the kinds of FFDC that
30    #                     are to be collected
31    #                     (e.g. "FFDC Generic Report:BMC Specific Files").
32    #                     Acceptable values can be found in the description
33    #                     field of FFDC_METHOD_CALL in
34    #                     lib/openbmc_ffdc_list.py.  Those values can be
35    #                     obtained via a call to 'Get FFDC Method Desc' (also
36    #                     from lib/openbmc_ffdc_list.py).
37
38    @{entries}=  Get FFDC Method Index
39    # Example entries:
40    # entries:
41    #   entries[0]:  BMC LOGS
42
43    @{ffdc_file_list}=  Create List
44    :FOR  ${index}  IN  @{entries}
45    \    ${ffdc_file_sub_list}=  Method Call Keyword List  ${index}
46    ...      ${ffdc_function_list}
47    \    ${ffdc_file_list}=  Smart Combine Lists  ${ffdc_file_list}
48    ...      ${ffdc_file_sub_list}
49
50    Run Key U  SSHLibrary.Close All Connections
51
52    [Return]  ${ffdc_file_list}
53
54Method Call Keyword List
55    [Documentation]  Process FFDC request and return a list of generated files.
56    [Arguments]  ${index}  ${ffdc_function_list}=${EMPTY}
57
58    # Description of argument(s):
59    # index               The index into the FFDC_METHOD_CALL dictionary (e.g.
60    #                     'BMC LOGS').
61    # ffdc_function_list  See ffdc_function_list description in
62    #                     "Call FFDC Methods" (above).
63
64    @{method_list}=  Get FFDC Method Call  ${index}
65    # Example method_list:
66    # method_list:
67    #   method_list[0]:
68    #     method_list[0][0]: FFDC Generic Report
69    #     method_list[0][1]: BMC FFDC Manifest
70    #   method_list[1]:
71    #     method_list[1][0]: Get Request FFDC
72    #     method_list[1][1]: BMC FFDC Get Requests
73    # (etc.)
74
75    # If function list is empty assign default (i.e. a list of all allowable
76    # values).  In either case, convert ffdc_function_list from a string to
77    # a list.
78    @{ffdc_function_list}=
79    ...  Run Keyword If  '${ffdc_function_list}' == '${EMPTY}'
80    ...    Get FFDC Method Desc  ${index}
81    ...  ELSE
82    ...    Split String  ${ffdc_function_list}  separator=:
83
84    @{ffdc_file_list}=  Create List
85    :FOR  ${method}  IN  @{method_list}
86    \    ${ffdc_file_sub_list}=  Execute Keyword Method  ${method[0]}
87    ...      ${method[1]}  @{ffdc_function_list}
88    \    ${ffdc_file_list}=  Smart Combine Lists  ${ffdc_file_list}
89    ...      ${ffdc_file_sub_list}
90
91    [Return]  ${ffdc_file_list}
92
93
94Execute Keyword Method
95    [Documentation]  Call into BMC method keywords. Don't let one
96    ...              failure skip the remaining. Get whatever data
97    ...              it could gather at worse case scenario.
98    [Arguments]  ${description}  ${keyword_name}  @{ffdc_function_list}
99
100    # Description of argument(s):
101    # description         The description of the FFDC to be collected.  This
102    #                     would be any value returned by
103    #                     'Get FFDC Method Desc' (e.g. "FFDC Generic Report").
104    # keyword_name        The name of the keyword to call to collect the FFDC
105    #                     data (again, see FFDC_METHOD_CALL).
106    # ffdc_function_list  See ffdc_function_list description in
107    #                     "Call FFDC Methods" (above).  The only difference is
108    #                     in this case, it should be a list rather than a
109    #                     colon-delimited value.
110
111    @{ffdc_file_list}=  Create List
112
113    ${index}=  Get Index From List  ${ffdc_function_list}  ${description}
114    Run Keyword If  '${index}' == '${-1}'  Return from Keyword
115    ...  ${ffdc_file_list}
116
117    ${status}  ${ffdc_file_list}=  Run Key  ${keyword_name}  ignore=1
118    [Return]  ${ffdc_file_list}
119
120# Method : BMC FFDC Manifest                                   #
121#          Execute command on BMC and write to ffdc_report.txt #
122
123BMC FFDC Manifest
124    [Documentation]  Run the ssh commands from FFDC_BMC_CMD and return a list
125    ...              of generated files.
126
127    @{ffdc_file_list}=  Create List  ${FFDC_FILE_PATH}
128    @{entries}=  Get FFDC Cmd Index
129    :FOR  ${index}  IN  @{entries}
130    \    Iterate BMC Command List Pairs  ${index}
131
132    [Return]  ${ffdc_file_list}
133
134
135Iterate BMC Command List Pairs
136    [Documentation]    Feed in key pair list from dictionary to execute
137    [Arguments]        ${key_index}
138
139    @{cmd_list}=      Get ffdc bmc cmd    ${key_index}
140    Set Suite Variable   ${ENTRY_INDEX}   ${key_index}
141    :FOR  ${cmd}  IN  @{cmd_list}
142    \    Execute Command and Write FFDC    ${cmd[0]}  ${cmd[1]}
143
144
145Execute Command and Write FFDC
146    [Documentation]  Run a command on the BMC or OS, write the output to the
147    ...              specified file and return a list of generated files.
148    [Arguments]  ${key_index}  ${cmd}  ${logpath}=${FFDC_FILE_PATH}
149    ...          ${target}=BMC
150
151    Run Keyword If  '${logpath}' == '${FFDC_FILE_PATH}'
152    ...    Write Cmd Output to FFDC File  ${key_index}  ${cmd}
153
154    @{ffdc_file_list}=  Create List  ${log_path}
155
156    ${cmd_buf}=  Catenate  ${target} Execute Command \ ${cmd} \ ignore_err=${1}
157    ${status}  ${ret_values}=  Run Key  ${cmd_buf}  ignore=${1}
158
159    ${stdout}=  Set Variable  @{ret_values}[0]
160    ${stderr}=  Set Variable  @{ret_values}[1]
161
162    # Write stdout on success and stderr/stdout to the file on failure.
163    Run Keyword If  $stderr == '${EMPTY}'
164    ...    Write Data To File  ${stdout}${\n}  ${logpath}
165    ...  ELSE  Write Data To File
166    ...    ERROR output:${\n}${stderr}${\n}Output:${\n}${stdout}${\n}
167    ...    ${logpath}
168
169    [Return]  ${ffdc_file_list}
170
171
172# Method : BMC FFDC Files                                      #
173#          Execute command on BMC and write to individual file #
174#          based on the file name pre-defined in the list      #
175
176BMC FFDC Files
177    [Documentation]  Run the commands from FFDC_BMC_FILE and return a list of
178    ...              generated files.
179
180    @{entries}=  Get FFDC File Index
181    # Example of entries:
182    # entries:
183    #   entries[0]: BMC FILES
184
185    @{ffdc_file_list}=  Create List
186    :FOR  ${index}  IN  @{entries}
187    \    ${ffdc_file_sub_list}=  Create File and Write Data  ${index}
188    \     ${ffdc_file_list}=  Smart Combine Lists  ${ffdc_file_list}
189    ...       ${ffdc_file_sub_list}
190
191    [Return]  ${ffdc_file_list}
192
193
194Create File and Write Data
195    [Documentation]  Run commands from FFDC_BMC_FILE to create FFDC files and
196    ...              return a list of generated files.
197    [Arguments]  ${key_index}
198
199    # Description of argument(s):
200    # key_index  The index into the FFDC_BMC_FILE dictionary.
201
202    @{ffdc_file_list}=  Create List
203    @{cmd_list}=  Get FFDC BMC File  ${key_index}
204    :FOR  ${cmd}  IN  @{cmd_list}
205    \    ${logpath}=  Catenate  SEPARATOR=  ${LOG_PREFIX}  ${cmd[0]}.txt
206    \    ${ffdc_file_sub_list}=  Execute Command and Write FFDC  ${cmd[0]}
207    ...      ${cmd[1]}  ${logpath}
208    \     ${ffdc_file_list}=  Smart Combine Lists  ${ffdc_file_list}
209    ...       ${ffdc_file_sub_list}
210
211    [Return]  ${ffdc_file_list}
212
213
214# Method : Log Test Case Status                                #
215#          Creates test result history footprint for reference #
216
217Log Test Case Status
218    [Documentation]  Test case execution result history.
219    ...  Create once and append to this file
220    ...  logs/test_history.txt
221    ...  Format   Date:Test suite:Test case:Status
222    ...  20160909214053719992:Test Warmreset:Test WarmReset via REST:FAIL
223
224    ${FFDC_DIR_PATH_STYLE}=  Get Variable Value  ${FFDC_DIR_PATH_STYLE}
225    ...  ${EMPTY}
226    ${FFDC_DIR_PATH}=  Get Variable Value  ${FFDC_DIR_PATH}  ${EMPTY}
227
228    Run Keyword If  '${FFDC_DIR_PATH}' == '${EMPTY}'  Set FFDC Defaults
229
230    Run Keyword If  '${FFDC_DIR_PATH_STYLE}' == '${1}'  Run Keywords
231    ...  Set Global Variable  ${FFDC_LOG_PATH}  ${FFDC_DIR_PATH}  AND
232    ...  Set Global Variable  ${TEST_HISTORY}  ${FFDC_DIR_PATH}test_history.txt
233
234    Create Directory   ${FFDC_LOG_PATH}
235
236    ${exist}=   Run Keyword and Return Status
237    ...   OperatingSystem.File Should Exist   ${TEST_HISTORY}
238
239    Run Keyword If  '${exist}' == '${False}'
240    ...   Create File  ${TEST_HISTORY}
241
242    Rpvars  TEST_HISTORY
243
244    ${cur_time}=      Get Current Time Stamp
245
246    Append To File    ${TEST_HISTORY}
247    ...   ${cur_time}:${SUITE_NAME}:${TEST_NAME}:${TEST_STATUS}${\n}
248
249
250Log FFDC Get Requests
251    [Documentation]  Run the get requests associated with the key and return a
252    ...              list of generated files.
253    [Arguments]  ${key_index}
254
255    # Note: Output will be in JSON pretty_print format.
256
257    # Description of argument(s):
258    # key_index  The key to the FFDC_GET_REQUEST dictionary that contains the
259    #            get requests that are to be run.
260
261    @{ffdc_file_list}=  Create List
262    @{cmd_list}=  Get FFDC Get Request  ${key_index}
263    :FOR  ${cmd}  IN  @{cmd_list}
264    \    ${logpath}=  Catenate  SEPARATOR=  ${LOG_PREFIX}  ${cmd[0]}.txt
265    \    ${resp}=  OpenBMC Get Request  ${cmd[1]}  quiet=${1}
266    \    ${status}=  Run Keyword and Return Status
267    ...  Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
268    \    Run Keyword If  '${status}' == '${False}'  Continue For Loop
269    \    ${jsondata}=  to json  ${resp.content}  pretty_print=True
270    \    Write Data To File  ${\n}${jsondata}${\n}  ${logpath}
271    \    Append To List  ${ffdc_file_list}  ${logpath}
272
273    [Return]  ${ffdc_file_list}
274
275BMC FFDC Get Requests
276    [Documentation]  Iterate over get request list and return a list of
277    ...              generated files.
278
279    @{ffdc_file_list}=  Create List
280
281    @{entries}=  Get ffdc get request index
282    # Example of entries:
283    # entries:
284    #  entries[0]:  GET REQUESTS
285    :FOR  ${index}  IN  @{entries}
286    \    ${ffdc_file_sub_list}=  Log FFDC Get Requests  ${index}
287    \    ${ffdc_file_list}=  Smart Combine Lists  ${ffdc_file_list}
288    ...  ${ffdc_file_sub_list}
289
290    [Return]  ${ffdc_file_list}
291
292Log OS All distros FFDC
293    [Documentation]  Run commands from FFDC_OS_ALL_DISTROS_FILE to create FFDC
294    ...              files and return a list of generated files.
295    [Arguments]  ${key_index}
296
297    # Description of argument(s):
298    # key_index  The index into the FFDC_OS_ALL_DISTROS_FILE dictionary.
299
300    @{ffdc_file_list}=  Create List
301
302    @{cmd_list}=  Get FFDC OS All Distros Call  ${key_index}
303    :FOR  ${cmd}  IN  @{cmd_list}
304    \    ${logpath}=  Catenate  SEPARATOR=  ${LOG_PREFIX}  ${cmd[0]}.txt
305    \    ${ffdc_file_sub_list}=  Execute Command and Write FFDC  ${cmd[0]}
306    ...      ${cmd[1]}  ${logpath}  target=OS
307    \    ${ffdc_file_list}=  Smart Combine Lists  ${ffdc_file_list}
308    ...      ${ffdc_file_sub_list}
309
310    [Return]  ${ffdc_file_list}
311
312
313Log OS SPECIFIC DISTRO FFDC
314    [Documentation]  Run commands from the FFDC_OS_<distro>_FILE to create FFDC
315    ...              files and return a list of generated files.
316    [Arguments]  ${key_index}  ${linux_distro}
317
318    # Description of argument(s):
319    # key_index  The index into the FFDC_OS_<distro>_FILE dictionary.
320    # linux_distro  Your OS's linux distro (e.g. "UBUNTU", "RHEL", etc).
321
322    @{ffdc_file_list}=  Create List
323
324    @{cmd_list}=  Get FFDC OS Distro Call  ${key_index}  ${linux_distro}
325    :FOR  ${cmd}  IN  @{cmd_list}
326    \    ${logpath}=  Catenate  SEPARATOR=  ${LOG_PREFIX}  ${cmd[0]}.txt
327    \    ${ffdc_file_sub_list}=  Execute Command and Write FFDC  ${cmd[0]}
328    ...      ${cmd[1]}  ${logpath}  target=OS
329    \    ${ffdc_file_list}=  Smart Combine Lists  ${ffdc_file_list}
330    ...      ${ffdc_file_sub_list}
331
332    [Return]  ${ffdc_file_list}
333
334
335OS FFDC Files
336    [Documentation]  Run the commands from FFDC_OS_ALL_DISTROS_FILE to create
337    ...              FFDC files and return a list of generated files.
338    [Arguments]  ${OS_HOST}=${OS_HOST}  ${OS_USERNAME}=${OS_USERNAME}
339    ...  ${OS_PASSWORD}=${OS_PASSWORD}
340
341    @{ffdc_file_list}=  Create List
342
343    Run Keyword If  '${OS_HOST}' == '${EMPTY}'  Run Keywords
344    ...  Print Timen  No OS Host provided so no OS FFDC will be done.  AND
345    ...  Return From Keyword  ${ffdc_file_list}
346
347    ${match_state}=  Create Dictionary  os_ping=^1$  os_login=^1$
348    ...  os_run_cmd=^1$
349    ${status}  ${ret_values}=  Run Keyword and Ignore Error  Check State
350    ...  ${match_state}  quiet=0
351
352    Run Keyword If  '${status}' == 'FAIL'  Run Keywords
353    ...  Print Timen  The OS is not communicating so no OS FFDC will be done.\n
354    ...  AND
355    ...  Return From Keyword  ${ffdc_file_list}
356
357    ${stdout}  ${stderr}  ${rc}=  OS Execute Command
358    ...  . /etc/os-release; echo $ID  ignore_err=${0}
359    Set Global Variable  ${linux_distro}  ${stdout}
360
361    Rpvars  linux_distro
362
363    @{entries}=  Get FFDC OS All Distros Index
364    :FOR  ${index}  IN  @{entries}
365    \    ${ffdc_file_sub_list}=  Log OS All distros FFDC  ${index}
366    \    ${ffdc_file_list}=  Smart Combine Lists  ${ffdc_file_list}
367    ...      ${ffdc_file_sub_list}
368
369    Return From Keyword If
370    ...  '${linux_distro}' == '${EMPTY}' or '${linux_distro}' == 'None'
371    ...  ${ffdc_file_list}
372
373    @{entries}=  Get ffdc os distro index  ${linux_distro}
374    :FOR  ${index}  IN  @{entries}
375    \    ${ffdc_file_sub_list}=  Log OS SPECIFIC DISTRO FFDC  ${index}
376    ...      ${linux_distro}
377    \    ${ffdc_file_list}=  Smart Combine Lists  ${ffdc_file_list}
378    ...      ${ffdc_file_sub_list}
379
380    [Return]  ${ffdc_file_list}
381
382
383System Inventory Files
384    [Documentation]  Copy systest os_inventory files and return a list of
385    ...              generated files..
386    # The os_inventory files are the result of running
387    # systest/htx_hardbootme_test.  If these files exist
388    # they are copied to the FFDC directory.
389    # Global variable ffdc_dir_path is the path name of the
390    # directory they are copied to.
391
392    @{ffdc_file_list}=  Create List
393
394    ${globex}=  Set Variable  os_inventory_*.json
395
396    @{file_list}=  OperatingSystem.List Files In Directory  .  ${globex}
397
398    Copy Files  ${globex}  ${ffdc_dir_path}
399
400    : FOR  ${file_name}  IN  @{file_list}
401    \    Append To List  ${ffdc_file_list}  ${ffdc_dir_path}${file_name}
402
403    Run Keyword and Ignore Error  Remove Files  ${globex}
404
405    [Return]  ${ffdc_file_list}
406
407
408SCP Coredump Files
409    [Documentation]  Copy core dump files from BMC to local system and return a
410    ...              list of generated file names.
411
412    @{ffdc_file_list}=  Create List
413
414    # Check if core dump exist in the /tmp
415    ${core_files}  ${stderr}  ${rc}=  BMC Execute Command  ls /tmp/core_*
416    ...  ignore_err=${1}
417    Run Keyword If  '${rc}' != '${0}'  Return From Keyword  ${ffdc_file_list}
418
419    @{core_list}=  Split String  ${core_files}
420    # Copy the core files
421    Run Key U  Open Connection for SCP
422    :FOR  ${index}  IN  @{core_list}
423    \    ${ffdc_file_path}=  Catenate  ${LOG_PREFIX}${index.lstrip("/tmp/")}
424    \    ${status}=  Run Keyword and Return Status
425    ...  scp.Get File  ${index}  ${ffdc_file_path}
426    \    Run Keyword If  '${status}' == '${False}'  Continue For Loop
427    \    Append To List  ${ffdc_file_list}  ${ffdc_file_path}
428    # Remove the file from remote to avoid re-copying on next FFDC call
429    \    BMC Execute Command  rm ${index}  ignore_err=${1}
430    # I can't find a way to do this: scp.Close Connection
431
432    [Return]  ${ffdc_file_list}
433
434SCP Dump Files
435    [Documentation]  Copy all dump files from BMC to local system.
436
437    # Check if dumps exist
438    ${ffdc_file_list}=  Scp Dumps  ${FFDC_DIR_PATH}  ${FFDC_PREFIX}
439
440    [Return]  ${ffdc_file_list}
441
442Collect Dump Log
443    [Documentation]  Collect dumps from dump entry.
444    [Arguments]  ${log_prefix_path}=${LOG_PREFIX}
445
446    ${data}=  Read Properties  ${DUMP_ENTRY_URI}/enumerate  quiet=${1}
447
448    # Grab the list of entries from dump/entry/
449    # The data shown below is the result of the "Get Dictionary Keys".
450    # Example:
451    # /xyz/openbmc_project/dump/entry/1
452    # /xyz/openbmc_project/dump/entry/2
453
454    ${dump_list}=  Get Dictionary Keys  ${data}
455
456Collect eSEL Log
457    [Documentation]  Collect eSEL log from logging entry and convert eSEL data
458    ...              to elog formatted string text file.
459    [Arguments]  ${log_prefix_path}=${LOG_PREFIX}
460
461    @{ffdc_file_list}=  Create List
462
463    ${resp}=  OpenBMC Get Request  ${BMC_LOGGING_ENTRY}/enumerate  quiet=${1}
464    ${status}=  Run Keyword And Return Status
465    ...  Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
466    Return From Keyword If  '${status}' == '${False}'  ${ffdc_file_list}
467
468    ${content}=  To Json  ${resp.content}
469    # Grab the list of entries from logging/entry/
470    # The data shown below is the result of the "Get Dictionary Keys".
471    # Example:
472    # /xyz/openbmc_project/logging/entry/1
473    # /xyz/openbmc_project/logging/entry/2
474    ${esel_list}=  Get Dictionary Keys  ${content['data']}
475
476    ${logpath}=  Catenate  SEPARATOR=  ${log_prefix_path}  esel
477    Create File  ${logpath}
478    # Fetch data from /xyz/openbmc_project/logging/entry/1/attr/AdditionalData
479    #  "ESEL=00 00 df 00 00 00 00 20 00 04 12 35 6f aa 00 00 "
480    # Sample eSEL entry:
481    #  "/xyz/openbmc_project/logging/entry/1": {
482    #    "Timestamp": 1487744317025,
483    #    "AdditionalData": [
484    #        "ESEL=00 00 df 00 00 00 00 20 00 04 12 35 6f aa 00 00 "
485    #    ],
486    #    "Message": "org.open_power.Error.Host.Event.Event",
487    #    "Id": 1,
488    #    "Severity": "xyz.openbmc_project.Logging.Entry.Level.Emergency"
489    # }
490
491    :FOR  ${entry_path}  IN  @{esel_list}
492    # Skip reading attribute if entry URI is a callout.
493    # Example: /xyz/openbmc_project/logging/entry/1/callout
494    \  Continue For Loop If  '${entry_path.rsplit('/', 1)[1]}' == 'callout'
495    \  ${esel_data}=  Read Attribute  ${entry_path}  AdditionalData  quiet=${1}
496    \  ${status}=  Run Keyword And Return Status
497    ...  Should Contain Match  ${esel_data}  ESEL*
498    \  Continue For Loop If  ${status} == ${False}
499    \  ${index}=  Get Esel Index  ${esel_data}
500    \  Write Data To File  "${esel_data[${index}]}"  ${logpath}
501    \  Write Data To File  ${\n}  ${logpath}
502
503    ${out}=  Run  which eSEL.pl
504    ${status}=  Run Keyword And Return Status
505    ...  Should Contain  ${out}  eSEL.pl
506    Return From Keyword If  '${status}' == '${False}'  ${ffdc_file_list}
507
508    Convert eSEL To Elog Format  ${logpath}
509
510    Append To List  ${ffdc_file_list}  ${logpath}
511    Append To List  ${ffdc_file_list}  ${logpath}.txt
512
513    [Return]  ${ffdc_file_list}
514
515
516Convert eSEL To Elog Format
517    [Documentation]  Execute parser tool on the eSEL data file to generate
518    ...              formatted error log.
519    [Arguments]  ${esel_file_path}
520    # Description of arguments:
521    # esel_file_path  Absolute path of the eSEL data (e.g.
522    #                 /tmp/w55.170404.154820.esel).
523
524    # Note: The only way to get eSEL.pl to put the output in a particular
525    # directory is to cd to that directory.
526    ${cmd_buf}=  Catenate  cd $(dirname ${esel_file_path}) ; eSEL.pl -l
527    ...  ${esel_file_path} -p decode_obmc_data
528    Run  ${cmd_buf}
529
530