1*** Settings ***
2Documentation  This module provides general keywords for dump.
3
4Library         bmc_ssh_utils.py
5
6*** Variables ***
7
8*** Keywords ***
9
10Create User Initiated Dump
11    [Documentation]  Generate user initiated dump and return
12    ...  the dump id number (e.g., "5").  Optionally return EMPTY
13    ...  if out of dump space.
14    [Arguments]   ${check_out_of_space}=${False}
15
16    # Description of Argument(s):
17    # check_out_of_space   If ${False}, a dump will be created and
18    #                      its dump_id will be returned.
19    #                      If ${True}, either the dump_id will be
20    #                      returned, or the value ${EMPTY} will be
21    #                      returned if out of dump space was
22    #                      detected when creating the dump.
23
24    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
25    Run Keyword If  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
26    ...  Set Global Variable  ${REST_DUMP_URI}  /xyz/openbmc_project/dump/
27
28    ${data}=  Create Dictionary  data=@{EMPTY}
29    ${resp}=  OpenBMC Post Request
30    ...  ${REST_DUMP_URI}action/CreateDump  data=${data}  quiet=${1}
31
32    Run Keyword If  '${check_out_of_space}' == '${False}'
33    ...      Run Keyword And Return  Get The Dump Id  ${resp}
34    ...  ELSE
35    ...      Run Keyword And Return  Check For Too Many Dumps  ${resp}
36
37
38Get The Dump Id
39    [Documentation]  Wait for the dump to be created. Return the
40    ...  dump id number (e.g., "5").
41    [Arguments]  ${resp}
42
43    # Description of Argument(s):
44    # resp   Response object from action/Create Dump attempt.
45    #        Example object:
46    #        {
47    #           "data": 5,
48    #           "message": "200 OK",
49    #           "status": "ok"
50    #        },
51    #        The "data" field conveys the id number of the created dump.
52
53    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
54    ${json}=  To JSON  ${resp.content}
55
56    Run Keyword If  ${json["data"]} == ${None}
57    ...  Fail  Dump id returned null.
58
59    ${dump_id}=  Set Variable  ${json["data"]}
60
61    Wait Until Keyword Succeeds  3 min  15 sec  Check Dump Existence
62    ...  ${dump_id}
63
64    [Return]  ${dump_id}
65
66
67Check For Too Many Dumps
68    [Documentation]  Return the dump_id number, or return ${EMPTY} if dump
69    ...  creation failed due to too many dumps.
70    [Arguments]  ${resp}
71
72    # Description of Argument(s):
73    # resp   Response object from action/Create Dump attempt.
74    #        Example object if there are too many dumps:
75    #       {
76    #           "data": {
77    #               "description": "xyz.openbmc_project.Dump.Create.Error.QuotaExceeded"
78    #           },
79    #           "message": "Dump not captured due to a cap.",
80    #           "status": "error"
81    #       }
82
83    # If dump was created normally, return the dump_id number.
84    Run Keyword If  '${resp.status_code}' == '${HTTP_OK}'
85    ...  Run Keyword And Return  Get The Dump Id  ${resp}
86
87    ${json}=  To JSON   ${resp.content}
88    ${exception}=  Set Variable  ${json["message"]}
89    ${at_capacity}=  Set Variable  Dump not captured due to a cap
90    ${too_many_dumps}=  Evaluate  $at_capacity in $exception
91    Printn
92    Rprint Vars   exception  too_many_dumps
93    # If there are too many dumps, return ${EMPTY}, otherwise Fail.
94    ${status}=  Run Keyword If  ${too_many_dumps}  Set Variable  ${EMPTY}
95    ...  ELSE  Fail  msg=${exception}.
96
97    [Return]  ${status}
98
99
100Verify No Dump In Progress
101    [Documentation]  Verify no dump in progress.
102
103    ${dump_progress}  ${stderr}  ${rc}=  BMC Execute Command  ls /tmp
104    Should Not Contain  ${dump_progress}  obmcdump
105
106
107Check Dump Existence
108    [Documentation]  Verify if given dump exist.
109    [Arguments]  ${dump_id}
110
111    # Description of Argument(s):
112    # dump_id  An integer value that identifies a particular dump
113    #          object(e.g. 1, 3, 5).
114
115    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
116    Run Keyword If  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
117    ...  Set Global Variable  ${DUMP_ENTRY_URI}  /xyz/openbmc_project/dump/entry/
118
119    ${resp}=  OpenBMC Get Request  ${DUMP_ENTRY_URI}${dump_id}
120    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
121
122
123Delete BMC Dump
124    [Documentation]  Deletes a given bmc dump.
125    [Arguments]  ${dump_id}
126
127    # Description of Argument(s):
128    # dump_id  An integer value that identifies a particular dump (e.g. 1, 3).
129
130    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
131    Run Keyword If  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
132    ...  Set Global Variable  ${DUMP_ENTRY_URI}  /xyz/openbmc_project/dump/entry/
133
134    ${data}=  Create Dictionary  data=@{EMPTY}
135    ${resp}=  OpenBMC Post Request
136    ...  ${DUMP_ENTRY_URI}${dump_id}/action/Delete  data=${data}
137
138    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
139
140Delete All Dumps
141    [Documentation]  Delete all dumps.
142
143    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
144    Run Keyword If  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
145    ...  Set Global Variable  ${DUMP_ENTRY_URI}  /xyz/openbmc_project/dump/entry/
146
147    # Check if dump entries exist, if not return.
148    ${resp}=  OpenBMC Get Request  ${DUMP_ENTRY_URI}list  quiet=${1}
149    Return From Keyword If  ${resp.status_code} == ${HTTP_NOT_FOUND}
150
151    # Get the list of dump entries and delete them all.
152    ${dump_entries}=  Get URL List  ${DUMP_ENTRY_URI}
153    FOR  ${entry}  IN  @{dump_entries}
154        ${dump_id}=  Fetch From Right  ${entry}  /
155        Delete BMC Dump  ${dump_id}
156    END
157
158
159Redfish Delete BMC Dump
160    [Documentation]  Deletes a given BMC dump via Redfish..
161    [Arguments]  ${dump_id}
162
163    # Description of Argument(s):
164    # dump_id  An integer value that identifies a particular dump (e.g. 1, 3).
165
166    Redfish.Delete  /redfish/v1/Managers/bmc/LogServices/Dump/Entries/${dump_id}
167
168
169Redfish Delete All BMC Dumps
170    [Documentation]  Delete all BMC dumps via Redfish.
171
172    # Check if dump entries exist, if not return.
173    ${resp}=  Redfish.Get  /redfish/v1/Managers/bmc/LogServices/Dump/Entries
174    Return From Keyword If  ${resp.dict["Members@odata.count"]} == ${0}
175
176    Redfish.Post  /redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.ClearLog
177
178
179Redfish Delete All System Dumps
180    [Documentation]  Delete all system  dumps via Redfish.
181
182    Redfish.Post  /redfish/v1/Systems/system/LogServices/Dump/Actions/LogService.ClearLog
183
184
185Delete All BMC Dump
186    [Documentation]  Delete all BMC dump entries using "DeleteAll" interface.
187
188    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
189    Run Keyword If  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
190    ...  Set Global Variable  ${REST_DUMP_URI}  /xyz/openbmc_project/dump/
191
192    ${data}=  Create Dictionary  data=@{EMPTY}
193    ${resp}=  Openbmc Post Request  ${REST_DUMP_URI}action/DeleteAll  data=${data}
194    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
195
196Dump Should Not Exist
197    [Documentation]  Verify that BMC dumps do not exist.
198
199    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
200    Run Keyword If  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
201    ...  Set Global Variable  ${DUMP_ENTRY_URI}  /xyz/openbmc_project/dump/entry/
202
203    ${resp}=  OpenBMC Get Request  ${DUMP_ENTRY_URI}list  quiet=${1}
204    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_NOT_FOUND}
205
206Check Existence Of BMC Dump File
207    [Documentation]  Verify existence of BMC dump file.
208    [Arguments]  ${dump_id}
209
210    # Description of argument(s):
211    # dump_id  BMC dump identifier
212
213    ${dump_check_cmd}=  Set Variable
214    ...  ls /var/lib/phosphor-debug-collector/dumps
215
216    # Output of sample BMC Execute command with '2' as dump id is as follows
217    # ls /var/lib/phosphor-debug-collector/dumps/2
218    # obmcdump_2_XXXXXXXXXX.tar.xz
219    ${file_there}  ${stderr}  ${rc}=  BMC Execute Command
220    ...  ${dump_check_cmd}/${dump_id}
221    Should End With  ${file_there}  tar.xz  msg=BMC dump file not found.
222
223Get Dump Entries
224    [Documentation]  Return dump entries list.
225
226    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
227    Run Keyword If  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
228    ...  Set Global Variable  ${DUMP_ENTRY_URI}  /xyz/openbmc_project/dump/entry/
229
230    ${dump_entries}=  Get URL List  ${DUMP_ENTRY_URI}
231    [Return]  ${dump_entries}
232
233Trigger Core Dump
234    [Documentation]  Trigger core dump.
235
236    # Find the pid of the active ipmid and kill it.
237    ${cmd_buf}=  Catenate  kill -s SEGV $(ps | egrep ' ipmid$' |
238    ...  egrep -v grep | \ cut -c1-6)
239
240    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command  ${cmd_buf}
241    Should Be Empty  ${stderr}  msg=BMC execute command error.
242    Should Be Equal As Integers  ${rc}  ${0}
243    ...  msg=BMC execute command return code is not zero.
244
245Initiate BMC Dump Using Redfish And Return Task Id
246     [Documentation]  Initiate BMC dump via Redfish and return its task ID.
247
248     ${payload}=  Create Dictionary  DiagnosticDataType=Manager
249     ${resp}=  Redfish.Post
250     ...  /redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData
251     ...  body=${payload}  valid_status_codes=[${HTTP_ACCEPTED}]
252
253     # Example of response from above Redfish POST request.
254     # "@odata.id": "/redfish/v1/TaskService/Tasks/0",
255     # "@odata.type": "#Task.v1_4_3.Task",
256     # "Id": "0",
257     # "TaskState": "Running",
258     # "TaskStatus": "OK"
259
260     [Return]  ${resp.dict['Id']}
261
262Create User Initiated BMC Dump Via Redfish
263    [Documentation]  Generate user initiated BMC dump via Redfish and return the dump id number (e.g., "5").
264
265    ${payload}=  Create Dictionary  DiagnosticDataType=Manager
266    ${resp}=  Redfish.Post  /redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData
267    ...  body=${payload}  valid_status_codes=[${HTTP_ACCEPTED}]
268
269    # Example of response from above Redfish POST request.
270    # "@odata.id": "/redfish/v1/TaskService/Tasks/0",
271    # "@odata.type": "#Task.v1_4_3.Task",
272    # "Id": "0",
273    # "TaskState": "Running",
274    # "TaskStatus": "OK"
275
276    Wait Until Keyword Succeeds  5 min  15 sec  Check Task Completion  ${resp.dict['Id']}
277    ${task_id}=  Set Variable  ${resp.dict['Id']}
278
279    ${task_dict}=  Redfish.Get Properties  /redfish/v1/TaskService/Tasks/${task_id}
280
281    # Example of HttpHeaders field of task details.
282    # "Payload": {
283    #   "HttpHeaders": [
284    #     "Host: <BMC_IP>",
285    #      "Accept-Encoding: identity",
286    #      "Connection: Keep-Alive",
287    #      "Accept: */*",
288    #      "Content-Length: 33",
289    #      "Location: /redfish/v1/Managers/bmc/LogServices/Dump/Entries/2"]
290    #    ],
291    #    "HttpOperation": "POST",
292    #    "JsonBody": "{\"DiagnosticDataType\":\"Manager\"}",
293    #     "TargetUri": "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData"
294    # }
295
296    [Return]  ${task_dict["Payload"]["HttpHeaders"][-1].split("/")[-1]}
297
298Auto Generate BMC Dump
299    [Documentation]  Auto generate BMC dump.
300
301    ${cmd}=  Catenate  busctl --verbose call xyz.openbmc_project.Dump.Manager
302    ...  /xyz/openbmc_project/dump/bmc xyz.openbmc_project.Dump.Create CreateDump a{sv} 0
303    ${stdout}  ${stderr}  ${rc}=
304    ...  BMC Execute Command  ${cmd}
305    [Return]  ${stdout}  ${stderr}  ${rc}
306
307Get Dump Size
308    [Documentation]  Get dump size.
309    [Arguments]  ${dump_uri}
310
311    # Description of argument(s):
312    # dump_uri        Dump URI
313    #                 (Eg. 	/xyz/openbmc_project/dump/bmc/entry/1).
314
315    # Example of Dump entry.
316    # "data": {
317    #   "CompletedTime": 1616760931,
318    #   "Elapsed": 1616760931,
319    #   "OffloadUri": "",
320    #   "Offloaded": false,
321    #   "Password": "",
322    #   "Size": 3056,
323    #   "SourceDumpId": 117440513,
324    #   "StartTime": 1616760931,
325    #   "Status": "xyz.openbmc_project.Common.Progress.OperationStatus.Completed",
326    #   "VSPString": ""
327    #  },
328
329    Log  ${dump_uri}
330    ${dump_data}=  Redfish.Get Properties  ${dump_uri}
331    [Return]  ${dump_data["data"]["Size"]}
332
333Get Dump ID
334    [Documentation]  Return dump ID.
335    [Arguments]   ${task_id}
336
337    # Description of argument(s):
338    # task_id        Task ID.
339
340    # Example of HttpHeaders field of task details.
341    # "Payload": {
342    #   "HttpHeaders": [
343    #     "Host: <BMC_IP>",
344    #      "Accept-Encoding: identity",
345    #      "Connection: Keep-Alive",
346    #      "Accept: */*",
347    #      "Content-Length: 33",
348    #      "Location: /redfish/v1/Managers/bmc/LogServices/Dump/Entries/2"]
349    #    ],
350    #    "HttpOperation": "POST",
351    #    "JsonBody": "{\"DiagnosticDataType\":\"Manager\"}",
352    #     "TargetUri":
353    # "/redfish/v1/Managers/bmc/LogServices/Dump/Actions/LogService.CollectDiagnosticData"
354    # }
355
356    ${task_dict}=  Redfish.Get Properties  /redfish/v1/TaskService/Tasks/${task_id}
357    ${key}  ${value}=  Set Variable  ${task_dict["Payload"]["HttpHeaders"][-1].split(":")}
358    Run Keyword If  '${key}' != 'Location'  Fail
359    [Return]  ${value.strip('/').split('/')[-1]}
360
361Get Task Status
362    [Documentation]  Return task status.
363    [Arguments]   ${task_id}
364
365    # Description of argument(s):
366    # task_id        Task ID.
367
368    ${resp}=  Redfish.Get Properties  /redfish/v1/TaskService/Tasks/${task_id}
369    [Return]  ${resp['TaskState']}
370
371Check Task Completion
372    [Documentation]  Check if the task is complete.
373    [Arguments]   ${task_id}
374
375    # Description of argument(s):
376    # task_id        Task ID.
377
378    ${task_dict}=  Redfish.Get Properties  /redfish/v1/TaskService/Tasks/${task_id}
379    Should Be Equal As Strings  ${task_dict['TaskState']}  Completed
380
381Get Dump ID And Status
382    [Documentation]  Return dump ID and status.
383    [Arguments]   ${task_id}
384
385    # Description of argument(s):
386    # task_id        Task ID.
387
388    Wait Until Keyword Succeeds  10 min  15 sec  Check Task Completion  ${task_id}
389    ${dump_id}=  Get Dump ID  ${task_id}
390    [Return]  ${dump_id}  Completed
391