1 #pragma once 2 3 #include "config.h" 4 5 #include "activation.hpp" 6 #include "association_interface.hpp" 7 #include "types.hpp" 8 #include "utils.hpp" 9 #include "version.hpp" 10 11 #include <phosphor-logging/log.hpp> 12 #include <sdbusplus/server.hpp> 13 #include <xyz/openbmc_project/Association/Definitions/server.hpp> 14 #include <xyz/openbmc_project/Collection/DeleteAll/server.hpp> 15 16 #include <filesystem> 17 #include <map> 18 #include <string> 19 #include <variant> 20 #include <vector> 21 22 class TestItemUpdater; 23 24 namespace phosphor 25 { 26 namespace software 27 { 28 namespace updater 29 { 30 31 class Version; 32 33 using ItemUpdaterInherit = sdbusplus::server::object_t< 34 sdbusplus::xyz::openbmc_project::Association::server::Definitions>; 35 36 namespace MatchRules = sdbusplus::bus::match::rules; 37 38 namespace fs = std::filesystem; 39 40 /** @class ItemUpdater 41 * @brief Manages the activation of the PSU version items. 42 */ 43 class ItemUpdater : 44 public ItemUpdaterInherit, 45 public AssociationInterface, 46 public ActivationListener 47 { 48 friend class ::TestItemUpdater; 49 50 public: 51 /** @brief Constructs ItemUpdater 52 * 53 * @param[in] bus - The D-Bus bus object 54 * @param[in] path - The D-Bus path 55 */ ItemUpdater(sdbusplus::bus_t & bus,const std::string & path)56 ItemUpdater(sdbusplus::bus_t& bus, const std::string& path) : 57 ItemUpdaterInherit(bus, path.c_str()), bus(bus), 58 versionMatch( 59 bus, 60 MatchRules::interfacesAdded() + MatchRules::path(SOFTWARE_OBJPATH), 61 std::bind(std::mem_fn(&ItemUpdater::onVersionInterfacesAddedMsg), 62 this, std::placeholders::_1)), 63 psuInterfaceMatch( 64 bus, 65 MatchRules::interfacesAdded() + 66 MatchRules::path("/xyz/openbmc_project/inventory") + 67 MatchRules::sender("xyz.openbmc_project.Inventory.Manager"), 68 std::bind(std::mem_fn(&ItemUpdater::onPSUInterfacesAdded), this, 69 std::placeholders::_1)) 70 { 71 processPSUImageAndSyncToLatest(); 72 } 73 74 /** @brief Deletes version 75 * 76 * @param[in] versionId - Id of the version to delete 77 */ 78 void erase(const std::string& versionId); 79 80 /** @brief Creates an active association to the 81 * newly active software image 82 * 83 * @param[in] path - The path to create the association to. 84 */ 85 void createActiveAssociation(const std::string& path) override; 86 87 /** @brief Add the functional association to the 88 * new "running" PSU images 89 * 90 * @param[in] path - The path to add the association to. 91 */ 92 void addFunctionalAssociation(const std::string& path) override; 93 94 /** @brief Add the updateable association to the 95 * "running" PSU software image 96 * 97 * @param[in] path - The path to create the association. 98 */ 99 void addUpdateableAssociation(const std::string& path) override; 100 101 /** @brief Removes the associations from the provided software image path 102 * 103 * @param[in] path - The path to remove the association from. 104 */ 105 void removeAssociation(const std::string& path) override; 106 107 /** @brief Notify a PSU is updated 108 * 109 * @param[in] versionId - The versionId of the activation 110 * @param[in] psuInventoryPath - The PSU inventory path that is updated 111 */ 112 void onUpdateDone(const std::string& versionId, 113 const std::string& psuInventoryPath) override; 114 115 private: 116 using Properties = 117 std::map<std::string, utils::UtilsInterface::PropertyType>; 118 using InterfacesAddedMap = 119 std::map<std::string, 120 std::map<std::string, std::variant<bool, std::string>>>; 121 122 /** @brief Callback function for Software.Version match. 123 * 124 * @param[in] msg - Data associated with subscribed signal 125 */ 126 void onVersionInterfacesAddedMsg(sdbusplus::message_t& msg); 127 128 /** @brief Called when new Software.Version interfaces are found 129 * @details Creates an Activation D-Bus object if appropriate 130 * Throws an exception if an error occurs. 131 * 132 * @param[in] path - D-Bus object path 133 * @param[in] interfaces - D-Bus interfaces that were added 134 */ 135 void onVersionInterfacesAdded(const std::string& path, 136 const InterfacesAddedMap& interfaces); 137 138 /** @brief Callback function for PSU inventory match. 139 * 140 * @param[in] msg - Data associated with subscribed signal 141 */ 142 void onPsuInventoryChangedMsg(sdbusplus::message_t& msg); 143 144 /** @brief Called when a PSU inventory object has changed 145 * @details Update an Activation D-Bus object for PSU inventory. 146 * Throws an exception if an error occurs. 147 * 148 * @param[in] psuPath - The PSU inventory path 149 * @param[in] properties - The updated properties 150 */ 151 void onPsuInventoryChanged(const std::string& psuPath, 152 const Properties& properties); 153 154 /** @brief Create Activation object */ 155 std::unique_ptr<Activation> createActivationObject( 156 const std::string& path, const std::string& versionId, 157 const std::string& extVersion, Activation::Status activationStatus, 158 const AssociationList& assocs, const std::string& filePath); 159 160 /** @brief Create Version object */ 161 std::unique_ptr<Version> createVersionObject( 162 const std::string& objPath, const std::string& versionId, 163 const std::string& versionString, 164 sdbusplus::xyz::openbmc_project::Software::server::Version:: 165 VersionPurpose versionPurpose); 166 167 /** @brief Create Activation and Version object for PSU inventory 168 * @details If the same version exists for multiple PSUs, just add 169 * related association, instead of creating new objects. 170 * */ 171 void createPsuObject(const std::string& psuInventoryPath, 172 const std::string& psuVersion); 173 174 /** @brief Remove Activation and Version object for PSU inventory 175 * @details If the same version exists for multiple PSUs, just remove 176 * related association. 177 * If the version has no association, the Activation and 178 * Version object will be removed 179 */ 180 void removePsuObject(const std::string& psuInventoryPath); 181 182 /** @brief Add PSU inventory path to the PSU status map 183 * @details Also adds a PropertiesChanged listener for the inventory path 184 * so we are notified when the Present property changes. 185 * Does nothing if the inventory path already exists in the map. 186 * 187 * @param[in] psuPath - The PSU inventory path 188 */ 189 void addPsuToStatusMap(const std::string& psuPath); 190 191 /** @brief Handle a change in presence for a PSU. 192 * 193 * @param[in] psuPath - The PSU inventory path 194 */ 195 void handlePSUPresenceChanged(const std::string& psuPath); 196 197 /** 198 * @brief Create and populate the active PSU Version. 199 */ 200 void processPSUImage(); 201 202 /** @brief Create PSU Version from stored images */ 203 void processStoredImage(); 204 205 /** @brief Scan a directory and create PSU Version from stored images 206 * @details Throws an exception if an error occurs 207 * 208 * @param[in] dir Directory path to scan 209 */ 210 void scanDirectory(const fs::path& dir); 211 212 /** @brief Find the PSU model subdirectory within the specified directory 213 * @details Throws an exception if an error occurs 214 * 215 * @param[in] dir Directory path to search 216 * 217 * @return Subdirectory path, or an empty path if none found 218 */ 219 fs::path findModelDirectory(const fs::path& dir); 220 221 /** @brief Get the versionId of the latest PSU version */ 222 std::optional<std::string> getLatestVersionId(); 223 224 /** @brief Update PSUs to the latest version */ 225 void syncToLatestImage(); 226 227 /** @brief Invoke the activation via DBus */ 228 static void invokeActivation(const std::unique_ptr<Activation>& activation); 229 230 /** @brief Callback function for interfaces added signal. 231 * 232 * This method is called when new interfaces are added. It updates the 233 * internal status map and processes the new PSU if it's present. 234 * 235 * @param[in] msg - Data associated with subscribed signal 236 */ 237 void onPSUInterfacesAdded(sdbusplus::message_t& msg); 238 239 /** 240 * @brief Handles the processing of PSU images. 241 * 242 * This function responsible for invoking the sequence of processing PSU 243 * images, processing stored images, and syncing to the latest firmware 244 * image. 245 */ 246 void processPSUImageAndSyncToLatest(); 247 248 /** @brief Retrieve FW version from IMG_DIR_BUILTIN 249 * 250 * This function retrieves the firmware version from the PSU model directory 251 * that is in the IMG_DIR_BUILTIN. It loops through the activations map to 252 * find matching path starts with IMG_DIR_BUILTIN, then gets the 253 * corresponding version ID, and then looks it up in the versions map to 254 * retrieve the associated version string. 255 */ 256 std::string getFWVersionFromBuiltinDir(); 257 258 /** @brief Persistent sdbusplus D-Bus bus connection. */ 259 sdbusplus::bus_t& bus; 260 261 /** @brief Persistent map of Activation D-Bus objects and their 262 * version id */ 263 std::map<std::string, std::unique_ptr<Activation>> activations; 264 265 /** @brief Persistent map of Version D-Bus objects and their 266 * version id */ 267 std::map<std::string, std::unique_ptr<Version>> versions; 268 269 /** @brief The reference map of PSU Inventory objects and the 270 * Activation*/ 271 std::map<std::string, const std::unique_ptr<Activation>&> 272 psuPathActivationMap; 273 274 /** @brief sdbusplus signal match for PSU Software*/ 275 sdbusplus::bus::match_t versionMatch; 276 277 /** @brief sdbusplus signal matches for PSU Inventory */ 278 std::vector<sdbusplus::bus::match_t> psuMatches; 279 280 /** @brief This entry's associations */ 281 AssociationList assocs; 282 283 /** @brief A collection of the version strings */ 284 std::set<std::string> versionStrings; 285 286 /** @brief A struct to hold the PSU present status and model */ 287 struct psuStatus 288 { 289 bool present; 290 std::string model; 291 }; 292 293 /** @brief The map of PSU inventory path and the psuStatus 294 * 295 * It is used to handle psu inventory changed event, that only create psu 296 * software object when a PSU is present and the model is retrieved */ 297 std::map<std::string, psuStatus> psuStatusMap; 298 299 /** @brief Signal match for PSU interfaces added. 300 * 301 * This match listens for D-Bus signals indicating new interface has been 302 * added. When such a signal received, it triggers the 303 * `onInterfacesAdded` method to handle the new PSU. 304 */ 305 sdbusplus::bus::match_t psuInterfaceMatch; 306 }; 307 308 } // namespace updater 309 } // namespace software 310 } // namespace phosphor 311