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    @{cmd_list}=      Get ffdc bmc file   ${key_index}
158    :FOR  ${cmd}  IN  @{cmd_list}
159    \   ${logpath}=  Catenate  SEPARATOR=   ${LOG_PREFIX}   ${cmd[0]}.txt
160    \   Execute Command and Write FFDC  ${cmd[0]}  ${cmd[1]}   ${logpath}
161
162
163
164################################################################
165# Method : Log Test Case Status                                #
166#          Creates test result history footprint for reference #
167################################################################
168
169Log Test Case Status
170    [Documentation]  Test case execution result history.
171    ...  Create once and append to this file
172    ...  logs/test_history.txt
173    ...  Format   Date:Test suite:Test case:Status
174    ...  20160909214053719992:Test Warmreset:Test WarmReset via REST:FAIL
175
176    ${FFDC_DIR_PATH_STYLE}=  Get Variable Value  ${FFDC_DIR_PATH_STYLE}
177    ...  ${EMPTY}
178    ${FFDC_DIR_PATH}=  Get Variable Value  ${FFDC_DIR_PATH}  ${EMPTY}
179
180    Run Keyword If  '${FFDC_DIR_PATH}' == '${EMPTY}'  Set FFDC Defaults
181
182    Run Keyword If  '${FFDC_DIR_PATH_STYLE}' == '${1}'  Run Keywords
183    ...  Set Global Variable  ${FFDC_LOG_PATH}  ${FFDC_DIR_PATH}  AND
184    ...  Set Global Variable  ${TEST_HISTORY}  ${FFDC_DIR_PATH}test_history.txt
185
186    Create Directory   ${FFDC_LOG_PATH}
187
188    ${exist}=   Run Keyword and Return Status
189    ...   OperatingSystem.File Should Exist   ${TEST_HISTORY}
190
191    Run Keyword If  '${exist}' == '${False}'
192    ...   Create File  ${TEST_HISTORY}
193
194    Rpvars  TEST_HISTORY
195
196    ${cur_time}=      Get Current Time Stamp
197
198    Append To File    ${TEST_HISTORY}
199    ...   ${cur_time}:${SUITE_NAME}:${TEST_NAME}:${TEST_STATUS}${\n}
200
201
202Log FFDC Get Requests
203    [Documentation]    Create file in current FFDC log directory.
204    ...                Do openbmc get request and write to
205    ...                corresponding file name.
206    ...                JSON pretty print for logging to file.
207    [Arguments]        ${key_index}
208
209    @{cmd_list}=  Get ffdc get request  ${key_index}
210    :FOR  ${cmd}  IN  @{cmd_list}
211    \   ${logpath}=  Catenate  SEPARATOR=  ${LOG_PREFIX}  ${cmd[0]}.txt
212    \   ${resp}=  OpenBMC Get Request  ${cmd[1]}  quiet=${1}
213    \   ${status}=    Run Keyword and Return Status
214    ...   Should Be Equal As Strings    ${resp.status_code}    ${HTTP_OK}
215    \   Run Keyword If   '${status}' == '${False}'  Continue For Loop
216    \   ${jsondata}=  to json  ${resp.content}    pretty_print=True
217    \   Write Data To File  ${\n}${jsondata}${\n}  ${logpath}
218
219
220BMC FFDC Get Requests
221    [Documentation]    Get the command list and iterate
222    Open Connection And Log In
223    @{entries}=  Get ffdc get request index
224    :FOR  ${index}  IN  @{entries}
225    \   Log FFDC Get Requests   ${index}
226
227
228Log OS ALL DISTROS FFDC
229    [Documentation]    Create file in current FFDC log directory.
230    ...                Executes OS command and write to
231    ...                corresponding file name.
232    [Arguments]        ${key_index}
233
234    @{cmd_list}=  get ffdc os all distros call  ${key_index}
235    :FOR  ${cmd}  IN  @{cmd_list}
236    \   ${logpath}=  Catenate  SEPARATOR=  ${LOG_PREFIX}  ${cmd[0]}.txt
237    \   Execute Command and Write FFDC  ${cmd[0]}  ${cmd[1]}   ${logpath}
238
239
240Log OS SPECIFIC DISTRO FFDC
241    [Documentation]    Create file in current FFDC log directory.
242    ...                Executes OS command and write to
243    ...                corresponding file name.
244    [Arguments]        ${key_index}  ${linux_distro}
245
246    @{cmd_list}=  get ffdc os distro call  ${key_index}  ${linux_distro}
247    :FOR  ${cmd}  IN  @{cmd_list}
248    \   ${logpath}=  Catenate  SEPARATOR=  ${LOG_PREFIX}  ${cmd[0]}.txt
249    \   Execute Command and Write FFDC  ${cmd[0]}  ${cmd[1]}   ${logpath}
250
251
252
253OS FFDC Files
254    [Documentation]    Get the command list and iterate
255    [Arguments]  ${OS_HOST}=${OS_HOST}  ${OS_USERNAME}=${OS_USERNAME}
256    ...   ${OS_PASSWORD}=${OS_PASSWORD}
257
258    Return From Keyword If  '${OS_HOST}' == '${EMPTY}'
259    ...   No OS Host Provided
260
261    # If can't ping, return
262    ${rc}=  Run Keyword and Return Status  Ping Host  ${OS_HOST}
263    Return From Keyword If  '${rc}' == '${False}'
264    ...   Could not ping OS
265
266    Open Connection And Log In  host=${OS_HOST}  username=${OS_USERNAME}
267    ...   password=${OS_PASSWORD}
268
269    ${output}  ${stderr}  ${rc}=  Execute Command  uptime  return_stderr=True
270    ...   return_rc=True
271
272    # If the return code returned by "Execute Command" is non-zero, return
273    Return From Keyword If  '${rc}' != '${0}'
274    ...   Could not connect to OS
275
276    @{entries}=  Get ffdc os all distros index
277    :FOR  ${index}  IN  @{entries}
278    \   Log OS ALL DISTROS FFDC  ${index}
279
280    ${linux_distro}=  Execute Command
281    ...   . /etc/os-release; echo $ID
282    ...   return_stdout=True  return_stderr=False  return_rc=False
283
284    Return From Keyword If
285    ...  '${linux_distro}' == '${EMPTY}' or '${linux_distro}' == 'None'
286    ...  Could not determine Linux Distribution
287
288    @{entries}=  Get ffdc os distro index  ${linux_distro}
289    :FOR  ${index}  IN  @{entries}
290    \   Log OS SPECIFIC DISTRO FFDC  ${index}  ${linux_distro}
291
292
293##############################################################################
294SCP Coredump Files
295    [Documentation]  Copy core dump file from BMC to local system.
296    # Check if core dump exist in the /tmp
297    Open Connection And Log In
298    ${core_files}=  Execute Command  ls /tmp/core_*
299    @{core_list} =  Split String    ${core_files}
300    # Copy the core files
301    Open Connection for SCP
302    :FOR  ${index}  IN  @{core_list}
303    \  scp.Get File  ${index}  ${LOG_PREFIX}${index.lstrip("/tmp/")}
304    # Remove the file from remote to avoid re-copying on next FFDC call
305    \  Execute Command On BMC  rm ${index}
306
307
308##############################################################################
309Collect eSEL Log
310    [Documentation]  Collect eSEL log from logging entry and convert eSEL data
311    ...              to elog formated string text file.
312    ${resp}=  OpenBMC Get Request  ${BMC_LOGGING_ENTRY}/enumerate  quiet=${1}
313    ${status}=  Run Keyword And Return Status
314    ...  Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
315    Return From Keyword If  '${status}' == '${False}'
316
317    ${content}=  To Json  ${resp.content}
318    # Grab the list of entries from logging/entry/
319    # The data shown below is the result of the "Get Dictionary Keys".
320    # Example:
321    # /xyz/openbmc_project/logging/entry/1
322    # /xyz/openbmc_project/logging/entry/2
323    ${esel_list}=  Get Dictionary Keys  ${content['data']}
324
325    ${logpath}=  Catenate  SEPARATOR=  ${LOG_PREFIX}  esel
326    Create File  ${logpath}
327    # Fetch data from /xyz/openbmc_project/logging/entry/1/attr/AdditionalData
328    #  "ESEL=00 00 df 00 00 00 00 20 00 04 12 35 6f aa 00 00 "
329    # Sample eSEL entry:
330    #  "/xyz/openbmc_project/logging/entry/1": {
331    #    "Timestamp": 1487744317025,
332    #    "AdditionalData": [
333    #        "ESEL=00 00 df 00 00 00 00 20 00 04 12 35 6f aa 00 00 "
334    #    ],
335    #    "Message": "org.open_power.Error.Host.Event.Event",
336    #    "Id": 1,
337    #    "Severity": "xyz.openbmc_project.Logging.Entry.Level.Emergency"
338    # }
339
340    :FOR  ${entry_path}  IN  @{esel_list}
341    \  ${esel_data}=  Read Attribute  ${entry_path}  AdditionalData  quiet=${1}
342    \  ${length}=  Get Length  ${esel_data}
343    # Skip writting to file if eSEL AdditionalData is empty
344    \  Continue For Loop If  ${length} == ${0}
345    \  Write Data To File  "${esel_data[0]}"  ${logpath}
346    \  Write Data To File  ${\n}  ${logpath}
347
348    ${out}=  Run  which eSEL.pl
349    ${status}=  Run Keyword And Return Status
350    ...  Should Contain  ${out}  eSEL.pl
351    Return From Keyword If  '${status}' == '${False}'
352
353    Convert eSEL To Elog Format  ${logpath}
354
355
356##############################################################################
357Convert eSEL To Elog Format
358    [Documentation]  Execute parser tool on the eSEL data file to generate
359    ...              formatted error log.
360    [Arguments]  ${esel_file_path}
361    # Desription of arguments:
362    # esel_file_path  Absolute path of the eSEL data (e.g.
363    #                 /tmp/w55.170404.154820.esel).
364
365    # Note: The only way to get eSEL.pl to put the output in a particular
366    # directory is to cd to that directory.
367    ${cmd_buf}=  Catenate  cd $(dirname ${esel_file_path}) ; eSEL.pl -l
368    ...  ${esel_file_path} -p decode_obmc_data
369    Run  ${cmd_buf}
370
371##############################################################################
372