140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3eee0013eSWilly Tu #pragma once 4d7857201SEd Tanous #include "bmcweb_config.h" 5d7857201SEd Tanous 63ccb3adbSEd Tanous #include "async_resp.hpp" 7177612aaSEd Tanous #include "boost_formatters.hpp" 8d7857201SEd Tanous #include "dbus_singleton.hpp" 93ccb3adbSEd Tanous #include "dbus_utility.hpp" 103ccb3adbSEd Tanous #include "error_messages.hpp" 113ccb3adbSEd Tanous #include "generated/enums/resource.hpp" 12d7857201SEd Tanous #include "logging.hpp" 133ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 143ccb3adbSEd Tanous 15d7857201SEd Tanous #include <asm-generic/errno.h> 16d7857201SEd Tanous 17e99073f5SGeorge Liu #include <boost/system/error_code.hpp> 18ef4c65b7SEd Tanous #include <boost/url/format.hpp> 19d7857201SEd Tanous #include <nlohmann/json.hpp> 20d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 21d1bde9e5SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 22eee0013eSWilly Tu 23eee0013eSWilly Tu #include <algorithm> 24e99073f5SGeorge Liu #include <array> 25d7857201SEd Tanous #include <functional> 26d7857201SEd Tanous #include <memory> 277f23576aSJagpal Singh Gill #include <optional> 283544d2a7SEd Tanous #include <ranges> 29eee0013eSWilly Tu #include <string> 30e99073f5SGeorge Liu #include <string_view> 31d7857201SEd Tanous #include <utility> 32eee0013eSWilly Tu #include <vector> 33eee0013eSWilly Tu 34eee0013eSWilly Tu namespace redfish 35eee0013eSWilly Tu { 36eee0013eSWilly Tu namespace sw_util 37eee0013eSWilly Tu { 38eee0013eSWilly Tu /* @brief String that indicates a bios software instance */ 39eee0013eSWilly Tu constexpr const char* biosPurpose = 40eee0013eSWilly Tu "xyz.openbmc_project.Software.Version.VersionPurpose.Host"; 41eee0013eSWilly Tu 42eee0013eSWilly Tu /* @brief String that indicates a BMC software instance */ 43eee0013eSWilly Tu constexpr const char* bmcPurpose = 44eee0013eSWilly Tu "xyz.openbmc_project.Software.Version.VersionPurpose.BMC"; 45eee0013eSWilly Tu 46504af5a0SPatrick Williams inline std::optional<sdbusplus::message::object_path> getFunctionalSoftwarePath( 47504af5a0SPatrick Williams const std::string& swType) 487f23576aSJagpal Singh Gill { 497f23576aSJagpal Singh Gill if (swType == bmcPurpose) 507f23576aSJagpal Singh Gill { 517f23576aSJagpal Singh Gill if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS) 527f23576aSJagpal Singh Gill { 537f23576aSJagpal Singh Gill return sdbusplus::message::object_path( 547f23576aSJagpal Singh Gill "/xyz/openbmc_project/software/bmc/functional"); 557f23576aSJagpal Singh Gill } 567f23576aSJagpal Singh Gill else 577f23576aSJagpal Singh Gill { 587f23576aSJagpal Singh Gill return sdbusplus::message::object_path( 597f23576aSJagpal Singh Gill "/xyz/openbmc_project/software/functional"); 607f23576aSJagpal Singh Gill } 617f23576aSJagpal Singh Gill } 627f23576aSJagpal Singh Gill else if (swType == biosPurpose) 637f23576aSJagpal Singh Gill { 647f23576aSJagpal Singh Gill if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS) 657f23576aSJagpal Singh Gill { 667f23576aSJagpal Singh Gill return sdbusplus::message::object_path( 677f23576aSJagpal Singh Gill "/xyz/openbmc_project/software/bios/functional"); 687f23576aSJagpal Singh Gill } 697f23576aSJagpal Singh Gill else 707f23576aSJagpal Singh Gill { 717f23576aSJagpal Singh Gill return sdbusplus::message::object_path( 727f23576aSJagpal Singh Gill "/xyz/openbmc_project/software/functional"); 737f23576aSJagpal Singh Gill } 747f23576aSJagpal Singh Gill } 757f23576aSJagpal Singh Gill else 767f23576aSJagpal Singh Gill { 777f23576aSJagpal Singh Gill BMCWEB_LOG_ERROR("No valid software path"); 787f23576aSJagpal Singh Gill return std::nullopt; 797f23576aSJagpal Singh Gill } 807f23576aSJagpal Singh Gill } 817f23576aSJagpal Singh Gill 82f8010a3dSEd Tanous inline void afterGetProperties( 83f8010a3dSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 84f8010a3dSEd Tanous const std::string& swId, bool runningImage, 85f8010a3dSEd Tanous const std::string& swVersionPurpose, 86f8010a3dSEd Tanous const std::string& activeVersionPropName, bool populateLinkToImages, 87f8010a3dSEd Tanous const boost::system::error_code& ec, 88f8010a3dSEd Tanous const dbus::utility::DBusPropertiesMap& propertiesList) 89f8010a3dSEd Tanous { 90f8010a3dSEd Tanous if (ec) 91f8010a3dSEd Tanous { 92f8010a3dSEd Tanous // Have seen the code update app delete the 93f8010a3dSEd Tanous // D-Bus object, during code update, between 94f8010a3dSEd Tanous // the call to mapper and here. Just leave 95f8010a3dSEd Tanous // these properties off if resource not 96f8010a3dSEd Tanous // found. 97fd4f088fSMyung Bae if (ec.value() != EBADR) 98f8010a3dSEd Tanous { 99fd4f088fSMyung Bae BMCWEB_LOG_ERROR("error_code = {}", ec); 100f8010a3dSEd Tanous messages::internalError(asyncResp->res); 101fd4f088fSMyung Bae } 102f8010a3dSEd Tanous return; 103f8010a3dSEd Tanous } 104f8010a3dSEd Tanous // example propertiesList 105f8010a3dSEd Tanous // a{sv} 2 "Version" s 106f8010a3dSEd Tanous // "IBM-witherspoon-OP9-v2.0.10-2.22" "Purpose" 107f8010a3dSEd Tanous // s 108f8010a3dSEd Tanous // "xyz.openbmc_project.Software.Version.VersionPurpose.Host" 109f8010a3dSEd Tanous const std::string* version = nullptr; 110f8010a3dSEd Tanous const std::string* swInvPurpose = nullptr; 111f8010a3dSEd Tanous 112f8010a3dSEd Tanous const bool success = sdbusplus::unpackPropertiesNoThrow( 113f8010a3dSEd Tanous dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose", 114f8010a3dSEd Tanous swInvPurpose, "Version", version); 115f8010a3dSEd Tanous 116f8010a3dSEd Tanous if (!success) 117f8010a3dSEd Tanous { 118f8010a3dSEd Tanous messages::internalError(asyncResp->res); 119f8010a3dSEd Tanous return; 120f8010a3dSEd Tanous } 121f8010a3dSEd Tanous 122*fa712405SDaniel Hsu if (version == nullptr) 123f8010a3dSEd Tanous { 124f8010a3dSEd Tanous messages::internalError(asyncResp->res); 125f8010a3dSEd Tanous return; 126f8010a3dSEd Tanous } 127f8010a3dSEd Tanous if (swInvPurpose == nullptr || *swInvPurpose != swVersionPurpose) 128f8010a3dSEd Tanous { 129f8010a3dSEd Tanous // Not purpose we're looking for 130f8010a3dSEd Tanous return; 131f8010a3dSEd Tanous } 132f8010a3dSEd Tanous 133f8010a3dSEd Tanous BMCWEB_LOG_DEBUG("Image ID: {}", swId); 134f8010a3dSEd Tanous BMCWEB_LOG_DEBUG("Running image: {}", runningImage); 135f8010a3dSEd Tanous BMCWEB_LOG_DEBUG("Image purpose: {}", *swInvPurpose); 136f8010a3dSEd Tanous 137f8010a3dSEd Tanous if (populateLinkToImages) 138f8010a3dSEd Tanous { 139f8010a3dSEd Tanous nlohmann::json& softwareImageMembers = 140f8010a3dSEd Tanous asyncResp->res.jsonValue["Links"]["SoftwareImages"]; 141f8010a3dSEd Tanous // Firmware images are at 142f8010a3dSEd Tanous // /redfish/v1/UpdateService/FirmwareInventory/<Id> 143f8010a3dSEd Tanous // e.g. .../FirmwareInventory/82d3ec86 144f8010a3dSEd Tanous nlohmann::json::object_t member; 145f8010a3dSEd Tanous member["@odata.id"] = boost::urls::format( 146f8010a3dSEd Tanous "/redfish/v1/UpdateService/FirmwareInventory/{}", swId); 147f8010a3dSEd Tanous softwareImageMembers.emplace_back(std::move(member)); 148f8010a3dSEd Tanous asyncResp->res.jsonValue["Links"]["SoftwareImages@odata.count"] = 149f8010a3dSEd Tanous softwareImageMembers.size(); 150f8010a3dSEd Tanous 151f8010a3dSEd Tanous if (runningImage) 152f8010a3dSEd Tanous { 153f8010a3dSEd Tanous nlohmann::json::object_t runningMember; 154f8010a3dSEd Tanous runningMember["@odata.id"] = boost::urls::format( 155f8010a3dSEd Tanous "/redfish/v1/UpdateService/FirmwareInventory/{}", swId); 156f8010a3dSEd Tanous // Create the link to the running image 157f8010a3dSEd Tanous asyncResp->res.jsonValue["Links"]["ActiveSoftwareImage"] = 158f8010a3dSEd Tanous std::move(runningMember); 159f8010a3dSEd Tanous } 160f8010a3dSEd Tanous } 161f8010a3dSEd Tanous if (!activeVersionPropName.empty() && runningImage) 162f8010a3dSEd Tanous { 163*fa712405SDaniel Hsu if (version->empty()) 164*fa712405SDaniel Hsu { 165*fa712405SDaniel Hsu BMCWEB_LOG_INFO("Version is empty for swId: {}", swId); 166*fa712405SDaniel Hsu return; 167*fa712405SDaniel Hsu } 168f8010a3dSEd Tanous asyncResp->res.jsonValue[activeVersionPropName] = *version; 169f8010a3dSEd Tanous } 170f8010a3dSEd Tanous } 171f8010a3dSEd Tanous 172f8010a3dSEd Tanous inline void afterGetSubtree( 173f8010a3dSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 174f8010a3dSEd Tanous const std::string& swVersionPurpose, 175f8010a3dSEd Tanous const std::string& activeVersionPropName, bool populateLinkToImages, 176f8010a3dSEd Tanous const std::vector<std::string>& functionalSwIds, 177f8010a3dSEd Tanous const boost::system::error_code& ec, 178f8010a3dSEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) 179f8010a3dSEd Tanous { 180f8010a3dSEd Tanous if (ec) 181f8010a3dSEd Tanous { 182fd4f088fSMyung Bae if (ec.value() != EBADR) 183fd4f088fSMyung Bae { 184f8010a3dSEd Tanous BMCWEB_LOG_ERROR("error_code = {}", ec); 185f8010a3dSEd Tanous messages::internalError(asyncResp->res); 186fd4f088fSMyung Bae } 187f8010a3dSEd Tanous return; 188f8010a3dSEd Tanous } 189f8010a3dSEd Tanous 190f8010a3dSEd Tanous BMCWEB_LOG_DEBUG("Found {} images", subtree.size()); 191f8010a3dSEd Tanous 192f8010a3dSEd Tanous for (const std::pair< 193f8010a3dSEd Tanous std::string, 194f8010a3dSEd Tanous std::vector<std::pair<std::string, std::vector<std::string>>>>& 195f8010a3dSEd Tanous obj : subtree) 196f8010a3dSEd Tanous { 197f8010a3dSEd Tanous sdbusplus::message::object_path path(obj.first); 198f8010a3dSEd Tanous std::string swId = path.filename(); 199f8010a3dSEd Tanous if (swId.empty()) 200f8010a3dSEd Tanous { 201f8010a3dSEd Tanous messages::internalError(asyncResp->res); 202f8010a3dSEd Tanous BMCWEB_LOG_ERROR("Invalid software ID"); 203f8010a3dSEd Tanous 204f8010a3dSEd Tanous return; 205f8010a3dSEd Tanous } 206f8010a3dSEd Tanous 207f8010a3dSEd Tanous bool runningImage = false; 208f8010a3dSEd Tanous // Look at Ids from 209f8010a3dSEd Tanous // /xyz/openbmc_project/software/functional 210f8010a3dSEd Tanous // to determine if this is 211f8010a3dSEd Tanous // a running image 212f8010a3dSEd Tanous if (std::ranges::find(functionalSwIds, swId) != functionalSwIds.end()) 213f8010a3dSEd Tanous { 214f8010a3dSEd Tanous runningImage = true; 215f8010a3dSEd Tanous } 216f8010a3dSEd Tanous 217f8010a3dSEd Tanous // Now grab its version 218f8010a3dSEd Tanous // info 219deae6a78SEd Tanous dbus::utility::getAllProperties( 220f8010a3dSEd Tanous *crow::connections::systemBus, obj.second[0].first, obj.first, 221f8010a3dSEd Tanous "xyz.openbmc_project.Software.Version", 222f8010a3dSEd Tanous [asyncResp, swId, runningImage, swVersionPurpose, 223f8010a3dSEd Tanous activeVersionPropName, populateLinkToImages]( 224f8010a3dSEd Tanous const boost::system::error_code& ec3, 225f8010a3dSEd Tanous const dbus::utility::DBusPropertiesMap& propertiesList) { 226f8010a3dSEd Tanous afterGetProperties(asyncResp, swId, runningImage, 227f8010a3dSEd Tanous swVersionPurpose, activeVersionPropName, 228f8010a3dSEd Tanous populateLinkToImages, ec3, propertiesList); 229f8010a3dSEd Tanous }); 230f8010a3dSEd Tanous } 231f8010a3dSEd Tanous } 232f8010a3dSEd Tanous 233f8010a3dSEd Tanous inline void afterAssociatedEndpoints( 234f8010a3dSEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 235f8010a3dSEd Tanous const std::string& swVersionPurpose, 236f8010a3dSEd Tanous const std::string& activeVersionPropName, bool populateLinkToImages, 237f8010a3dSEd Tanous const boost::system::error_code& ec, 238f8010a3dSEd Tanous const dbus::utility::MapperEndPoints& functionalSw) 239f8010a3dSEd Tanous { 240f8010a3dSEd Tanous BMCWEB_LOG_DEBUG("populateSoftwareInformation enter"); 241f8010a3dSEd Tanous if (ec) 242f8010a3dSEd Tanous { 243a5f87d48SGunnar Mills BMCWEB_LOG_DEBUG("error_code = {}", ec); 244f8010a3dSEd Tanous // No functional software for this swVersionPurpose, so just 245f8010a3dSEd Tanous return; 246f8010a3dSEd Tanous } 247f8010a3dSEd Tanous 248f8010a3dSEd Tanous if (functionalSw.empty()) 249f8010a3dSEd Tanous { 250f8010a3dSEd Tanous // Could keep going and try to populate SoftwareImages 251f8010a3dSEd Tanous // but something is seriously wrong, so just fail 252f8010a3dSEd Tanous BMCWEB_LOG_ERROR("Zero functional software in system"); 253f8010a3dSEd Tanous messages::internalError(asyncResp->res); 254f8010a3dSEd Tanous return; 255f8010a3dSEd Tanous } 256f8010a3dSEd Tanous 257f8010a3dSEd Tanous std::vector<std::string> functionalSwIds; 258f8010a3dSEd Tanous // example functionalSw: 259f8010a3dSEd Tanous // v as 2 "/xyz/openbmc_project/software/ace821ef" 260f8010a3dSEd Tanous // "/xyz/openbmc_project/software/230fb078" 261f8010a3dSEd Tanous for (const auto& sw : functionalSw) 262f8010a3dSEd Tanous { 263f8010a3dSEd Tanous sdbusplus::message::object_path path(sw); 264f8010a3dSEd Tanous std::string leaf = path.filename(); 265f8010a3dSEd Tanous if (leaf.empty()) 266f8010a3dSEd Tanous { 267f8010a3dSEd Tanous continue; 268f8010a3dSEd Tanous } 269f8010a3dSEd Tanous 270f8010a3dSEd Tanous functionalSwIds.push_back(leaf); 271f8010a3dSEd Tanous } 272f8010a3dSEd Tanous 273f8010a3dSEd Tanous constexpr std::array<std::string_view, 1> interfaces = { 274f8010a3dSEd Tanous "xyz.openbmc_project.Software.Version"}; 275f8010a3dSEd Tanous dbus::utility::getSubTree( 276f8010a3dSEd Tanous "/xyz/openbmc_project/software", 0, interfaces, 277f8010a3dSEd Tanous [asyncResp, swVersionPurpose, activeVersionPropName, 278f8010a3dSEd Tanous populateLinkToImages, functionalSwIds]( 279f8010a3dSEd Tanous const boost::system::error_code& ec2, 280f8010a3dSEd Tanous const dbus::utility::MapperGetSubTreeResponse& subtree) { 281f8010a3dSEd Tanous afterGetSubtree(asyncResp, swVersionPurpose, activeVersionPropName, 282f8010a3dSEd Tanous populateLinkToImages, functionalSwIds, ec2, 283f8010a3dSEd Tanous subtree); 284f8010a3dSEd Tanous }); 285f8010a3dSEd Tanous } 286f8010a3dSEd Tanous 287eee0013eSWilly Tu /** 288eee0013eSWilly Tu * @brief Populate the running software version and image links 289eee0013eSWilly Tu * 290ac106bf6SEd Tanous * @param[i,o] asyncResp Async response object 291eee0013eSWilly Tu * @param[i] swVersionPurpose Indicates what target to look for 292ac106bf6SEd Tanous * @param[i] activeVersionPropName Index in asyncResp->res.jsonValue to write 293eee0013eSWilly Tu * the running software version to 294ac106bf6SEd Tanous * @param[i] populateLinkToImages Populate asyncResp->res "Links" 295eee0013eSWilly Tu * "ActiveSoftwareImage" with a link to the running software image and 296eee0013eSWilly Tu * "SoftwareImages" with a link to the all its software images 297eee0013eSWilly Tu * 298eee0013eSWilly Tu * @return void 299eee0013eSWilly Tu */ 300ac106bf6SEd Tanous inline void populateSoftwareInformation( 301ac106bf6SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 302eee0013eSWilly Tu const std::string& swVersionPurpose, 303ac106bf6SEd Tanous const std::string& activeVersionPropName, const bool populateLinkToImages) 304eee0013eSWilly Tu { 3057f23576aSJagpal Singh Gill auto swPath = getFunctionalSoftwarePath(swVersionPurpose); 3067f23576aSJagpal Singh Gill if (!swPath) 3077f23576aSJagpal Singh Gill { 3087f23576aSJagpal Singh Gill BMCWEB_LOG_ERROR("Invalid software type"); 3097f23576aSJagpal Singh Gill messages::internalError(asyncResp->res); 3107f23576aSJagpal Singh Gill return; 3117f23576aSJagpal Singh Gill } 312eee0013eSWilly Tu // Used later to determine running (known on Redfish as active) Sw images 313a4eb761aSGeorge Liu dbus::utility::getAssociationEndPoints( 3147f23576aSJagpal Singh Gill swPath.value().str, 315ac106bf6SEd Tanous [asyncResp, swVersionPurpose, activeVersionPropName, 316ac106bf6SEd Tanous populateLinkToImages]( 317a4eb761aSGeorge Liu const boost::system::error_code& ec, 318a4eb761aSGeorge Liu const dbus::utility::MapperEndPoints& functionalSw) { 319f8010a3dSEd Tanous afterAssociatedEndpoints(asyncResp, swVersionPurpose, 320f8010a3dSEd Tanous activeVersionPropName, 321f8010a3dSEd Tanous populateLinkToImages, ec, functionalSw); 322eee0013eSWilly Tu }); 323eee0013eSWilly Tu } 324eee0013eSWilly Tu 325eee0013eSWilly Tu /** 326eee0013eSWilly Tu * @brief Translate input swState to Redfish state 327eee0013eSWilly Tu * 328eee0013eSWilly Tu * This function will return the corresponding Redfish state 329eee0013eSWilly Tu * 330eee0013eSWilly Tu * @param[i] swState The OpenBMC software state 331eee0013eSWilly Tu * 332eee0013eSWilly Tu * @return The corresponding Redfish state 333eee0013eSWilly Tu */ 3340ec8b83dSEd Tanous inline resource::State getRedfishSwState(const std::string& swState) 335eee0013eSWilly Tu { 336eee0013eSWilly Tu if (swState == "xyz.openbmc_project.Software.Activation.Activations.Active") 337eee0013eSWilly Tu { 3380ec8b83dSEd Tanous return resource::State::Enabled; 339eee0013eSWilly Tu } 340eee0013eSWilly Tu if (swState == "xyz.openbmc_project.Software.Activation." 341eee0013eSWilly Tu "Activations.Activating") 342eee0013eSWilly Tu { 3430ec8b83dSEd Tanous return resource::State::Updating; 344eee0013eSWilly Tu } 345eee0013eSWilly Tu if (swState == "xyz.openbmc_project.Software.Activation." 346eee0013eSWilly Tu "Activations.StandbySpare") 347eee0013eSWilly Tu { 3480ec8b83dSEd Tanous return resource::State::StandbySpare; 349eee0013eSWilly Tu } 35062598e31SEd Tanous BMCWEB_LOG_DEBUG("Default sw state {} to Disabled", swState); 3510ec8b83dSEd Tanous return resource::State::Disabled; 352eee0013eSWilly Tu } 353eee0013eSWilly Tu 354eee0013eSWilly Tu /** 355eee0013eSWilly Tu * @brief Translate input swState to Redfish health state 356eee0013eSWilly Tu * 357eee0013eSWilly Tu * This function will return the corresponding Redfish health state 358eee0013eSWilly Tu * 359eee0013eSWilly Tu * @param[i] swState The OpenBMC software state 360eee0013eSWilly Tu * 361eee0013eSWilly Tu * @return The corresponding Redfish health state 362eee0013eSWilly Tu */ 363eee0013eSWilly Tu inline std::string getRedfishSwHealth(const std::string& swState) 364eee0013eSWilly Tu { 365eee0013eSWilly Tu if ((swState == 366eee0013eSWilly Tu "xyz.openbmc_project.Software.Activation.Activations.Active") || 367eee0013eSWilly Tu (swState == "xyz.openbmc_project.Software.Activation.Activations." 368eee0013eSWilly Tu "Activating") || 369eee0013eSWilly Tu (swState == 370eee0013eSWilly Tu "xyz.openbmc_project.Software.Activation.Activations.Ready")) 371eee0013eSWilly Tu { 372eee0013eSWilly Tu return "OK"; 373eee0013eSWilly Tu } 37462598e31SEd Tanous BMCWEB_LOG_DEBUG("Sw state {} to Warning", swState); 375eee0013eSWilly Tu return "Warning"; 376eee0013eSWilly Tu } 377eee0013eSWilly Tu 378eee0013eSWilly Tu /** 379c9bd0924SGunnar Mills * @brief Put LowestSupportedVersion of input swId into json response 380c9bd0924SGunnar Mills * 381c9bd0924SGunnar Mills * This function will put the MinimumVersion from D-Bus of the input 382c9bd0924SGunnar Mills * software id to ["LowestSupportedVersion"]. 383c9bd0924SGunnar Mills * 384c9bd0924SGunnar Mills * @param[i,o] asyncResp Async response object 385c9bd0924SGunnar Mills * @param[i] swId The software ID to get Minimum Version for 386c9bd0924SGunnar Mills * @param[i] dbusSvc The dbus service implementing the software object 387c9bd0924SGunnar Mills * 388c9bd0924SGunnar Mills * @return void 389c9bd0924SGunnar Mills */ 390c9bd0924SGunnar Mills inline void getSwMinimumVersion( 391c9bd0924SGunnar Mills const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 392c9bd0924SGunnar Mills const std::shared_ptr<std::string>& swId, const std::string& dbusSvc) 393c9bd0924SGunnar Mills { 394c9bd0924SGunnar Mills BMCWEB_LOG_DEBUG("getSwMinimumVersion: svc {}, swId {}", dbusSvc, *swId); 395c9bd0924SGunnar Mills 396c9bd0924SGunnar Mills sdbusplus::message::object_path path("/xyz/openbmc_project/software"); 397c9bd0924SGunnar Mills path /= *swId; 398c9bd0924SGunnar Mills 399c9bd0924SGunnar Mills dbus::utility::getProperty<std::string>( 400c9bd0924SGunnar Mills dbusSvc, path, "xyz.openbmc_project.Software.MinimumVersion", 401c9bd0924SGunnar Mills "MinimumVersion", 402c9bd0924SGunnar Mills [asyncResp](const boost::system::error_code& ec, 403c9bd0924SGunnar Mills const std::string& swMinimumVersion) { 404c9bd0924SGunnar Mills if (ec) 405c9bd0924SGunnar Mills { 406c9bd0924SGunnar Mills // not all software has this interface and it is not critical 407c9bd0924SGunnar Mills return; 408c9bd0924SGunnar Mills } 409c9bd0924SGunnar Mills 410c9bd0924SGunnar Mills BMCWEB_LOG_DEBUG("getSwMinimumVersion: MinimumVersion {}", 411c9bd0924SGunnar Mills swMinimumVersion); 412c9bd0924SGunnar Mills 413c9bd0924SGunnar Mills asyncResp->res.jsonValue["LowestSupportedVersion"] = 414c9bd0924SGunnar Mills swMinimumVersion; 415c9bd0924SGunnar Mills }); 416c9bd0924SGunnar Mills } 417c9bd0924SGunnar Mills 418c9bd0924SGunnar Mills /** 419eee0013eSWilly Tu * @brief Put status of input swId into json response 420eee0013eSWilly Tu * 421eee0013eSWilly Tu * This function will put the appropriate Redfish state of the input 422eee0013eSWilly Tu * software id to ["Status"]["State"] within the json response 423eee0013eSWilly Tu * 424ac106bf6SEd Tanous * @param[i,o] asyncResp Async response object 425eee0013eSWilly Tu * @param[i] swId The software ID to get status for 426eee0013eSWilly Tu * @param[i] dbusSvc The dbus service implementing the software object 427eee0013eSWilly Tu * 428eee0013eSWilly Tu * @return void 429eee0013eSWilly Tu */ 430eee0013eSWilly Tu inline void getSwStatus(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 431eee0013eSWilly Tu const std::shared_ptr<std::string>& swId, 432eee0013eSWilly Tu const std::string& dbusSvc) 433eee0013eSWilly Tu { 43462598e31SEd Tanous BMCWEB_LOG_DEBUG("getSwStatus: swId {} svc {}", *swId, dbusSvc); 435eee0013eSWilly Tu 436deae6a78SEd Tanous dbus::utility::getAllProperties( 437deae6a78SEd Tanous dbusSvc, "/xyz/openbmc_project/software/" + *swId, 438d1bde9e5SKrzysztof Grobelny "xyz.openbmc_project.Software.Activation", 439eee0013eSWilly Tu [asyncResp, 4408b24275dSEd Tanous swId](const boost::system::error_code& ec, 441eee0013eSWilly Tu const dbus::utility::DBusPropertiesMap& propertiesList) { 4428b24275dSEd Tanous if (ec) 443eee0013eSWilly Tu { 444eee0013eSWilly Tu // not all swtypes are updateable, this is ok 445539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 446539d8c6bSEd Tanous resource::State::Enabled; 447eee0013eSWilly Tu return; 448eee0013eSWilly Tu } 449d1bde9e5SKrzysztof Grobelny 450eee0013eSWilly Tu const std::string* swInvActivation = nullptr; 451d1bde9e5SKrzysztof Grobelny 452d1bde9e5SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 453d1bde9e5SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), propertiesList, "Activation", 454d1bde9e5SKrzysztof Grobelny swInvActivation); 455d1bde9e5SKrzysztof Grobelny 456d1bde9e5SKrzysztof Grobelny if (!success) 457eee0013eSWilly Tu { 458d1bde9e5SKrzysztof Grobelny messages::internalError(asyncResp->res); 459d1bde9e5SKrzysztof Grobelny return; 460eee0013eSWilly Tu } 461eee0013eSWilly Tu 462eee0013eSWilly Tu if (swInvActivation == nullptr) 463eee0013eSWilly Tu { 464eee0013eSWilly Tu messages::internalError(asyncResp->res); 465eee0013eSWilly Tu return; 466eee0013eSWilly Tu } 467d1bde9e5SKrzysztof Grobelny 46862598e31SEd Tanous BMCWEB_LOG_DEBUG("getSwStatus: Activation {}", *swInvActivation); 469eee0013eSWilly Tu asyncResp->res.jsonValue["Status"]["State"] = 470eee0013eSWilly Tu getRedfishSwState(*swInvActivation); 471eee0013eSWilly Tu asyncResp->res.jsonValue["Status"]["Health"] = 472eee0013eSWilly Tu getRedfishSwHealth(*swInvActivation); 473d1bde9e5SKrzysztof Grobelny }); 474eee0013eSWilly Tu } 475eee0013eSWilly Tu 476c018f705SJagpal Singh Gill inline void handleUpdateableEndpoints( 477c018f705SJagpal Singh Gill const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 478c018f705SJagpal Singh Gill const std::shared_ptr<std::string>& swId, 479c018f705SJagpal Singh Gill const boost::system::error_code& ec, 480c018f705SJagpal Singh Gill const dbus::utility::MapperEndPoints& objPaths) 481c018f705SJagpal Singh Gill { 482c018f705SJagpal Singh Gill if (ec) 483c018f705SJagpal Singh Gill { 484c018f705SJagpal Singh Gill BMCWEB_LOG_DEBUG(" error_code = {} error msg = {}", ec, ec.message()); 485c018f705SJagpal Singh Gill // System can exist with no updateable software, 486c018f705SJagpal Singh Gill // so don't throw error here. 487c018f705SJagpal Singh Gill return; 488c018f705SJagpal Singh Gill } 489c018f705SJagpal Singh Gill sdbusplus::message::object_path reqSwObjPath( 490c018f705SJagpal Singh Gill "/xyz/openbmc_project/software"); 491c018f705SJagpal Singh Gill reqSwObjPath = reqSwObjPath / *swId; 492c018f705SJagpal Singh Gill 493c018f705SJagpal Singh Gill if (std::ranges::find(objPaths, reqSwObjPath.str) != objPaths.end()) 494c018f705SJagpal Singh Gill { 495c018f705SJagpal Singh Gill asyncResp->res.jsonValue["Updateable"] = true; 496c018f705SJagpal Singh Gill return; 497c018f705SJagpal Singh Gill } 498c018f705SJagpal Singh Gill } 499c018f705SJagpal Singh Gill 500504af5a0SPatrick Williams inline void handleUpdateableObject( 501504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 502c018f705SJagpal Singh Gill const boost::system::error_code& ec, 503c018f705SJagpal Singh Gill const dbus::utility::MapperGetObject& objectInfo) 504c018f705SJagpal Singh Gill { 505c018f705SJagpal Singh Gill if (ec) 506c018f705SJagpal Singh Gill { 507c018f705SJagpal Singh Gill BMCWEB_LOG_DEBUG(" error_code = {} error msg = {}", ec, ec.message()); 508c018f705SJagpal Singh Gill // System can exist with no updateable software, 509c018f705SJagpal Singh Gill // so don't throw error here. 510c018f705SJagpal Singh Gill return; 511c018f705SJagpal Singh Gill } 512c018f705SJagpal Singh Gill if (objectInfo.empty()) 513c018f705SJagpal Singh Gill { 514c018f705SJagpal Singh Gill BMCWEB_LOG_DEBUG("No updateable software found"); 515c018f705SJagpal Singh Gill // System can exist with no updateable software, 516c018f705SJagpal Singh Gill // so don't throw error here. 517c018f705SJagpal Singh Gill return; 518c018f705SJagpal Singh Gill } 519c018f705SJagpal Singh Gill asyncResp->res.jsonValue["Updateable"] = true; 520c018f705SJagpal Singh Gill } 521c018f705SJagpal Singh Gill 522eee0013eSWilly Tu /** 523eee0013eSWilly Tu * @brief Updates programmable status of input swId into json response 524eee0013eSWilly Tu * 525eee0013eSWilly Tu * This function checks whether software inventory component 526eee0013eSWilly Tu * can be programmable or not and fill's the "Updatable" 527eee0013eSWilly Tu * Property. 528eee0013eSWilly Tu * 529eee0013eSWilly Tu * @param[i,o] asyncResp Async response object 530eee0013eSWilly Tu * @param[i] swId The software ID 531eee0013eSWilly Tu */ 532504af5a0SPatrick Williams inline void getSwUpdatableStatus( 533504af5a0SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 534eee0013eSWilly Tu const std::shared_ptr<std::string>& swId) 535eee0013eSWilly Tu { 536c018f705SJagpal Singh Gill if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS) 537c018f705SJagpal Singh Gill { 538c018f705SJagpal Singh Gill sdbusplus::message::object_path swObjectPath( 539c018f705SJagpal Singh Gill "/xyz/openbmc_project/software"); 540c018f705SJagpal Singh Gill swObjectPath = swObjectPath / *swId; 541c018f705SJagpal Singh Gill constexpr std::array<std::string_view, 1> interfaces = { 542c018f705SJagpal Singh Gill "xyz.openbmc_project.Software.Update"}; 543c018f705SJagpal Singh Gill dbus::utility::getDbusObject( 544c018f705SJagpal Singh Gill swObjectPath.str, interfaces, 545c018f705SJagpal Singh Gill std::bind_front(handleUpdateableObject, asyncResp)); 546c018f705SJagpal Singh Gill } 547c018f705SJagpal Singh Gill else 548c018f705SJagpal Singh Gill { 5496c3e9451SGeorge Liu dbus::utility::getAssociationEndPoints( 550eee0013eSWilly Tu "/xyz/openbmc_project/software/updateable", 551c018f705SJagpal Singh Gill std::bind_front(handleUpdateableEndpoints, asyncResp, swId)); 552eee0013eSWilly Tu } 553eee0013eSWilly Tu } 554eee0013eSWilly Tu 555eee0013eSWilly Tu } // namespace sw_util 556eee0013eSWilly Tu } // namespace redfish 557