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/bmc  FirmwareVersion
26    ...  ELSE
27    ...    Redfish.Get Attribute  /redfish/v1/Systems/system  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/bmc  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 matchine 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
205Redfish Upload Image And Check Progress State
206    [Documentation]  Code update with ApplyTime.
207
208    Log To Console   Start uploading image to BMC.
209    Redfish Upload Image  ${REDFISH_BASE_URI}UpdateService  ${IMAGE_FILE_PATH}
210    Log To Console   Completed image upload to BMC.
211
212    ${image_id}=  Get Latest Image ID
213    Rprint Vars  image_id
214
215    # We have noticed firmware inventory state Enabled quickly as soon the image
216    # is uploaded via redfish.
217    Wait Until Keyword Succeeds  2 min  05 sec
218    ...  Check Image Update Progress State  match_state='Disabled', 'Updating', 'Enabled'  image_id=${image_id}
219
220    Wait Until Keyword Succeeds  8 min  10 sec
221    ...  Check Image Update Progress State
222    ...    match_state='Enabled'  image_id=${image_id}
223
224
225Get Host Power State
226    [Documentation]  Get host power state.
227    [Arguments]  ${quiet}=0
228
229    # Description of arguments:
230    # quiet    Indicates whether results should be printed.
231
232    ${state}=  Redfish.Get Attribute
233    ...  ${REDFISH_BASE_URI}Systems/system  PowerState
234    Rqprint Vars  state
235
236    [Return]  ${state}
237
238
239Check Host Power State
240    [Documentation]  Check that the machine's host state matches
241    ...  the caller's required host state.
242    [Arguments]  ${match_state}
243
244    # Description of argument(s):
245    # match_state    The expected state. This may be one or more
246    #                comma-separated values (e.g. "On", "Off").
247    #                If the actual state matches any of the
248    #                states named in this argument,
249    #                this keyword passes.
250
251    ${state}=  Get Host Power State
252    Rvalid Value  state  valid_values=[${match_state}]
253
254
255Get System Firmware Details
256    [Documentation]  Return dictionary of system firmware details.
257
258    # {
259    #    FirmwareVersion: 2.8.0-dev-1067-gdc66ce1c5,
260    #    BiosVersion: witherspoon-XXX-XX.X-X
261    # }
262
263    ${firmware_version}=  Redfish Get BMC Version
264    ${bios_version}=  Redfish Get Host Version
265
266    &{sys_firmware_dict}=  Create Dictionary
267    Set To Dictionary
268    ...  ${sys_firmware_dict}  FirmwareVersion  ${firmware_version}  BiosVersion  ${bios_version}
269    Rprint Vars  sys_firmware_dict
270
271    [Return]  &{sys_firmware_dict}
272
273
274Switch Backup Firmware Image To Functional
275   [Documentation]  Switch the backup firmware image to make functional.
276
277   ${sw_inv}=  Get Functional Firmware  BMC image
278   ${nonfunctional_sw_inv}=  Get Non Functional Firmware  ${sw_inv}  False
279
280   ${firmware_inv_path}=
281   ...  Set Variable  /redfish/v1/UpdateService/FirmwareInventory/${nonfunctional_sw_inv['image_id']}
282
283   # Below URI, change to backup image and reset the BMC.
284   Redfish.Patch  /redfish/v1/Managers/bmc
285   ...  body={'Links': {'ActiveSoftwareImage': {'@odata.id': '${firmware_inv_path}'}}}
286
287
288Create List Of Task
289    [Documentation]  Return list of task id(s) from provided list of dictionary.
290    [Arguments]  ${task_dict_list}
291
292    # Description of argument(s):
293    # task_dict_list    Task id dictionary list.
294
295    # '@odata.id': '/redfish/v1/TaskService/Tasks/0'
296
297    ${task_list}=  Create List
298
299    FOR  ${task_dict}  IN  @{task_dict_list}
300      Append To List  ${task_list}  ${task_dict['@odata.id']}
301    END
302
303    [Return]  ${task_list}
304
305
306Create Initiated Task State Dict
307    [Documentation]  Create active task inventory dictionary as certain URI create task
308    ...  to serve the user request.
309    [Arguments]  ${task_obj}
310
311    # Description of argument(s):
312    # task_obj    Task dictionary.
313
314    # task_inv
315    # TargetUri     /redfish/v1/UpdateService
316    # TaskIdURI     /redfish/v1/TaskService/Tasks/0
317    # TaskState     Starting
318    # TaskStatus    OK
319
320    ${task_inv}=  Create Dictionary
321    Set To Dictionary  ${task_inv}  TargetUri  ${task_obj['Payload']['TargetUri']}
322    Set To Dictionary  ${task_inv}  TaskIdURI  ${task_obj['@odata.id']}
323    Set To Dictionary  ${task_inv}  TaskState  ${task_obj['TaskState']}
324    Set To Dictionary  ${task_inv}  TaskStatus  ${task_obj['TaskStatus']}
325
326    [Return]  ${task_inv}
327
328
329Match Target URI
330    [Documentation]  Match target uri from task list.
331    [Arguments]  ${task_list}  ${target_uri}
332
333    # Description of argument(s):
334    # task_list    Task id list.
335    # target_uri   Task created for target URI.
336
337    # target_uri   /redfish/v1/UpdateService
338
339    FOR  ${task_id}  IN  @{task_list}
340      ${task_payload}=  Redfish.Get Properties  ${task_id}
341      Run Keyword And Return If  '${task_payload['Payload']['TargetUri']}' == '${target_uri}'  Create Initiated Task State Dict  ${task_payload}
342    END
343
344
345Check Task With Match TargetUri
346    [Documentation]  Create task state dictionary.
347    [Arguments]  ${target_uri}=/redfish/v1/TaskService/Tasks
348
349    # Description of argument(s):
350    # target_uri    Target URI for which task is initiated.
351
352    ${task_dict_list}=  Redfish.Get Attribute  /redfish/v1/TaskService/Tasks  Members
353
354    ${task_list}=  Create List Of Task  ${task_dict_list}
355
356    ${task_inv}=  Match Target URI  ${task_list}  ${target_uri}
357
358    [Return]  ${task_inv}
359
360
361Verify Task Progress State
362    [Documentation]  Verify task progress matches the user expected task state.
363    [Arguments]  ${task_inv}  ${task_state}
364
365    # Description of argument(s):
366    # task_inv      Initiated task inventory dict information.
367    # task_state    Expected task state, user reference from data/task_state.json.
368
369    # task_inv
370    # TaskIdURI     /redfish/v1/TaskService/Tasks/0
371    # TaskState     Starting
372    # TaskStatus    OK
373
374    ${task_payload}=  Redfish.Get Properties   ${task_inv['TaskIdURI']}
375
376    ${temp_task_inv}=  Create Dictionary
377    Set To Dictionary  ${temp_task_inv}  TaskState  ${task_payload['TaskState']}
378    Set To Dictionary  ${temp_task_inv}  TaskStatus  ${task_payload['TaskStatus']}
379
380    Rprint Vars  temp_task_inv
381
382    Should Be Equal As Strings  ${task_state['TaskState']}  ${task_payload['TaskState']}
383    Should Be Equal As Strings  ${task_state['TaskStatus']}  ${task_payload['TaskStatus']}
384
385