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