xref: /openbmc/openbmc-test-automation/lib/dump_utils.robot (revision 314a778e6cd45dc80da13bf73a3cb3732f8d5ae5)
1*** Settings ***
2Documentation  This module provides general keywords for dump.
3
4Library         bmc_ssh_utils.py
5Variables       ../data/variables.py
6
7*** Variables ***
8
9*** Keywords ***
10
11Create User Initiated Dump
12    [Documentation]  Generate user initiated dump and return
13    ...  the dump id number (e.g., "5").  Optionally return EMPTY
14    ...  if out of dump space.
15    [Arguments]   ${check_out_of_space}=${False}
16
17    # Description of Argument(s):
18    # check_out_of_space   If ${False}, a dump will be created and
19    #                      its dump_id will be returned.
20    #                      If ${True}, either the dump_id will be
21    #                      returned, or the value ${EMPTY} will be
22    #                      returned if out of dump space was
23    #                      detected when creating the dump.
24
25    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
26    IF  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
27        Set Global Variable  ${REST_DUMP_URI}  /xyz/openbmc_project/dump/
28    END
29
30    ${data}=  Create Dictionary  data=@{EMPTY}
31    ${resp}=  OpenBMC Post Request
32    ...  ${REST_DUMP_URI}action/CreateDump  data=${data}  quiet=${1}
33
34    IF  '${check_out_of_space}' == '${False}'
35        Run Keyword And Return  Get The Dump Id  ${resp}
36    ELSE
37        Run Keyword And Return  Check For Too Many Dumps  ${resp}
38    END
39
40Get The Dump Id
41    [Documentation]  Wait for the dump to be created. Return the
42    ...  dump id number (e.g., "5").
43    [Arguments]  ${resp}
44
45    # Description of Argument(s):
46    # resp   Response object from action/Create Dump attempt.
47    #        Example object:
48    #        {
49    #           "data": 5,
50    #           "message": "200 OK",
51    #           "status": "ok"
52    #        },
53    #        The "data" field conveys the id number of the created dump.
54
55    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
56
57    IF  ${resp.json()["data"]} == ${None}
58        Fail  Dump id returned null.
59    END
60
61    ${dump_id}=  Set Variable  ${json["data"]}
62
63    Wait Until Keyword Succeeds  3 min  15 sec  Check Dump Existence
64    ...  ${dump_id}
65
66    RETURN  ${dump_id}
67
68
69Check For Too Many Dumps
70    [Documentation]  Return the dump_id number, or return ${EMPTY} if dump
71    ...  creation failed due to too many dumps.
72    [Arguments]  ${resp}
73
74    # Description of Argument(s):
75    # resp   Response object from action/Create Dump attempt.
76    #        Example object if there are too many dumps:
77    #       {
78    #           "data": {
79    #               "description": "xyz.openbmc_project.Dump.Create.Error.QuotaExceeded"
80    #           },
81    #           "message": "Dump not captured due to a cap.",
82    #           "status": "error"
83    #       }
84
85    # If dump was created normally, return the dump_id number.
86    IF  '${resp.status_code}' == '${HTTP_OK}'
87        Run Keyword And Return  Get The Dump Id  ${resp}
88    END
89
90    ${exception}=  Set Variable  ${resp.json()["message"]}
91    ${at_capacity}=  Set Variable  Dump not captured due to a cap
92    ${too_many_dumps}=  Evaluate  $at_capacity in $exception
93    Printn
94    Rprint Vars   exception  too_many_dumps
95    # If there are too many dumps, return ${EMPTY}, otherwise Fail.
96    ${status}=  IF  ${too_many_dumps}  Set Variable  ${EMPTY}
97    ...  ELSE  Fail  msg=${exception}.
98
99    RETURN  ${status}
100
101
102Verify No Dump In Progress
103    [Documentation]  Verify no dump in progress.
104
105    ${dump_progress}  ${stderr}  ${rc}=  BMC Execute Command  ls /tmp
106    Should Not Contain  ${dump_progress}  obmcdump
107
108
109Check Dump Existence
110    [Documentation]  Verify if given dump exist.
111    [Arguments]  ${dump_id}
112
113    # Description of Argument(s):
114    # dump_id  An integer value that identifies a particular dump
115    #          object(e.g. 1, 3, 5).
116
117    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
118    IF  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
119        Set Global Variable  ${DUMP_ENTRY_URI}  /xyz/openbmc_project/dump/entry/
120    END
121
122    ${resp}=  OpenBMC Get Request  ${DUMP_ENTRY_URI}${dump_id}
123    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
124
125
126Delete BMC Dump
127    [Documentation]  Deletes a given bmc dump.
128    [Arguments]  ${dump_id}
129
130    # Description of Argument(s):
131    # dump_id  An integer value that identifies a particular dump (e.g. 1, 3).
132
133    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
134    IF  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
135        Set Global Variable  ${DUMP_ENTRY_URI}  /xyz/openbmc_project/dump/entry/
136    END
137
138    ${args}=  Set Variable   {"data": []}
139    ${resp}=  OpenBMC Post Request
140    ...  ${DUMP_ENTRY_URI}${dump_id}/action/Delete  data=${args}
141
142    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
143
144Delete All Dumps
145    [Documentation]  Delete all dumps.
146
147    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
148    IF  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
149        Set Global Variable  ${DUMP_ENTRY_URI}  /xyz/openbmc_project/dump/entry/
150    END
151
152    # Check if dump entries exist, if not return.
153    ${resp}=  OpenBMC Get Request  ${DUMP_ENTRY_URI}list  quiet=${1}
154    Return From Keyword If  ${resp.status_code} == ${HTTP_NOT_FOUND}
155
156    # Get the list of dump entries and delete them all.
157    ${dump_entries}=  Get URL List  ${DUMP_ENTRY_URI}
158    FOR  ${entry}  IN  @{dump_entries}
159        ${dump_id}=  Fetch From Right  ${entry}  /
160        Delete BMC Dump  ${dump_id}
161    END
162
163
164Redfish Delete BMC Dump
165    [Documentation]  Deletes a given BMC dump via Redfish.
166    [Arguments]  ${dump_id}
167
168    # Description of Argument(s):
169    # dump_id  An integer value that identifies a particular dump (e.g. 1, 3).
170
171    Redfish.Delete  /redfish/v1/Managers/${MANAGER_ID}/LogServices/Dump/Entries/${dump_id}
172
173
174Redfish Delete All BMC Dumps
175    [Documentation]  Delete all BMC dumps via Redfish.
176
177    # Check if dump entries exist, if not return.
178    ${resp}=  Redfish.Get  /redfish/v1/Managers/${MANAGER_ID}/LogServices/Dump/Entries
179    Return From Keyword If  ${resp.dict["Members@odata.count"]} == ${0}
180
181    Redfish.Post  /redfish/v1/Managers/${MANAGER_ID}/LogServices/Dump/Actions/LogService.ClearLog
182
183
184Redfish Get All System Dumps
185     [Documentation]  Get the system dump log entries.
186
187     ${resp}=  Redfish.Get  ${REDFISH_SYSTEM_DUMP}
188
189     RETURN  ${resp.dict}
190
191
192Get Redfish BMC Dump Log Entries
193     [Documentation]  Get the BMC dump log entries.
194
195     ${resp}=  Redfish.Get  ${REDFISH_DUMP_URI}
196
197     RETURN  ${resp.dict}
198
199
200Redfish Delete All System Dumps
201    [Documentation]  Delete all system  dumps via Redfish.
202
203    Redfish.Post  /redfish/v1/Systems/${SYSTEM_ID}/LogServices/Dump/Actions/LogService.ClearLog
204
205
206Redfish BMC Dump Should Not Exist
207     [Documentation]  Verify that there is no BMC dump at dump URI.
208
209     # Verify no dump exists.
210     ${dump_entries}=  Get Redfish BMC Dump Log Entries
211     Should Be Equal As Integers  0  ${dump_entries['Members@odata.count']}
212
213
214Redfish BMC Dump Should Exist
215    [Documentation]  Check if BMC dump is generated.
216
217    ${dump_entries}=  Get Redfish BMC Dump Log Entries
218    Should Be True   ${dump_entries['Members@odata.count']} >= 1  msg=No BMC dump generated.
219
220
221Delete All BMC Dump
222    [Documentation]  Delete all BMC dump entries using "DeleteAll" interface.
223
224    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
225    IF  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
226        Set Global Variable  ${REST_DUMP_URI}  /xyz/openbmc_project/dump/
227    END
228
229    ${args}=  Set Variable   {"data": []}
230    ${resp}=  Openbmc Post Request  ${REST_DUMP_URI}action/DeleteAll  data=${args}
231    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
232
233Dump Should Not Exist
234    [Documentation]  Verify that BMC dumps do not exist.
235
236    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
237    IF  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
238        Set Global Variable  ${DUMP_ENTRY_URI}  /xyz/openbmc_project/dump/entry/
239    END
240
241    ${resp}=  OpenBMC Get Request  ${DUMP_ENTRY_URI}list  quiet=${1}
242    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_NOT_FOUND}
243
244Check Existence Of BMC Dump File
245    [Documentation]  Verify existence of BMC dump file.
246    [Arguments]  ${dump_id}
247
248    # Description of argument(s):
249    # dump_id  BMC dump identifier
250
251    ${dump_check_cmd}=  Set Variable
252    ...  ls /var/lib/phosphor-debug-collector/dumps
253
254    # Output of sample BMC Execute command with '2' as dump id is as follows
255    # ls /var/lib/phosphor-debug-collector/dumps/2
256    # obmcdump_2_XXXXXXXXXX.tar.xz
257    ${file_there}  ${stderr}  ${rc}=  BMC Execute Command
258    ...  ${dump_check_cmd}/${dump_id}
259    Should End With  ${file_there}  tar.xz  msg=BMC dump file not found.
260
261Get Dump Entries
262    [Documentation]  Return dump entries list.
263
264    ${resp}=  OpenBMC Get Request  ${REST_DUMP_URI}
265    IF  '${resp.status_code}' == '${HTTP_NOT_FOUND}'
266        Set Global Variable  ${DUMP_ENTRY_URI}  /xyz/openbmc_project/dump/entry/
267    END
268
269    ${dump_entries}=  Get URL List  ${DUMP_ENTRY_URI}
270    RETURN  ${dump_entries}
271
272Trigger Core Dump
273    [Documentation]  Trigger core dump.
274
275    # Find the pid of the active ipmid and kill it.
276    ${cmd_buf}=  Catenate  kill -s SEGV $(ps | egrep ' ipmid$' |
277    ...  egrep -v grep | \ cut -c1-6)
278
279    ${cmd_output}  ${stderr}  ${rc}=  BMC Execute Command  ${cmd_buf}
280    Should Be Empty  ${stderr}  msg=BMC execute command error.
281    Should Be Equal As Integers  ${rc}  ${0}
282    ...  msg=BMC execute command return code is not zero.
283
284Initiate BMC Dump Using Redfish And Return Task Id
285     [Documentation]  Initiate BMC dump via Redfish and return its task ID.
286
287     ${payload}=  Create Dictionary  DiagnosticDataType=Manager
288     ${resp}=  Redfish.Post
289     ...  /redfish/v1/Managers/${MANAGER_ID}/LogServices/Dump/Actions/LogService.CollectDiagnosticData
290     ...  body=${payload}  valid_status_codes=[${HTTP_ACCEPTED}]
291
292     # Example of response from above Redfish POST request.
293     # "@odata.id": "/redfish/v1/TaskService/Tasks/0",
294     # "@odata.type": "#Task.v1_4_3.Task",
295     # "Id": "0",
296     # "TaskState": "Running",
297     # "TaskStatus": "OK"
298
299     RETURN  ${resp.dict['Id']}
300
301Create User Initiated BMC Dump Via Redfish
302    [Documentation]  Generate user initiated BMC dump via Redfish and return the dump id number (e.g., "5").
303    [Arguments]  ${skip_dump_completion}=0
304
305    # Description of Argument(s):
306    # skip_dump_completion          If skip_dump_completion is set to 0, this
307    #                               keyword will waiting for BMC dump to
308    #                               complete and returns the dump id.
309    #                               Otherwise, the keyword is skipped after
310    #                               initiating BMC dump and returns dump task id.
311
312    ${payload}=  Create Dictionary  DiagnosticDataType=Manager
313    ${resp}=  Redfish.Post  /redfish/v1/Managers/${MANAGER_ID}/LogServices/Dump/Actions/LogService.CollectDiagnosticData
314    ...  body=${payload}  valid_status_codes=[${HTTP_ACCEPTED}]
315
316    # Example of response from above Redfish POST request.
317    # "@odata.id": "/redfish/v1/TaskService/Tasks/0",
318    # "@odata.type": "#Task.v1_4_3.Task",
319    # "Id": "0",
320    # "TaskState": "Running",
321    # "TaskStatus": "OK"
322
323    IF  ${skip_dump_completion} != 0  Return From Keyword  ${resp.dict['Id']}
324    Wait Until Keyword Succeeds  5 min  15 sec  Check Task Completion  ${resp.dict['Id']}
325    ${task_id}=  Set Variable  ${resp.dict['Id']}
326
327    ${task_dict}=  Redfish.Get Properties  /redfish/v1/TaskService/Tasks/${task_id}
328
329    # Example of HttpHeaders field of task details.
330    # "Payload": {
331    #   "HttpHeaders": [
332    #     "Host: <BMC_IP>",
333    #      "Accept-Encoding: identity",
334    #      "Connection: Keep-Alive",
335    #      "Accept: */*",
336    #      "Content-Length: 33",
337    #      "Location: /redfish/v1/Managers/${MANAGER_ID}/LogServices/Dump/Entries/2"]
338    #    ],
339    #    "HttpOperation": "POST",
340    #    "JsonBody": "{\"DiagnosticDataType\":\"Manager\"}",
341    #     "TargetUri": "/redfish/v1/Managers/${MANAGER_ID}/LogServices/Dump/Actions/LogService.CollectDiagnosticData"
342    # }
343
344    RETURN  ${task_dict["Payload"]["HttpHeaders"][-1].split("/")[-1]}
345
346Auto Generate BMC Dump
347    [Documentation]  Auto generate BMC dump.
348
349    ${cmd}=  Catenate  busctl --verbose call xyz.openbmc_project.Dump.Manager
350    ...  /xyz/openbmc_project/dump/bmc xyz.openbmc_project.Dump.Create CreateDump a{sv} 0
351    ${stdout}  ${stderr}  ${rc}=
352    ...  BMC Execute Command  ${cmd}
353    RETURN  ${stdout}  ${stderr}  ${rc}
354
355Get Dump Size
356    [Documentation]  Get dump size.
357    [Arguments]  ${dump_uri}
358
359    # Description of argument(s):
360    # dump_uri        Dump URI
361    #                 (Eg. 	/xyz/openbmc_project/dump/bmc/entry/1).
362
363    # Example of Dump entry.
364    # "data": {
365    #   "CompletedTime": 1616760931,
366    #   "Elapsed": 1616760931,
367    #   "OffloadUri": "",
368    #   "Offloaded": false,
369    #   "Password": "",
370    #   "Size": 3056,
371    #   "SourceDumpId": 117440513,
372    #   "StartTime": 1616760931,
373    #   "Status": "xyz.openbmc_project.Common.Progress.OperationStatus.Completed",
374    #   "VSPString": ""
375    #  },
376
377    Log  ${dump_uri}
378    ${dump_data}=  Redfish.Get Properties  ${dump_uri}
379    RETURN  ${dump_data["data"]["Size"]}
380
381Get Dump ID
382    [Documentation]  Return dump ID.
383    [Arguments]   ${task_id}
384
385    # Description of argument(s):
386    # task_id        Task ID.
387
388    # Example of HttpHeaders field of task details.
389    # "Payload": {
390    #   "HttpHeaders": [
391    #     "Host: <BMC_IP>",
392    #      "Accept-Encoding: identity",
393    #      "Connection: Keep-Alive",
394    #      "Accept: */*",
395    #      "Content-Length: 33",
396    #      "Location: /redfish/v1/Managers/${MANAGER_ID}/LogServices/Dump/Entries/2"]
397    #    ],
398    #    "HttpOperation": "POST",
399    #    "JsonBody": "{\"DiagnosticDataType\":\"Manager\"}",
400    #     "TargetUri":
401    # "/redfish/v1/Managers/${MANAGER_ID}/LogServices/Dump/Actions/LogService.CollectDiagnosticData"
402    # }
403
404    ${task_dict}=  Redfish.Get Properties  /redfish/v1/TaskService/Tasks/${task_id}
405    ${key}  ${value}=  Set Variable  ${task_dict["Payload"]["HttpHeaders"][-1].split(":")}
406    IF  '${key}' != 'Location'  Fail
407    RETURN  ${value.strip('/').split('/')[-1]}
408
409Get Task Status
410    [Documentation]  Return task status.
411    [Arguments]   ${task_id}
412
413    # Description of argument(s):
414    # task_id        Task ID.
415
416    ${resp}=  Redfish.Get Properties  /redfish/v1/TaskService/Tasks/${task_id}
417    RETURN  ${resp['TaskState']}
418
419Check Task Completion
420    [Documentation]  Check if the task is complete.
421    [Arguments]   ${task_id}
422
423    # Description of argument(s):
424    # task_id        Task ID.
425
426    ${task_dict}=  Redfish.Get Properties  /redfish/v1/TaskService/Tasks/${task_id}
427    Should Be Equal As Strings  ${task_dict['TaskState']}  Completed
428
429Get Dump ID And Status
430    [Documentation]  Return dump ID and status.
431    [Arguments]   ${task_id}
432
433    # Description of argument(s):
434    # task_id        Task ID.
435
436    Wait Until Keyword Succeeds  10 min  15 sec  Check Task Completion  ${task_id}
437    ${dump_id}=  Get Dump ID  ${task_id}
438    RETURN  ${dump_id}  Completed
439
440
441Create BMC User Dump
442    [Documentation]  Generate user initiated BMC dump via Redfish and return
443    ...  the task instance Id and response object (e.g., "5").
444
445    ${payload}=  Create Dictionary  DiagnosticDataType=Manager
446    ${resp}=  Redfish.Post  /redfish/v1/Managers/${MANAGER_ID}/LogServices/Dump/Actions/LogService.CollectDiagnosticData
447    ...  body=${payload}  valid_status_codes=[${HTTP_ACCEPTED}]
448
449    ${ip_resp}=  Evaluate  json.loads(r'''${resp.text}''')  json
450
451    Return From Keyword  ${ip_resp["Id"]}  ${resp}
452
453
454Wait For Task Completion
455    [Documentation]  Check whether the state of task instance matches any of the
456    ...  expected completion states before maximum number of retries exceeds and
457    ...  exit loop in case completion state is met.
458    [Arguments]  ${task_id}  ${expected_status}  ${retry_max_count}=300
459    ...  ${check_state}=${FALSE}
460
461    # Description of argument(s):
462    # task_id                     the task id for which completion is
463    #                             to be monitored.
464    # expected_status             the task state which is to be considered as the
465    #                             end of task life cycle.
466    # retry_max_count             the maximum number of retry count to wait for
467    #                             task to reach its completion state. Default
468    #                             value of retry_max_count is 300.
469    # check_state                 if set as TRUE, the task state will be
470    #                             monitored whether the task state value is
471    #                             valid throughout task life cycle until
472    #                             expected completion state is reached.
473    #                             Default value of check_state is FALSE.
474
475    FOR  ${retry}  IN RANGE  ${retry_max_count}
476        ${resp}=  Redfish.Get Properties  /redfish/v1/TaskService/Tasks/${task_id}
477        ${current_task_state}=  Set Variable  ${resp["TaskState"]}
478        Rprint Vars  current_task_state
479
480        IF  ${check_state} == ${TRUE}
481	    Should Be True  '${resp["TaskState"]}' in ${allowed_task_state}
482        ...  msg=Verify task state is valid
483        END
484        Exit For Loop If
485        ...  '${resp["TaskState"]}' in ${expected_status}
486
487        Sleep  5s
488    END
489
490Get Dump Status In BMC
491    [Documentation]  Get dump status from BMC using busctl method.
492    [Arguments]  ${dump_uri}
493
494    # Description of argument(s):
495    # dump_uri   Dump URI E.g: /xyz/openbmc_project/dump/bmc/entry/7.
496
497    ${cmd}=  Catenate  busctl get-property xyz.openbmc_project.Dump.Manager
498    ...  ${dump_uri} xyz.openbmc_project.Common.Progress Status
499
500    ${stdout}  ${stderr}  ${rc}=  BMC Execute Command  ${cmd}
501    Log  ${stdout}
502    # Example output:
503    # s "xyz.openbmc_project.Common.Progress.OperationStatus.Completed".
504
505    ${status}=  Set Variable  ${stdout.split('.')[-1].strip('"')}
506    RETURN  ${status}
507
508Verify Dump Status In BMC
509    [Documentation]  Verify Dump Status in BMC.
510    [Arguments]  ${dump_uri}  ${expected_dump_status}
511
512    # Description of argument(s):
513    # dump_uri              Dump URI E.g: /xyz/openbmc_project/dump/bmc/entry/7.
514    # expected_dump_status  Expected Dump Status (Completed or Failed etc).
515
516    ${dump_status}=  Get Dump Status In BMC  ${dump_uri}
517    Should Be Equal  ${dump_status}  ${expected_dump_status}
518