1eee0013eSWilly Tu #pragma once 23ccb3adbSEd Tanous #include "async_resp.hpp" 33ccb3adbSEd Tanous #include "dbus_utility.hpp" 43ccb3adbSEd Tanous #include "error_messages.hpp" 53ccb3adbSEd Tanous #include "generated/enums/resource.hpp" 6eddfc437SWilly Tu #include "http/utility.hpp" 73ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 83ccb3adbSEd Tanous 9e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 10eee0013eSWilly Tu #include <sdbusplus/asio/property.hpp> 11d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 12eee0013eSWilly Tu 13eee0013eSWilly Tu #include <algorithm> 14e99073f5SGeorge Liu #include <array> 15eee0013eSWilly Tu #include <string> 16e99073f5SGeorge Liu #include <string_view> 17eee0013eSWilly Tu #include <vector> 18eee0013eSWilly Tu 19eee0013eSWilly Tu namespace redfish 20eee0013eSWilly Tu { 21eee0013eSWilly Tu namespace sw_util 22eee0013eSWilly Tu { 23eee0013eSWilly Tu /* @brief String that indicates a bios software instance */ 24eee0013eSWilly Tu constexpr const char* biosPurpose = 25eee0013eSWilly Tu "xyz.openbmc_project.Software.Version.VersionPurpose.Host"; 26eee0013eSWilly Tu 27eee0013eSWilly Tu /* @brief String that indicates a BMC software instance */ 28eee0013eSWilly Tu constexpr const char* bmcPurpose = 29eee0013eSWilly Tu "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"; 30eee0013eSWilly Tu 31eee0013eSWilly Tu /** 32eee0013eSWilly Tu * @brief Populate the running software version and image links 33eee0013eSWilly Tu * 34eee0013eSWilly Tu * @param[i,o] aResp Async response object 35eee0013eSWilly Tu * @param[i] swVersionPurpose Indicates what target to look for 36eee0013eSWilly Tu * @param[i] activeVersionPropName Index in aResp->res.jsonValue to write 37eee0013eSWilly Tu * the running software version to 38eee0013eSWilly Tu * @param[i] populateLinkToImages Populate aResp->res "Links" 39eee0013eSWilly Tu * "ActiveSoftwareImage" with a link to the running software image and 40eee0013eSWilly Tu * "SoftwareImages" with a link to the all its software images 41eee0013eSWilly Tu * 42eee0013eSWilly Tu * @return void 43eee0013eSWilly Tu */ 44eee0013eSWilly Tu inline void 45eee0013eSWilly Tu populateSoftwareInformation(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 46eee0013eSWilly Tu const std::string& swVersionPurpose, 47eee0013eSWilly Tu const std::string& activeVersionPropName, 48eee0013eSWilly Tu const bool populateLinkToImages) 49eee0013eSWilly Tu { 50eee0013eSWilly Tu // Used later to determine running (known on Redfish as active) Sw images 51a4eb761aSGeorge Liu dbus::utility::getAssociationEndPoints( 52eee0013eSWilly Tu "/xyz/openbmc_project/software/functional", 53a4eb761aSGeorge Liu [aResp, swVersionPurpose, activeVersionPropName, populateLinkToImages]( 54a4eb761aSGeorge Liu const boost::system::error_code& ec, 55a4eb761aSGeorge Liu const dbus::utility::MapperEndPoints& functionalSw) { 56eee0013eSWilly Tu BMCWEB_LOG_DEBUG << "populateSoftwareInformation enter"; 57eee0013eSWilly Tu if (ec) 58eee0013eSWilly Tu { 59eee0013eSWilly Tu BMCWEB_LOG_ERROR << "error_code = " << ec; 60eee0013eSWilly Tu BMCWEB_LOG_ERROR << "error msg = " << ec.message(); 61eee0013eSWilly Tu messages::internalError(aResp->res); 62eee0013eSWilly Tu return; 63eee0013eSWilly Tu } 64eee0013eSWilly Tu 65eee0013eSWilly Tu if (functionalSw.empty()) 66eee0013eSWilly Tu { 67eee0013eSWilly Tu // Could keep going and try to populate SoftwareImages but 68eee0013eSWilly Tu // something is seriously wrong, so just fail 69eee0013eSWilly Tu BMCWEB_LOG_ERROR << "Zero functional software in system"; 70eee0013eSWilly Tu messages::internalError(aResp->res); 71eee0013eSWilly Tu return; 72eee0013eSWilly Tu } 73eee0013eSWilly Tu 74eee0013eSWilly Tu std::vector<std::string> functionalSwIds; 75eee0013eSWilly Tu // example functionalSw: 76eee0013eSWilly Tu // v as 2 "/xyz/openbmc_project/software/ace821ef" 77eee0013eSWilly Tu // "/xyz/openbmc_project/software/230fb078" 78c6830d5fSGunnar Mills for (const auto& sw : functionalSw) 79eee0013eSWilly Tu { 80c6830d5fSGunnar Mills sdbusplus::message::object_path path(sw); 81eee0013eSWilly Tu std::string leaf = path.filename(); 82eee0013eSWilly Tu if (leaf.empty()) 83eee0013eSWilly Tu { 84eee0013eSWilly Tu continue; 85eee0013eSWilly Tu } 86eee0013eSWilly Tu 87eee0013eSWilly Tu functionalSwIds.push_back(leaf); 88eee0013eSWilly Tu } 89eee0013eSWilly Tu 90e99073f5SGeorge Liu constexpr std::array<std::string_view, 1> interfaces = { 91e99073f5SGeorge Liu "xyz.openbmc_project.Software.Version"}; 92e99073f5SGeorge Liu dbus::utility::getSubTree( 93e99073f5SGeorge Liu "/xyz/openbmc_project/software", 0, interfaces, 94eee0013eSWilly Tu [aResp, swVersionPurpose, activeVersionPropName, 95eee0013eSWilly Tu populateLinkToImages, functionalSwIds]( 96e99073f5SGeorge Liu const boost::system::error_code& ec2, 97eee0013eSWilly Tu const dbus::utility::MapperGetSubTreeResponse& subtree) { 98eee0013eSWilly Tu if (ec2) 99eee0013eSWilly Tu { 100eee0013eSWilly Tu BMCWEB_LOG_ERROR << "error_code = " << ec2; 101eee0013eSWilly Tu BMCWEB_LOG_ERROR << "error msg = " << ec2.message(); 102eee0013eSWilly Tu messages::internalError(aResp->res); 103eee0013eSWilly Tu return; 104eee0013eSWilly Tu } 105eee0013eSWilly Tu 106eee0013eSWilly Tu BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " images"; 107eee0013eSWilly Tu 108eee0013eSWilly Tu for (const std::pair<std::string, 109eee0013eSWilly Tu std::vector<std::pair< 110eee0013eSWilly Tu std::string, std::vector<std::string>>>>& 111eee0013eSWilly Tu obj : subtree) 112eee0013eSWilly Tu { 113eee0013eSWilly Tu 114eee0013eSWilly Tu sdbusplus::message::object_path path(obj.first); 115eee0013eSWilly Tu std::string swId = path.filename(); 116eee0013eSWilly Tu if (swId.empty()) 117eee0013eSWilly Tu { 118eee0013eSWilly Tu messages::internalError(aResp->res); 119eee0013eSWilly Tu BMCWEB_LOG_ERROR << "Invalid software ID"; 120eee0013eSWilly Tu 121eee0013eSWilly Tu return; 122eee0013eSWilly Tu } 123eee0013eSWilly Tu 124eee0013eSWilly Tu bool runningImage = false; 125eee0013eSWilly Tu // Look at Ids from 126eee0013eSWilly Tu // /xyz/openbmc_project/software/functional 127eee0013eSWilly Tu // to determine if this is a running image 128eee0013eSWilly Tu if (std::find(functionalSwIds.begin(), functionalSwIds.end(), 129eee0013eSWilly Tu swId) != functionalSwIds.end()) 130eee0013eSWilly Tu { 131eee0013eSWilly Tu runningImage = true; 132eee0013eSWilly Tu } 133eee0013eSWilly Tu 134eee0013eSWilly Tu // Now grab its version info 135d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 136d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, obj.second[0].first, 137d1bde9e5SKrzysztof Grobelny obj.first, "xyz.openbmc_project.Software.Version", 138eee0013eSWilly Tu [aResp, swId, runningImage, swVersionPurpose, 139eee0013eSWilly Tu activeVersionPropName, populateLinkToImages]( 1405e7e2dc5SEd Tanous const boost::system::error_code& ec3, 141eee0013eSWilly Tu const dbus::utility::DBusPropertiesMap& 142eee0013eSWilly Tu propertiesList) { 143eee0013eSWilly Tu if (ec3) 144eee0013eSWilly Tu { 145eee0013eSWilly Tu BMCWEB_LOG_ERROR << "error_code = " << ec3; 146eee0013eSWilly Tu BMCWEB_LOG_ERROR << "error msg = " << ec3.message(); 147eee0013eSWilly Tu // Have seen the code update app delete the D-Bus 148eee0013eSWilly Tu // object, during code update, between the call to 149eee0013eSWilly Tu // mapper and here. Just leave these properties off if 150eee0013eSWilly Tu // resource not found. 151eee0013eSWilly Tu if (ec3.value() == EBADR) 152eee0013eSWilly Tu { 153eee0013eSWilly Tu return; 154eee0013eSWilly Tu } 155eee0013eSWilly Tu messages::internalError(aResp->res); 156eee0013eSWilly Tu return; 157eee0013eSWilly Tu } 158eee0013eSWilly Tu // example propertiesList 159eee0013eSWilly Tu // a{sv} 2 "Version" s 160eee0013eSWilly Tu // "IBM-witherspoon-OP9-v2.0.10-2.22" "Purpose" 161eee0013eSWilly Tu // s 162eee0013eSWilly Tu // "xyz.openbmc_project.Software.Version.VersionPurpose.Host" 163d1bde9e5SKrzysztof Grobelny const std::string* version = nullptr; 164d1bde9e5SKrzysztof Grobelny const std::string* swInvPurpose = nullptr; 165d1bde9e5SKrzysztof Grobelny 166d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 167d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), propertiesList, 168d1bde9e5SKrzysztof Grobelny "Purpose", swInvPurpose, "Version", version); 169d1bde9e5SKrzysztof Grobelny 170d1bde9e5SKrzysztof Grobelny if (!success) 171eee0013eSWilly Tu { 172eee0013eSWilly Tu messages::internalError(aResp->res); 173eee0013eSWilly Tu return; 174eee0013eSWilly Tu } 175eee0013eSWilly Tu 176d1bde9e5SKrzysztof Grobelny if (version == nullptr || version->empty()) 177eee0013eSWilly Tu { 178eee0013eSWilly Tu messages::internalError(aResp->res); 179eee0013eSWilly Tu return; 180eee0013eSWilly Tu } 181d1bde9e5SKrzysztof Grobelny if (swInvPurpose == nullptr || 182d1bde9e5SKrzysztof Grobelny *swInvPurpose != swVersionPurpose) 183eee0013eSWilly Tu { 184eee0013eSWilly Tu // Not purpose we're looking for 185eee0013eSWilly Tu return; 186eee0013eSWilly Tu } 187eee0013eSWilly Tu 188d1bde9e5SKrzysztof Grobelny BMCWEB_LOG_DEBUG << "Image ID: " << swId; 189d1bde9e5SKrzysztof Grobelny BMCWEB_LOG_DEBUG << "Running image: " << runningImage; 190d1bde9e5SKrzysztof Grobelny BMCWEB_LOG_DEBUG << "Image purpose: " << *swInvPurpose; 191d1bde9e5SKrzysztof Grobelny 192eee0013eSWilly Tu if (populateLinkToImages) 193eee0013eSWilly Tu { 194eee0013eSWilly Tu nlohmann::json& softwareImageMembers = 195eee0013eSWilly Tu aResp->res.jsonValue["Links"]["SoftwareImages"]; 196eee0013eSWilly Tu // Firmware images are at 197eee0013eSWilly Tu // /redfish/v1/UpdateService/FirmwareInventory/<Id> 198eee0013eSWilly Tu // e.g. .../FirmwareInventory/82d3ec86 199613dabeaSEd Tanous nlohmann::json::object_t member; 200eddfc437SWilly Tu member["@odata.id"] = crow::utility::urlFromPieces( 201eddfc437SWilly Tu "redfish", "v1", "UpdateService", 202eddfc437SWilly Tu "FirmwareInventory", swId); 203613dabeaSEd Tanous softwareImageMembers.push_back(std::move(member)); 204eee0013eSWilly Tu aResp->res 205eee0013eSWilly Tu .jsonValue["Links"]["SoftwareImages@odata.count"] = 206eee0013eSWilly Tu softwareImageMembers.size(); 207eee0013eSWilly Tu 208eee0013eSWilly Tu if (runningImage) 209eee0013eSWilly Tu { 210613dabeaSEd Tanous nlohmann::json::object_t runningMember; 211613dabeaSEd Tanous runningMember["@odata.id"] = 212eddfc437SWilly Tu crow::utility::urlFromPieces( 213eddfc437SWilly Tu "redfish", "v1", "UpdateService", 214eddfc437SWilly Tu "FirmwareInventory", swId); 215eee0013eSWilly Tu // Create the link to the running image 216eee0013eSWilly Tu aResp->res 217613dabeaSEd Tanous .jsonValue["Links"]["ActiveSoftwareImage"] = 218613dabeaSEd Tanous std::move(runningMember); 219eee0013eSWilly Tu } 220eee0013eSWilly Tu } 221eee0013eSWilly Tu if (!activeVersionPropName.empty() && runningImage) 222eee0013eSWilly Tu { 223d1bde9e5SKrzysztof Grobelny aResp->res.jsonValue[activeVersionPropName] = *version; 224eee0013eSWilly Tu } 225d1bde9e5SKrzysztof Grobelny }); 226eee0013eSWilly Tu } 227e99073f5SGeorge Liu }); 228eee0013eSWilly Tu }); 229eee0013eSWilly Tu } 230eee0013eSWilly Tu 231eee0013eSWilly Tu /** 232eee0013eSWilly Tu * @brief Translate input swState to Redfish state 233eee0013eSWilly Tu * 234eee0013eSWilly Tu * This function will return the corresponding Redfish state 235eee0013eSWilly Tu * 236eee0013eSWilly Tu * @param[i] swState The OpenBMC software state 237eee0013eSWilly Tu * 238eee0013eSWilly Tu * @return The corresponding Redfish state 239eee0013eSWilly Tu */ 2400ec8b83dSEd Tanous inline resource::State getRedfishSwState(const std::string& swState) 241eee0013eSWilly Tu { 242eee0013eSWilly Tu if (swState == "xyz.openbmc_project.Software.Activation.Activations.Active") 243eee0013eSWilly Tu { 2440ec8b83dSEd Tanous return resource::State::Enabled; 245eee0013eSWilly Tu } 246eee0013eSWilly Tu if (swState == "xyz.openbmc_project.Software.Activation." 247eee0013eSWilly Tu "Activations.Activating") 248eee0013eSWilly Tu { 2490ec8b83dSEd Tanous return resource::State::Updating; 250eee0013eSWilly Tu } 251eee0013eSWilly Tu if (swState == "xyz.openbmc_project.Software.Activation." 252eee0013eSWilly Tu "Activations.StandbySpare") 253eee0013eSWilly Tu { 2540ec8b83dSEd Tanous return resource::State::StandbySpare; 255eee0013eSWilly Tu } 256eee0013eSWilly Tu BMCWEB_LOG_DEBUG << "Default sw state " << swState << " to Disabled"; 2570ec8b83dSEd Tanous return resource::State::Disabled; 258eee0013eSWilly Tu } 259eee0013eSWilly Tu 260eee0013eSWilly Tu /** 261eee0013eSWilly Tu * @brief Translate input swState to Redfish health state 262eee0013eSWilly Tu * 263eee0013eSWilly Tu * This function will return the corresponding Redfish health state 264eee0013eSWilly Tu * 265eee0013eSWilly Tu * @param[i] swState The OpenBMC software state 266eee0013eSWilly Tu * 267eee0013eSWilly Tu * @return The corresponding Redfish health state 268eee0013eSWilly Tu */ 269eee0013eSWilly Tu inline std::string getRedfishSwHealth(const std::string& swState) 270eee0013eSWilly Tu { 271eee0013eSWilly Tu if ((swState == 272eee0013eSWilly Tu "xyz.openbmc_project.Software.Activation.Activations.Active") || 273eee0013eSWilly Tu (swState == "xyz.openbmc_project.Software.Activation.Activations." 274eee0013eSWilly Tu "Activating") || 275eee0013eSWilly Tu (swState == 276eee0013eSWilly Tu "xyz.openbmc_project.Software.Activation.Activations.Ready")) 277eee0013eSWilly Tu { 278eee0013eSWilly Tu return "OK"; 279eee0013eSWilly Tu } 280eee0013eSWilly Tu BMCWEB_LOG_DEBUG << "Sw state " << swState << " to Warning"; 281eee0013eSWilly Tu return "Warning"; 282eee0013eSWilly Tu } 283eee0013eSWilly Tu 284eee0013eSWilly Tu /** 285eee0013eSWilly Tu * @brief Put status of input swId into json response 286eee0013eSWilly Tu * 287eee0013eSWilly Tu * This function will put the appropriate Redfish state of the input 288eee0013eSWilly Tu * software id to ["Status"]["State"] within the json response 289eee0013eSWilly Tu * 290eee0013eSWilly Tu * @param[i,o] aResp Async response object 291eee0013eSWilly Tu * @param[i] swId The software ID to get status for 292eee0013eSWilly Tu * @param[i] dbusSvc The dbus service implementing the software object 293eee0013eSWilly Tu * 294eee0013eSWilly Tu * @return void 295eee0013eSWilly Tu */ 296eee0013eSWilly Tu inline void getSwStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 297eee0013eSWilly Tu const std::shared_ptr<std::string>& swId, 298eee0013eSWilly Tu const std::string& dbusSvc) 299eee0013eSWilly Tu { 300eee0013eSWilly Tu BMCWEB_LOG_DEBUG << "getSwStatus: swId " << *swId << " svc " << dbusSvc; 301eee0013eSWilly Tu 302d1bde9e5SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 303d1bde9e5SKrzysztof Grobelny *crow::connections::systemBus, dbusSvc, 304d1bde9e5SKrzysztof Grobelny "/xyz/openbmc_project/software/" + *swId, 305d1bde9e5SKrzysztof Grobelny "xyz.openbmc_project.Software.Activation", 306eee0013eSWilly Tu [asyncResp, 3075e7e2dc5SEd Tanous swId](const boost::system::error_code& errorCode, 308eee0013eSWilly Tu const dbus::utility::DBusPropertiesMap& propertiesList) { 309eee0013eSWilly Tu if (errorCode) 310eee0013eSWilly Tu { 311eee0013eSWilly Tu // not all swtypes are updateable, this is ok 312eee0013eSWilly Tu asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 313eee0013eSWilly Tu return; 314eee0013eSWilly Tu } 315d1bde9e5SKrzysztof Grobelny 316eee0013eSWilly Tu const std::string* swInvActivation = nullptr; 317d1bde9e5SKrzysztof Grobelny 318d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 319d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), propertiesList, "Activation", 320d1bde9e5SKrzysztof Grobelny swInvActivation); 321d1bde9e5SKrzysztof Grobelny 322d1bde9e5SKrzysztof Grobelny if (!success) 323eee0013eSWilly Tu { 324d1bde9e5SKrzysztof Grobelny messages::internalError(asyncResp->res); 325d1bde9e5SKrzysztof Grobelny return; 326eee0013eSWilly Tu } 327eee0013eSWilly Tu 328eee0013eSWilly Tu if (swInvActivation == nullptr) 329eee0013eSWilly Tu { 330eee0013eSWilly Tu messages::internalError(asyncResp->res); 331eee0013eSWilly Tu return; 332eee0013eSWilly Tu } 333d1bde9e5SKrzysztof Grobelny 334eee0013eSWilly Tu BMCWEB_LOG_DEBUG << "getSwStatus: Activation " << *swInvActivation; 335eee0013eSWilly Tu asyncResp->res.jsonValue["Status"]["State"] = 336eee0013eSWilly Tu getRedfishSwState(*swInvActivation); 337eee0013eSWilly Tu asyncResp->res.jsonValue["Status"]["Health"] = 338eee0013eSWilly Tu getRedfishSwHealth(*swInvActivation); 339d1bde9e5SKrzysztof Grobelny }); 340eee0013eSWilly Tu } 341eee0013eSWilly Tu 342eee0013eSWilly Tu /** 343eee0013eSWilly Tu * @brief Updates programmable status of input swId into json response 344eee0013eSWilly Tu * 345eee0013eSWilly Tu * This function checks whether software inventory component 346eee0013eSWilly Tu * can be programmable or not and fill's the "Updatable" 347eee0013eSWilly Tu * Property. 348eee0013eSWilly Tu * 349eee0013eSWilly Tu * @param[i,o] asyncResp Async response object 350eee0013eSWilly Tu * @param[i] swId The software ID 351eee0013eSWilly Tu */ 352eee0013eSWilly Tu inline void 353eee0013eSWilly Tu getSwUpdatableStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 354eee0013eSWilly Tu const std::shared_ptr<std::string>& swId) 355eee0013eSWilly Tu { 356*6c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 357eee0013eSWilly Tu "/xyz/openbmc_project/software/updateable", 3585e7e2dc5SEd Tanous [asyncResp, swId](const boost::system::error_code& ec, 359*6c3e9451SGeorge Liu const dbus::utility::MapperEndPoints& objPaths) { 360eee0013eSWilly Tu if (ec) 361eee0013eSWilly Tu { 362eee0013eSWilly Tu BMCWEB_LOG_DEBUG << " error_code = " << ec 363eee0013eSWilly Tu << " error msg = " << ec.message(); 364eee0013eSWilly Tu // System can exist with no updateable software, 365eee0013eSWilly Tu // so don't throw error here. 366eee0013eSWilly Tu return; 367eee0013eSWilly Tu } 368eee0013eSWilly Tu std::string reqSwObjPath = "/xyz/openbmc_project/software/" + *swId; 369eee0013eSWilly Tu 370eee0013eSWilly Tu if (std::find(objPaths.begin(), objPaths.end(), reqSwObjPath) != 371eee0013eSWilly Tu objPaths.end()) 372eee0013eSWilly Tu { 37383edb08fSGunnar Mills asyncResp->res.jsonValue["Updateable"] = true; 374eee0013eSWilly Tu return; 375eee0013eSWilly Tu } 376eee0013eSWilly Tu }); 377eee0013eSWilly Tu } 378eee0013eSWilly Tu 379eee0013eSWilly Tu } // namespace sw_util 380eee0013eSWilly Tu } // namespace redfish 381