1*** Settings ***
2Documentation   Redfish BMC and PNOR software utilities keywords.
3
4Library         code_update_utils.py
5Library         gen_robot_valid.py
6Library         tftp_update_utils.py
7Resource        bmc_redfish_utils.robot
8Resource        boot_utils.robot
9
10*** Keywords ***
11
12Get Software Functional State
13    [Documentation]  Return functional or active state of the software (i.e. True/False).
14    [Arguments]  ${image_id}
15
16    # Description of argument(s):
17    # image_id   The image ID (e.g. "acc9e073").
18
19    ${resp}=  Redfish.Get  /redfish/v1/UpdateService/FirmwareInventory/${image_id}
20    ...  valid_status_codes=[${HTTP_OK}, ${HTTP_INTERNAL_SERVER_ERROR}]
21    ${image_info}  Set Variable  ${resp.dict}
22
23    ${sw_functional}=  Run Keyword If
24    ...   '${image_info["Description"]}' == 'BMC image' or '${image_info["Description"]}' == 'BMC update'
25    ...    Redfish.Get Attribute  /redfish/v1/Managers/${MANAGER_ID}  FirmwareVersion
26    ...  ELSE
27    ...    Redfish.Get Attribute  /redfish/v1/Systems/${SYSTEM_ID}  BiosVersion
28
29    ${functional}=  Run Keyword And Return Status
30    ...   Should Be Equal  ${sw_functional}  ${image_info["Version"]}
31
32    # If they are not same, return from here.
33    Return From Keyword If  '${functional}' == 'False'  ${functional}
34
35    # WHen the functional and backup firmware versions are same, this ensure, we rightly set the
36    # test inventory dictionary for the firmware functional status.
37    Run Keyword If
38    ...   '${image_info["Description"]}' == 'BMC image' or '${image_info["Description"]}' == 'BMC update'
39    ...   Run Keyword And Return  Find Active Software Image  ${image_id}
40
41    RETURN  ${functional}
42
43
44Find Active Software Image
45    [Documentation]  Match the firmware id of ActiveSoftwareImage attribute with the input id.
46    ...              The ActiveSoftwareImage id is the current functional BMC firmware.
47    [Arguments]  ${image_id}
48
49    # Description of argument(s):
50    # image_id   The image ID (e.g. "acc9e073").
51
52    # This attribute tells which is the firmware version currently functional.
53    # "ActiveSoftwareImage": {
54    #         "@odata.id": "/redfish/v1/UpdateService/FirmwareInventory/5ca9fec0"
55    #     },
56    ${active_sw_img}=  Redfish.Get Attribute  /redfish/v1/Managers/${MANAGER_ID}  Links
57
58    ${active_id}=  Set Variable  ${active_sw_img["ActiveSoftwareImage"]["@odata.id"].split("/")[-1]}
59
60    ${matched_functional}=  Run Keyword And Return Status
61    ...  Should Be Equal As Strings  ${image_id}  ${active_id}
62
63    # Returns True if matched else False.
64    RETURN  ${matched_functional}
65
66
67Get Software Inventory State
68    [Documentation]  Return dictionary of the image type, version and functional state
69    ...  of the software objects active on the system.
70
71    # User defined state for software objects.
72    # Note: "Functional" term refers to firmware which system is currently booted with.
73    # sw_inv_dict:
74    #   [ace821ef]:
75    #     [image_type]:                 Host update
76    #     [image_id]:                   ace821ef
77    #     [functional]:                 True
78    #     [version]:                    witherspoon-xx.xx.xx.xx
79    #   [b9101858]:
80    #     [image_type]:                 BMC update
81    #     [image_id]:                   b9101858
82    #     [functional]:                 True
83    #     [version]:                    2.8.0-dev-150-g04508dc9f
84    #   [c45eafa5]:
85    #     [image_type]:                 BMC update
86    #     [image_id]:                   c45eafa5
87    #     [functional]:                 False
88    #     [version]:                    2.8.0-dev-149-g1a8df5077
89
90    ${sw_member_list}=  Redfish_Utils.Get Member List  /redfish/v1/UpdateService/FirmwareInventory
91    &{sw_inv_dict}=  Create Dictionary
92
93    # sw_member_list:
94    #   [0]:                            /redfish/v1/UpdateService/FirmwareInventory/98744d76
95    #   [1]:                            /redfish/v1/UpdateService/FirmwareInventory/9a8028ec
96    #   [2]:                            /redfish/v1/UpdateService/FirmwareInventory/acc9e073
97
98    FOR  ${uri_path}  IN  @{sw_member_list}
99        &{tmp_dict}=  Create Dictionary
100
101        ${resp}=  Redfish.Get  ${uri_path}  valid_status_codes=[${HTTP_OK}, ${HTTP_INTERNAL_SERVER_ERROR}]
102        ${image_info}  Set Variable  ${resp.dict}
103
104        Set To Dictionary  ${tmp_dict}  image_type  ${image_info["Description"]}
105        Set To Dictionary  ${tmp_dict}  image_id  ${uri_path.split("/")[-1]}
106
107        ${functional}=  Get Software Functional State  ${uri_path.split("/")[-1]}
108
109        Set To Dictionary  ${tmp_dict}  functional  ${functional}
110        Set To Dictionary  ${tmp_dict}  version  ${image_info["Version"]}
111        Set To Dictionary  ${sw_inv_dict}  ${uri_path.split("/")[-1]}  ${tmp_dict}
112    END
113
114    RETURN  &{sw_inv_dict}
115
116
117Get Software Inventory State By Version
118    [Documentation]  Return the software inventory record that matches the given software version.
119    [Arguments]  ${software_version}
120
121    # If no matching record can be found, return ${EMPTY}.
122
123    # Example of returned data:
124    # software_inventory_record:
125    #   [image_type]:      BMC update
126    #   [image_id]:        1e662ba8
127    #   [functional]:      True
128    #   [version]:         2.8.0-dev-150-g04508dc9f
129
130    # Description of argument(s):
131    # software_version     A BMC or Host version (e.g "2.8.0-dev-150-g04508dc9f").
132
133    ${software_inventory}=  Get Software Inventory State
134    # Filter out entries that don't match the criterion..
135    ${software_inventory}=  Filter Struct  ${software_inventory}  [('version', '${software_version}')]
136    # Convert from dictionary to list.
137    ${software_inventory}=  Get Dictionary Values  ${software_inventory}
138    ${num_records}=  Get Length  ${software_inventory}
139
140    Return From Keyword If  ${num_records} == ${0}  ${EMPTY}
141
142    # Return the first list entry.
143    RETURN  ${software_inventory}[0]
144
145
146Get BMC Functional Firmware
147    [Documentation]  Get BMC functional firmware details.
148
149    ${sw_inv}=  Get Functional Firmware  BMC update
150    ${sw_inv}=  Get Non Functional Firmware  ${sw_inv}  True
151
152    RETURN  ${sw_inv}
153
154
155Get Functional Firmware
156    [Documentation]  Get all the BMC firmware details.
157    [Arguments]  ${image_type}
158
159    # Description of argument(s):
160    # image_type    Image value can be either BMC update or Host update.
161
162    ${software_inventory}=  Get Software Inventory State
163    ${bmc_inv}=  Get BMC Firmware  ${image_type}  ${software_inventory}
164
165    RETURN  ${bmc_inv}
166
167
168Get Non Functional Firmware
169    [Documentation]  Get BMC non functional firmware details.
170    [Arguments]  ${sw_inv}  ${functional_state}
171
172    # Description of argument(s):
173    # sw_inv            This dictionary contains all the BMC firmware details.
174    # functional_state  Functional state can be either True or False.
175
176    ${resp}=  Filter Struct  ${sw_inv}  [('functional', ${functional_state})]
177
178    ${num_records}=  Get Length  ${resp}
179    Set Global Variable  ${num_records}
180    Return From Keyword If  ${num_records} == ${0}  ${EMPTY}
181
182    ${list_inv_dict}=  Get Dictionary Values  ${resp}
183
184    RETURN  ${list_inv_dict}[0]
185
186
187Get Non Functional Firmware List
188    [Documentation]  Get BMC non functional firmware details.
189    [Arguments]  ${sw_inv}  ${functional_state}
190
191    # Description of argument(s):
192    # sw_inv            This dictionary contains all the BMC firmware details.
193    # functional_state  Functional state can be either True or False.
194
195    ${list_inv}=  Create List
196
197    FOR  ${key}  IN  @{sw_inv.keys()}
198      Run Keyword If  '${sw_inv['${key}']['functional']}' == '${functional_state}'
199      ...  Append To List  ${list_inv}  ${sw_inv['${key}']}
200    END
201
202    RETURN  ${list_inv}
203
204
205Get Redfish Update Service URI
206    [Documentation]  Get Redfish firmware update URI.
207
208    ${update_url}=  Redfish.Get Attribute  ${REDFISH_BASE_URI}UpdateService  HttpPushUri
209
210    Log To Console  Firmware update URI: ${update_url}
211
212    RETURN  ${update_url}
213
214
215Redfish Upload Image And Check Progress State
216    [Documentation]  Code update with ApplyTime.
217
218    Log To Console   Start uploading image to BMC.
219
220    # URI : /redfish/v1/UpdateService
221    # "HttpPushUri": "/redfish/v1/UpdateService/update",
222
223    ${redfish_update_uri}=  Get Redfish Update Service URI
224    Redfish Upload Image  ${redfish_update_uri}  ${IMAGE_FILE_PATH}
225    Log To Console   Completed image upload to BMC.
226
227    ${image_id}=  Get Latest Image ID
228    Rprint Vars  image_id
229
230    # We have noticed firmware inventory state Enabled quickly as soon the image
231    # is uploaded via redfish.
232    Wait Until Keyword Succeeds  2 min  05 sec
233    ...  Check Image Update Progress State  match_state='Disabled', 'Updating', 'Enabled'  image_id=${image_id}
234
235    Wait Until Keyword Succeeds  8 min  10 sec
236    ...  Check Image Update Progress State
237    ...    match_state='Enabled'  image_id=${image_id}
238
239
240Get Host Power State
241    [Documentation]  Get host power state.
242    [Arguments]  ${quiet}=0
243
244    # Description of arguments:
245    # quiet    Indicates whether results should be printed.
246
247    ${state}=  Redfish.Get Attribute
248    ...  ${REDFISH_BASE_URI}Systems/${SYSTEM_ID}  PowerState
249    Rqprint Vars  state
250
251    RETURN  ${state}
252
253
254Check Host Power State
255    [Documentation]  Check that the machine's host state matches
256    ...  the caller's required host state.
257    [Arguments]  ${match_state}
258
259    # Description of argument(s):
260    # match_state    The expected state. This may be one or more
261    #                comma-separated values (e.g. "On", "Off").
262    #                If the actual state matches any of the
263    #                states named in this argument,
264    #                this keyword passes.
265
266    ${state}=  Get Host Power State
267    Rvalid Value  state  valid_values=[${match_state}]
268
269
270Get System Firmware Details
271    [Documentation]  Return dictionary of system firmware details.
272
273    # {
274    #    FirmwareVersion: 2.8.0-dev-1067-gdc66ce1c5,
275    #    BiosVersion: witherspoon-XXX-XX.X-X
276    # }
277
278    ${firmware_version}=  Redfish Get BMC Version
279    ${bios_version}=  Redfish Get Host Version
280
281    &{sys_firmware_dict}=  Create Dictionary
282    Set To Dictionary
283    ...  ${sys_firmware_dict}  FirmwareVersion  ${firmware_version}  BiosVersion  ${bios_version}
284    Rprint Vars  sys_firmware_dict
285
286    RETURN  &{sys_firmware_dict}
287
288
289Switch Backup Firmware Image To Functional
290   [Documentation]  Switch the backup firmware image to make functional.
291
292   ${sw_inv}=  Get Functional Firmware  BMC image
293   ${nonfunctional_sw_inv}=  Get Non Functional Firmware  ${sw_inv}  False
294
295   ${firmware_inv_path}=
296   ...  Set Variable  /redfish/v1/UpdateService/FirmwareInventory/${nonfunctional_sw_inv['image_id']}
297
298   # Below URI, change to backup image and reset the BMC.
299   Redfish.Patch  /redfish/v1/Managers/${MANAGER_ID}
300   ...  body={'Links': {'ActiveSoftwareImage': {'@odata.id': '${firmware_inv_path}'}}}
301
302
303Create List Of Task
304    [Documentation]  Return list of task id(s) from provided list of dictionary.
305    [Arguments]  ${task_dict_list}
306
307    # Description of argument(s):
308    # task_dict_list    Task id dictionary list.
309
310    # '@odata.id': '/redfish/v1/TaskService/Tasks/0'
311
312    ${task_list}=  Create List
313
314    FOR  ${task_dict}  IN  @{task_dict_list}
315      Append To List  ${task_list}  ${task_dict['@odata.id']}
316    END
317
318    RETURN  ${task_list}
319
320
321Create Initiated Task State Dict
322    [Documentation]  Create active task inventory dictionary as certain URI create task
323    ...  to serve the user request.
324    [Arguments]  ${task_obj}
325
326    # Description of argument(s):
327    # task_obj    Task dictionary.
328
329    # task_inv
330    # TargetUri     /redfish/v1/UpdateService
331    # TaskIdURI     /redfish/v1/TaskService/Tasks/0
332    # TaskState     Starting
333    # TaskStatus    OK
334
335    ${task_inv}=  Create Dictionary
336    Set To Dictionary  ${task_inv}  TargetUri  ${task_obj['Payload']['TargetUri']}
337    Set To Dictionary  ${task_inv}  TaskIdURI  ${task_obj['@odata.id']}
338    Set To Dictionary  ${task_inv}  TaskState  ${task_obj['TaskState']}
339    Set To Dictionary  ${task_inv}  TaskStatus  ${task_obj['TaskStatus']}
340
341    RETURN  ${task_inv}
342
343
344Get Task Inventory
345    [Documentation]  Return task inventory.
346    [Arguments]  ${task_info}
347
348    # Description of argument(s):
349    # task_info    Task information.
350
351    # Task information.
352    # @odata.id: /redfish/v1/TaskService/Tasks/1
353    # Id: 1
354    # TaskState: Starting
355    # TaskStatus: OK
356
357    ${task_payload}=  Redfish.Get Properties   ${task_info['@odata.id']}
358
359    ${task_inv}=  Create Initiated Task State Dict  ${task_payload}
360
361    RETURN  ${task_inv}
362
363
364Match Target URI
365    [Documentation]  Match target uri from task list.
366    [Arguments]  ${task_list}  ${target_uri}
367
368    # Description of argument(s):
369    # task_list    Task id list.
370    # target_uri   Task created for target URI.
371
372    # target_uri   /redfish/v1/UpdateService
373
374    FOR  ${task_id}  IN  @{task_list}
375      ${task_payload}=  Redfish.Get Properties  ${task_id}
376      Run Keyword And Return If  '${task_payload['Payload']['TargetUri']}' == '${target_uri}'  Create Initiated Task State Dict  ${task_payload}
377    END
378
379
380Check Task With Match TargetUri
381    [Documentation]  Create task state dictionary.
382    [Arguments]  ${target_uri}=/redfish/v1/TaskService/Tasks
383
384    # Description of argument(s):
385    # target_uri    Target URI for which task is initiated.
386
387    ${task_dict_list}=  Redfish.Get Attribute  /redfish/v1/TaskService/Tasks  Members
388
389    ${task_list}=  Create List Of Task  ${task_dict_list}
390
391    ${task_inv}=  Match Target URI  ${task_list}  ${target_uri}
392
393    RETURN  ${task_inv}
394
395
396Verify Task Progress State
397    [Documentation]  Verify task progress matches the user expected task state.
398    [Arguments]  ${task_inv}  ${task_state}
399
400    # Description of argument(s):
401    # task_inv      Initiated task inventory dict information.
402    # task_state    Expected task state, user reference from data/task_state.json.
403
404    # task_inv
405    # TaskIdURI     /redfish/v1/TaskService/Tasks/0
406    # TaskState     Starting
407    # TaskStatus    OK
408
409    ${task_payload}=  Redfish.Get Properties   ${task_inv['TaskIdURI']}
410
411    ${temp_task_inv}=  Create Dictionary
412    Set To Dictionary  ${temp_task_inv}  TaskState  ${task_payload['TaskState']}
413    Set To Dictionary  ${temp_task_inv}  TaskStatus  ${task_payload['TaskStatus']}
414
415    Rprint Vars  temp_task_inv
416
417    Should Be Equal As Strings  ${task_state['TaskState']}  ${task_payload['TaskState']}
418    Should Be Equal As Strings  ${task_state['TaskStatus']}  ${task_payload['TaskStatus']}
419
420