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