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