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