1*** Settings ***
2Documentation  BMC and PNOR update utilities keywords.
3
4Library     code_update_utils.py
5Library     OperatingSystem
6Library     String
7Library     utilities.py
8Variables   ../data/variables.py
9Resource    boot_utils.robot
10Resource    rest_client.robot
11Resource    openbmc_ffdc.robot
12
13*** Keywords ***
14
15Get Software Objects
16    [Documentation]  Get the host software objects and return as a list.
17    [Arguments]  ${version_type}=${VERSION_PURPOSE_HOST}
18
19    # Description of argument(s):
20    # version_type  Either BMC or host version purpose.
21    #               By default host version purpose string.
22    #  (e.g. "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"
23    #        "xyz.openbmc_project.Software.Version.VersionPurpose.Host").
24
25    # Example:
26    # "data": [
27    #      "/xyz/openbmc_project/software/f3b29aa8",
28    #      "/xyz/openbmc_project/software/e49bc78e",
29    # ],
30    # Iterate the list and return the host object name path list.
31
32    ${host_list}=  Create List
33    ${sw_list}=  Read Properties  ${SOFTWARE_VERSION_URI}
34
35    :FOR  ${index}  IN  @{sw_list}
36    \  ${attr_purpose}=  Read Software Attribute  ${index}  Purpose
37    \  Continue For Loop If  '${attr_purpose}' != '${version_type}'
38    \  Append To List  ${host_list}  ${index}
39
40    [Return]  ${host_list}
41
42
43Read Software Attribute
44    [Documentation]  Return software attribute data.
45    [Arguments]  ${software_object}  ${attribute_name}
46
47    # Description of argument(s):
48    # software_object   Software object path.
49    #                   (e.g. "/xyz/openbmc_project/software/f3b29aa8").
50    # attribute_name    Software object attribute name.
51
52    ${resp}=  OpenBMC Get Request  ${software_object}/attr/${attribute_name}
53    ...  quiet=${1}
54    Return From Keyword If  ${resp.status_code} != ${HTTP_OK}
55    ${content}=  To JSON  ${resp.content}
56    [Return]  ${content["data"]}
57
58
59Get Software Objects Id
60    [Documentation]  Get the software objects id and return as a list.
61    [Arguments]  ${version_type}=${VERSION_PURPOSE_HOST}
62
63    # Description of argument(s):
64    # version_type  Either BMC or host version purpose.
65    #               By default host version purpose string.
66    #              (e.g. "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"
67    #               "xyz.openbmc_project.Software.Version.VersionPurpose.Host").
68
69    ${sw_id_list}=  Create List
70    ${sw_list}=  Get Software Objects  ${version_type}
71
72    :FOR  ${index}  IN  @{sw_list}
73    \  Append To List  ${sw_id_list}  ${index.rsplit('/', 1)[1]}
74
75    [Return]  ${sw_id_list}
76
77
78Get Host Software Property
79    [Documentation]  Return a dictionary of host software properties.
80    [Arguments]  ${host_object}
81
82    # Description of argument(s):
83    # host_object  Host software object path.
84    #             (e.g. "/xyz/openbmc_project/software/f3b29aa8").
85
86    ${sw_attributes}=  Read Properties  ${host_object}
87    [return]  ${sw_attributes}
88
89Get Host Software Objects Details
90    [Documentation]  Return software object details as a list of dictionaries.
91    [Arguments]  ${quiet}=${QUIET}
92
93    ${software}=  Create List
94
95    ${pnor_details}=  Get Software Objects  ${VERSION_PURPOSE_HOST}
96    :FOR  ${pnor}  IN  @{pnor_details}
97    \  ${resp}=  OpenBMC Get Request  ${pnor}  quiet=${1}
98    \  ${json}=  To JSON  ${resp.content}
99    \  Append To List  ${software}  ${json["data"]}
100
101    [Return]  ${software}
102
103Set Host Software Property
104    [Documentation]  Set the host software properties of a given object.
105    [Arguments]  ${host_object}  ${sw_attribute}  ${data}
106
107    # Description of argument(s):
108    # host_object   Host software object name.
109    # sw_attribute  Host software attribute name.
110    #               (e.g. "Activation", "Priority", "RequestedActivation" etc).
111    # data          Value to be written.
112
113    ${args}=  Create Dictionary  data=${data}
114    Write Attribute  ${host_object}  ${sw_attribute}  data=${args}
115    # Sync time for software updater manager to update.
116    # TODO: openbmc/openbmc#2857
117    Sleep  10s
118
119
120Set Property To Invalid Value And Verify No Change
121    [Documentation]  Attempt to set a property and check that the value didn't
122    ...              change.
123    [Arguments]  ${property}  ${version_type}
124
125    # Description of argument(s):
126    # property      The property to attempt to set.
127    # version_type  Either BMC or host version purpose.
128    #               By default host version purpose string.
129    #  (e.g. "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"
130    #        "xyz.openbmc_project.Software.Version.VersionPurpose.Host").
131
132    ${software_objects}=  Get Software Objects  version_type=${version_type}
133    ${prev_properties}=  Get Host Software Property  @{software_objects}[0]
134    Run Keyword And Expect Error  500 != 200
135    ...  Set Host Software Property  @{software_objects}[0]  ${property}  foo
136    ${cur_properties}=  Get Host Software Property  @{software_objects}[0]
137    Should Be Equal As Strings  &{prev_properties}[${property}]
138    ...  &{cur_properties}[${property}]
139
140
141Set Priority To Invalid Value And Expect Error
142    [Documentation]  Set the priority of an image to an invalid value and
143    ...              check that an error was returned.
144    [Arguments]  ${version_type}  ${priority}
145
146    # Description of argument(s):
147    # version_type  Either BMC or host version purpose.
148    #               (e.g. "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"
149    #                     "xyz.openbmc_project.Software.Version.VersionPurpose.Host").
150    # priority      The priority value to set. Should be an integer outside of
151    #               the range of 0 through 255.
152
153    ${images}=  Get Software Objects  version_type=${version_type}
154    ${num_images}=  Get Length  ${images}
155    Should Be True  0 < ${num_images}
156
157    Run Keyword And Expect Error  403 != 200
158    ...  Set Host Software Property  @{images}[0]  Priority  ${priority}
159
160
161Upload And Activate Image
162    [Documentation]  Upload an image to the BMC and activate it with REST.
163    [Arguments]  ${image_file_path}  ${wait}=${1}  ${skip_if_active}=false
164
165    # Description of argument(s):
166    # image_file_path     The path to the image tarball to upload and activate.
167    # wait                Indicates that this keyword should wait for host or
168    #                     BMC activation is completed.
169    # skip_if_active      If set to true, will skip the code update if this
170    #                     image is already on the BMC.
171
172    OperatingSystem.File Should Exist  ${image_file_path}
173    ${image_version}=  Get Version Tar  ${image_file_path}
174
175    ${image_data}=  OperatingSystem.Get Binary File  ${image_file_path}
176
177    Wait Until Keyword Succeeds  3 times  60 sec
178    ...   Upload Image To BMC  /upload/image  timeout=${30}  data=${image_data}
179    ${ret}  ${version_id}=  Verify Image Upload  ${image_version}
180    Should Be True  ${ret}
181
182    # Verify the image is 'READY' to be activated or if it's already active,
183    # set priority to 0 and reboot the BMC.
184    ${software_state}=  Read Properties  ${SOFTWARE_VERSION_URI}${version_id}
185    ${activation}=  Set Variable  &{software_state}[Activation]
186
187    Run Keyword If
188    ...  '${skip_if_active}' == 'true' and '${activation}' == '${ACTIVE}'
189    ...  Run Keywords
190    ...      Set Host Software Property  ${SOFTWARE_VERSION_URI}${version_id}
191    ...      Priority  ${0}
192    ...    AND
193    ...      Return From Keyword
194
195    Should Be Equal As Strings  &{software_state}[Activation]  ${READY}
196
197    # Request the image to be activated.
198    ${args}=  Create Dictionary  data=${REQUESTED_ACTIVE}
199    Write Attribute  ${SOFTWARE_VERSION_URI}${version_id}
200    ...  RequestedActivation  data=${args}
201    ${software_state}=  Read Properties  ${SOFTWARE_VERSION_URI}${version_id}
202    Should Be Equal As Strings  &{software_state}[RequestedActivation]
203    ...  ${REQUESTED_ACTIVE}
204
205    # Does caller want to wait for activation to complete?
206    Return From Keyword If  '${wait}' == '${0}'  ${version_id}
207
208    # Verify code update was successful and Activation state is Active.
209    Wait For Activation State Change  ${version_id}  ${ACTIVATING}
210    ${software_state}=  Read Properties  ${SOFTWARE_VERSION_URI}${version_id}
211    Should Be Equal As Strings  &{software_state}[Activation]  ${ACTIVE}
212
213    # Uploaded and activated image should have priority set to 0. Due to timing
214    # contention, it may take up to 10 seconds to complete updating priority.
215    Wait Until Keyword Succeeds  10 sec  5 sec
216    ...  Check Software Object Attribute  ${version_id}  Priority  ${0}
217
218    [Return]  ${version_id}
219
220
221Attempt To Reboot BMC During Image Activation
222    [Documentation]  Attempt to reboot the BMC while an image is activating and
223    ...              check that the BMC ignores the reboot command and finishes
224    ...              activation.
225    [Arguments]  ${image_file_path}
226
227    # Description of argument(s):
228    # image_file_path  Path to the image to update to.
229
230    # Attempt to reboot during activation.
231    ${version_id}=  Upload And Activate Image  ${image_file_path}
232    ...  wait=${0}
233    ${resp}=  OpenBMC Get Request  ${SOFTWARE_VERSION_URI}${version_id}
234    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
235
236    OBMC Reboot (off)
237
238    ${resp}=  OpenBMC Get Request  ${SOFTWARE_VERSION_URI}${version_id}
239    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_NOT_FOUND}
240
241
242Activate Image And Verify No Duplicate Priorities
243    [Documentation]  Upload an image, and then check that no images have the
244    ...              same priority.
245    [Arguments]  ${image_file_path}  ${image_purpose}
246
247    # Description of argument(s):
248    # image_file_path  The path to the image to upload.
249    # image_purpose    The purpose in the image's MANIFEST file.
250
251    Upload And Activate Image  ${image_file_path}  skip_if_active=true
252    Verify No Duplicate Image Priorities  ${image_purpose}
253
254
255Set Same Priority For Multiple Images
256    [Documentation]  Find two images, set the priorities to be the same, and
257    ...              verify that the priorities are not the same.
258    [Arguments]  ${version_purpose}
259
260    # Description of argument(s):
261    # version_purpose  Either BMC or host version purpose.
262    #                  (e.g. "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"
263    #                        "xyz.openbmc_project.Software.Version.VersionPurpose.Host").
264
265    # Make sure we have more than two images.
266    ${software_objects}=  Get Software Objects  version_type=${version_purpose}
267    ${num_images}=  Get Length  ${software_objects}
268    Should Be True  1 < ${num_images}
269    ...  msg=Only found one image on the BMC with purpose ${version_purpose}.
270
271    # Set the priority of the second image to the priority of the first.
272    ${properties}=  Get Host Software Property  @{software_objects}[0]
273    Set Host Software Property  @{software_objects}[1]  Priority
274    ...  &{properties}[Priority]
275    Verify No Duplicate Image Priorities  ${version_purpose}
276
277    # Set the priority of the first image back to what it was before
278    Set Host Software Property  @{software_objects}[0]  Priority
279    ...  &{properties}[Priority]
280
281
282Delete Software Object
283    [Documentation]  Deletes an image from the BMC.
284    [Arguments]  ${software_object}
285
286    # Description of argument(s):
287    # software_object  The URI to the software image to delete.
288
289    ${arglist}=  Create List
290    ${args}=  Create Dictionary  data=${arglist}
291    ${resp}=  OpenBMC Post Request  ${software_object}/action/delete
292    ...  data=${args}
293    Should Be Equal As Strings  ${resp.status_code}  ${HTTP_OK}
294
295
296Delete Image And Verify
297    [Documentation]  Delete an image from the BMC and verify that it was
298    ...              removed from software and the /tmp/images directory.
299    [Arguments]  ${software_object}  ${version_type}
300
301    # Description of argument(s):
302    # software_object        The URI of the software object to delete.
303    # version_type  The type of the software object, e.g.
304    #               xyz.openbmc_project.Software.Version.VersionPurpose.Host
305    #               or xyz.openbmc_project.Software.Version.VersionPurpose.BMC.
306
307    Log To Console  Deleting ${software_object}
308
309    # Delete the image.
310    Delete Software Object  ${software_object}
311    # TODO: If/when we don't have to delete twice anymore, take this out
312    Run Keyword And Ignore Error  Delete Software Object  ${software_object}
313
314    # Verify that it's gone from software.
315    ${software_objects}=  Get Software Objects  version_type=${version_type}
316    Should Not Contain  ${software_objects}  ${software_object}
317
318    # Check that there is no file in the /tmp/images directory.
319    ${image_id}=  Fetch From Right  ${software_object}  /
320    BMC Execute Command
321    ...  [ ! -d "/tmp/images/${image_id}" ]
322
323
324Delete All Non Running BMC Images
325    [Documentation]  Delete all BMC images that are not running on the BMC.
326
327    @{datalist}=  Create List
328    ${data}=  Create Dictionary  data=@{datalist}
329    Call Method  ${SOFTWARE_VERSION_URI}  DeleteAll  data=${data}
330
331
332Check Error And Collect FFDC
333    [Documentation]  Collect FFDC if error log exists.
334
335    ${status}=  Run Keyword And Return Status  Error Logs Should Not Exist
336    Run Keyword If  '${status}' == 'False'  FFDC
337    Delete Error Logs
338
339
340Verify Running BMC Image
341    [Documentation]  Verify that the version on the BMC is the same as the
342    ...              version in the given image.
343    [Arguments]  ${image_file_path}
344
345    # Description of argument(s):
346    # image_file_path   Path to the BMC image tarball.
347
348    ${tar_version}=  Get Version Tar  ${image_file_path}
349    ${bmc_version}=  Get BMC Version
350    ${bmc_version}=  Remove String  ${bmc_version}  "
351    Should Be Equal  ${tar_version}  ${bmc_version}
352
353
354Verify Running Host Image
355    [Documentation]  Verify that the version of the PNOR image that is on the
356    ...              BMC is the same as the one in the given image.
357    [Arguments]  ${image_file_path}
358
359    # Description of argument(s):
360    # image_file_path   Path to the PNOR image tarball.
361
362    ${tar_version}=  Get Version Tar  ${image_file_path}
363    ${pnor_version}=  Get PNOR Version
364    Should Be Equal  ${tar_version}  ${pnor_version}
365
366
367Get Least Value Priority Image
368    [Documentation]  Find the least value in "Priority" attribute and return.
369    [Arguments]  ${version_type}
370
371    # Description of argument(s):
372    # version_type  Either BMC or host version purpose.
373
374    ${priority_value_list}=  Create List
375    ${sw_list}=  Get Software Objects  version_type=${version_type}
376
377    :FOR  ${index}  IN  @{sw_list}
378    \  ${priority_value}=
379    ...  Read Software Attribute  ${index}  Priority
380    \  Append To List  ${priority_value_list}  ${priority_value}
381
382    ${min_value}=  Min List Value  ${priority_value_list}
383
384    [Return]  ${min_value}
385
386
387Enable Field Mode And Verify Unmount
388    [Documentation]  Enable field mode and check that /usr/local is unmounted.
389
390    # After running, /xyz/openbmc_project/software should look like this:
391    # /xyz/openbmc_project/software
392    # {
393    #     "FieldModeEnabled": 1,
394    #     "associations": [
395    #         [
396    #             "active",
397    #             "software_version",
398    #             "/xyz/openbmc_project/software/fcf8e182"
399    #         ],
400    #         [
401    #             "functional",
402    #             "functional",
403    #             "/xyz/openbmc_project/software/fcf8e182"
404    #         ]
405    #     ]
406    # }
407
408    ${args}=  Create Dictionary  data=${1}
409    Write Attribute  ${SOFTWARE_VERSION_URI}  FieldModeEnabled  data=${args}
410    Sleep  5s
411    BMC Execute Command  [ ! -d "/usr/local/share" ]
412
413
414Disable Field Mode And Verify Unmount
415    [Documentation]  Disable field mode, unmask usr local mount and reboot.
416
417    BMC Execute Command  /sbin/fw_setenv fieldmode
418    BMC Execute Command  /bin/systemctl unmask usr-local.mount
419    OBMC Reboot (off)  stack_mode=normal
420    BMC Execute Command  [ -d "/usr/local/share" ]
421
422
423Field Mode Should Be Enabled
424    [Documentation]  Check that field mode is enabled.
425
426    ${value}=  Read Attribute  ${SOFTWARE_VERSION_URI}  FieldModeEnabled
427    Should Be True  ${value}  ${1}
428
429List Installed Images
430    [Documentation]  List all the installed images.
431    [Arguments]  ${image_type}
432
433    # Description of argument(s):
434    # image_type  Either "BMC" or "PNOR".
435
436    # List the installed images.
437    ${installed_images}=  Get Software Objects
438    ...  ${SOFTWARE_PURPOSE}.${image_type}
439
440    Run Keyword If  ${installed_images} != []
441    ...  Get List of Images  ${installed_images}
442    ...  ELSE  Log  No ${image_type} images are present.
443
444Get List of Images
445    [Documentation]  Get List of Images
446    [Arguments]  ${installed_images}
447
448    :FOR  ${uri}  IN  @{installed_images}
449    \  ${resp}=  OpenBMC Get Request  ${uri}
450    \  ${json}=  To JSON  ${resp.content}
451    \  Log  ${json["data"]}
452
453
454Check Software Object Attribute
455    [Documentation]  Get the software property of a given object and verify.
456    [Arguments]  ${image_object}  ${sw_attribute}  ${value}
457
458    # Description of argument(s):
459    # image_object  Image software object name.
460    # sw_attribute  Software attribute name.
461    #               (e.g. "Activation", "Priority", "RequestedActivation" etc).
462    # value         Software attribute value to compare.
463
464    ${data}=  Read Attribute
465    ...  ${SOFTWARE_VERSION_URI}${image_object}  ${sw_attribute}
466
467    Should Be True  ${data} == ${value}
468    ...  msg=Given attribute value ${data} mismatch ${value}.
469
470
471Image Should Be Signed
472    [Documentation]  Fail if the image is not signed.
473
474    Directory Should Exist  ${ACTIVATION_DIR_PATH}
475    ...  msg=${ACTIVATION_DIR_PATH} does not exist. Therefore, the image is not signed.
476
477
478Get Latest Image ID
479    [Documentation]  Return the ID of the most recently extracted image.
480    # Note: This keyword will fail if there is no such file.
481
482    # Example: # ls /tmp/images/
483    #            1b714fb7
484    ${image_id}=  Get Latest File  /tmp/images/
485    Rvalid Value  image_id
486
487    # Though an image sub-directory was found, it really isn't valid unless
488    # the MANIFEST file is present.
489    BMC Execute Command  ls -l /tmp/images/${image_id}/MANIFEST
490
491    [Return]  ${image_id}
492
493
494Check Image Update Progress State
495    [Documentation]  Check that the image update progress state matches the specified state.
496    [Arguments]  ${match_state}  ${image_id}
497
498    # Description of argument(s):
499    # match_state    The expected state. This may be one or more comma-separated values
500    #                (e.g. "Disabled", "Disabled, Updating"). If the actual state matches
501    #                any of the states named in this argument, this keyword passes.
502    # image_id       The image ID (e.g. "1b714fb7").
503
504    ${state}=  Get Image Update Progress State  image_id=${image_id}
505    Rvalid Value  state  valid_values=[${match_state}]
506
507
508Get Image Update Progress State
509    [Documentation]  Return the current state of the image update.
510    [Arguments]  ${image_id}
511
512    # Description of argument(s):
513    # image_id         The image ID (e.g. "1b714fb7").
514
515    # In this example, this keyword would return the value "Enabled".
516    #  "Status": {
517    #              "Health": "OK",
518    #              "HealthRollup": "OK",
519    #              "State": "Enabled"
520    #            },
521    ${status}=  Redfish.Get Attribute  /redfish/v1/UpdateService/FirmwareInventory/${image_id}  Status
522    Rprint Vars  status
523
524    [Return]  ${status["State"]}
525
526
527Get Firmware Image Version
528    [Documentation]  Get the version of the currently installed firmware and return it.
529    [Arguments]  ${image_id}
530
531    # Description of argument(s):
532    # image_id      The image ID (e.g. "1b714fb7").
533
534    # Example of a version returned by this keyword:
535    # 2.8.0-dev-19-g6d5764b33
536    ${version}=  Redfish.Get Attribute  /redfish/v1/UpdateService/FirmwareInventory/${image_id}  Version
537    Rprint Vars  version
538
539    [Return]  ${version}
540