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