Set ExtendedVersion property on Activations

Activation objects are created by this application in three scenarios:
1. When an InterfacesAdded event notifies the application about a new
   PSU image that was uploaded to IMG_DIR (/tmp/images).
2. When getting the firmware version that is already running on a PSU
   in the system.
3. When a firmware version is found in the file system (IMG_DIR_BUILTIN
   or IMG_DIR_PERSIST).

In scenario #2, there are two Activation properties that are not set:
1. Path: the file system path to the image directory.
2. ExtendedVersion: contains the manufacturer and model.

In scenario #3, a firmware version may be found in the file system that
is the same as the version running on a PSU. In this case, the
Activation object has already been created. The Path property on the
existing Activation is set to the file system path.

However, the ExtendedVersion property of the existing Activation is not
set. Due to this, the Activation has no manufacturer or model
information. This means it cannot be used to update other PSUs.

Solve this problem by setting the ExtendedVersion property of the
existing Activation when a matching version is found in the file system.
This will enable the Activation to obtain the manufacturer and model
information. This in turn will allow the Activation to be used to update
other PSUs that are not running the latest version.

Tested:
* Verified that extendedVersion, manufacturer, and model data members
  are set when the Activation constructor is called.
* Verified that extendedVersion, manufacturer, and model data members
  are set when the new, overridden extendedVersion() method is called.
* Verified that the ExtendedVersion property is set by scanDirectory()
  if an Activation already exists.
* For the complete test plan see:
  https://gist.github.com/smccarney/2a3bf72c6faa436199a70968cd99e30e

Change-Id: I7107b8c1d631ada5cd55648f92cf2c1e5cd90778
Signed-off-by: Shawn McCarney <shawnmm@us.ibm.com>
4 files changed
tree: c3928cf6121f5aaf0419f3f60982fdd017a26492
  1. services/
  2. src/
  3. test/
  4. tools/
  5. vendor-example/
  6. .clang-format
  7. .clang-tidy
  8. .gitignore
  9. LICENSE
  10. meson.build
  11. meson.options
  12. OWNERS
  13. README.md
README.md

phosphor-psu-code-mgmt

phosphor-psu-code-mgmt is a service to provide management for PSU code, including:

  • PSU code version
  • PSU code update

Building

meson build/ && ninja -C build

Unit test

  • Run it in OpenBMC CI, refer to local-ci-build.md

  • Run it in OE SDK, run below commands in a x86-64 SDK env:

    meson -Doe-sdk=enabled -Dtests=enabled build/
    ninja -C build/ test  # Meson skips running the case due to it thinks it's cross compiling
    # Manually run the tests
    for t in `find build/test/ -maxdepth 1 -name "test_*"`; do ./$t || break ; done
    

Vendor-specific tools

This repo contains generic code to handle the PSU versions and updates. It depends on vendor-specific tools to provide the below functions on the real PSU hardware:

  • Get PSU firmware version
  • Get PSU model
  • Compare the firmware version
  • Update the PSU firmware

It provides configure options for vendor-specific tools for the above functions:

  • PSU_VERSION_UTIL: It shall be defined as a command-line tool that accepts the PSU inventory path as input, and outputs the PSU version string to stdout.
  • PSU_MODEL_UTIL: It shall be defined as a command-line tool that accepts the PSU inventory path as input, and outputs the PSU model string to stdout.
  • PSU_VERSION_COMPARE_UTIL: It shall be defined as a command-line tool that accepts one or more PSU version strings, and outputs the latest version string to stdout.
  • PSU_UPDATE_SERVICE: It shall be defined as a systemd service that accepts two arguments:
    • The PSU inventory DBus object;
    • The path of the PSU image(s).

For example:

meson -Dtests=disabled \
    '-DPSU_VERSION_UTIL=/usr/bin/psutils --raw --get-version' \
    '-DPSU_MODEL_UTIL=/usr/bin/psutils --raw --get-model' \
    '-DPSU_VERSION_COMPARE_UTIL=/usr/bin/psutils --raw --compare' \
    '-DPSU_UPDATE_SERVICE=psu-update@.service' \
    build

The above configures the vendor-specific tools to use psutils from phosphor-power to get the PSU version and model, compare PSU versions, and use psu-update@.service to perform the PSU firmware update, where internally it invokes psutils as well.

Usage

PSU version

When the service starts, it queries the inventory to get all the PSU inventory paths, invokes the vendor-specific tool to get the versions, and creates version objects under /xyz/openbmc_project/software that are associated with the PSU inventory path. If multiple PSUs are using the same version, multiple PSU inventory paths are associated.

E.g.

  • Example of system with two PSUs that have different versions:

     "/xyz/openbmc_project/software/02572429": {
       "Activation": "xyz.openbmc_project.Software.Activation.Activations.Active",
       "Associations": [
         [
           "inventory",
           "activation",
           "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1"
         ]
       ],
       "ExtendedVersion": "",
       "Path": "",
       "Purpose": "xyz.openbmc_project.Software.Version.VersionPurpose.PSU",
       "RequestedActivation": "xyz.openbmc_project.Software.Activation.RequestedActivations.None",
       "Version": "01120114"
     },
     "/xyz/openbmc_project/software/7094f612": {
       "Activation": "xyz.openbmc_project.Software.Activation.Activations.Active",
       "Associations": [
         [
           "inventory",
           "activation",
           "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0"
         ]
       ],
       "ExtendedVersion": "",
       "Path": "",
       "Purpose": "xyz.openbmc_project.Software.Version.VersionPurpose.PSU",
       "RequestedActivation": "xyz.openbmc_project.Software.Activation.RequestedActivations.None",
       "Version": "00000110"
     },
    
  • Example of system with two PSUs that have the same version:

     "/xyz/openbmc_project/software/9463c2ad": {
       "Activation": "xyz.openbmc_project.Software.Activation.Activations.Active",
       "Associations": [
         [
           "inventory",
           "activation",
           "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply0"
         ],
         [
           "inventory",
           "activation",
           "/xyz/openbmc_project/inventory/system/chassis/motherboard/powersupply1"
         ]
       ],
       "ExtendedVersion": "",
       "Path": "",
       "Purpose": "xyz.openbmc_project.Software.Version.VersionPurpose.PSU",
       "RequestedActivation": "xyz.openbmc_project.Software.Activation.RequestedActivations.None",
       "Version": "01100110"
     },
    

PSU update

  1. Generate a tarball of PSU firmware image by generate-psu-tar tool.

    ./generate-psu-tar --image <psu-image> --version <version> --model <model> --manufacturer \
    <manufacturer> --machineName <machineName> --outfile <psu.tar> --sign
    
  2. To update the PSU firmware, follow the same steps as described in code-update.md:

    • Upload a PSU image tarball and get the version ID;
    • Set the RequestedActivation state of the uploaded image's version ID.
    • Check the state and wait for the activation to be completed.
  3. After a successful update, the PSU image and the manifest is stored in BMC's persistent storage defined by IMG_DIR_PERSIST. When a PSU is replaced, the PSU's firmware version will be checked and updated if it's older than the one stored in BMC.

  4. It is possible to put a PSU image and MANIFEST in the built-in OpenBMC image in BMC's read-only filesystem defined by IMG_DIR_BUILTIN. When the service starts, it will compare the versions of the built-in image and the existing PSUs. If there is any PSU that has older firmware, it will be updated to the new firmware.