Refactor swutils to break down in to functions
Prior to this patch, this is one of the offenders in the bmcweb
codebase for complexity. It does 4 levels of nested lambdas in a single
method, making it basically impossible to read. As a side note, this
came up because of an unrelated refactoring, and clang-format seemed to
have just given up, and formatted this block in a nonsensical way.
Tested: Inspection only. Don't have systems that use this code.
Change-Id: Ica5fa97bae6be2ba1d83d2ad01eeff85bdff6649
Signed-off-by: Ed Tanous <etanous@nvidia.com>
diff --git a/redfish-core/include/utils/sw_utils.hpp b/redfish-core/include/utils/sw_utils.hpp
index ad0994e..ef3163b 100644
--- a/redfish-core/include/utils/sw_utils.hpp
+++ b/redfish-core/include/utils/sw_utils.hpp
@@ -67,6 +67,207 @@
}
}
+inline void afterGetProperties(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& swId, bool runningImage,
+ const std::string& swVersionPurpose,
+ const std::string& activeVersionPropName, bool populateLinkToImages,
+ const boost::system::error_code& ec,
+ const dbus::utility::DBusPropertiesMap& propertiesList)
+{
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR("error_code = {}", ec);
+ BMCWEB_LOG_ERROR("error msg = {}", ec.message());
+ // Have seen the code update app delete the
+ // D-Bus object, during code update, between
+ // the call to mapper and here. Just leave
+ // these properties off if resource not
+ // found.
+ if (ec.value() == EBADR)
+ {
+ return;
+ }
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ // example propertiesList
+ // a{sv} 2 "Version" s
+ // "IBM-witherspoon-OP9-v2.0.10-2.22" "Purpose"
+ // s
+ // "xyz.openbmc_project.Software.Version.VersionPurpose.Host"
+ const std::string* version = nullptr;
+ const std::string* swInvPurpose = nullptr;
+
+ const bool success = sdbusplus::unpackPropertiesNoThrow(
+ dbus_utils::UnpackErrorPrinter(), propertiesList, "Purpose",
+ swInvPurpose, "Version", version);
+
+ if (!success)
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ if (version == nullptr || version->empty())
+ {
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ if (swInvPurpose == nullptr || *swInvPurpose != swVersionPurpose)
+ {
+ // Not purpose we're looking for
+ return;
+ }
+
+ BMCWEB_LOG_DEBUG("Image ID: {}", swId);
+ BMCWEB_LOG_DEBUG("Running image: {}", runningImage);
+ BMCWEB_LOG_DEBUG("Image purpose: {}", *swInvPurpose);
+
+ if (populateLinkToImages)
+ {
+ nlohmann::json& softwareImageMembers =
+ asyncResp->res.jsonValue["Links"]["SoftwareImages"];
+ // Firmware images are at
+ // /redfish/v1/UpdateService/FirmwareInventory/<Id>
+ // e.g. .../FirmwareInventory/82d3ec86
+ nlohmann::json::object_t member;
+ member["@odata.id"] = boost::urls::format(
+ "/redfish/v1/UpdateService/FirmwareInventory/{}", swId);
+ softwareImageMembers.emplace_back(std::move(member));
+ asyncResp->res.jsonValue["Links"]["SoftwareImages@odata.count"] =
+ softwareImageMembers.size();
+
+ if (runningImage)
+ {
+ nlohmann::json::object_t runningMember;
+ runningMember["@odata.id"] = boost::urls::format(
+ "/redfish/v1/UpdateService/FirmwareInventory/{}", swId);
+ // Create the link to the running image
+ asyncResp->res.jsonValue["Links"]["ActiveSoftwareImage"] =
+ std::move(runningMember);
+ }
+ }
+ if (!activeVersionPropName.empty() && runningImage)
+ {
+ asyncResp->res.jsonValue[activeVersionPropName] = *version;
+ }
+}
+
+inline void afterGetSubtree(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& swVersionPurpose,
+ const std::string& activeVersionPropName, bool populateLinkToImages,
+ const std::vector<std::string>& functionalSwIds,
+ const boost::system::error_code& ec,
+ const dbus::utility::MapperGetSubTreeResponse& subtree)
+{
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR("error_code = {}", ec);
+ BMCWEB_LOG_ERROR("error msg = {}", ec.message());
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ BMCWEB_LOG_DEBUG("Found {} images", subtree.size());
+
+ for (const std::pair<
+ std::string,
+ std::vector<std::pair<std::string, std::vector<std::string>>>>&
+ obj : subtree)
+ {
+ sdbusplus::message::object_path path(obj.first);
+ std::string swId = path.filename();
+ if (swId.empty())
+ {
+ messages::internalError(asyncResp->res);
+ BMCWEB_LOG_ERROR("Invalid software ID");
+
+ return;
+ }
+
+ bool runningImage = false;
+ // Look at Ids from
+ // /xyz/openbmc_project/software/functional
+ // to determine if this is
+ // a running image
+ if (std::ranges::find(functionalSwIds, swId) != functionalSwIds.end())
+ {
+ runningImage = true;
+ }
+
+ // Now grab its version
+ // info
+ sdbusplus::asio::getAllProperties(
+ *crow::connections::systemBus, obj.second[0].first, obj.first,
+ "xyz.openbmc_project.Software.Version",
+ [asyncResp, swId, runningImage, swVersionPurpose,
+ activeVersionPropName, populateLinkToImages](
+ const boost::system::error_code& ec3,
+ const dbus::utility::DBusPropertiesMap& propertiesList) {
+ afterGetProperties(asyncResp, swId, runningImage,
+ swVersionPurpose, activeVersionPropName,
+ populateLinkToImages, ec3, propertiesList);
+ });
+ }
+}
+
+inline void afterAssociatedEndpoints(
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ const std::string& swVersionPurpose,
+ const std::string& activeVersionPropName, bool populateLinkToImages,
+ const boost::system::error_code& ec,
+ const dbus::utility::MapperEndPoints& functionalSw)
+{
+ BMCWEB_LOG_DEBUG("populateSoftwareInformation enter");
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR("error_code = {}", ec);
+ BMCWEB_LOG_ERROR("error msg = {}", ec.message());
+ // No functional software for this swVersionPurpose, so just
+ return;
+ }
+
+ if (functionalSw.empty())
+ {
+ // Could keep going and try to populate SoftwareImages
+ // but something is seriously wrong, so just fail
+ BMCWEB_LOG_ERROR("Zero functional software in system");
+ messages::internalError(asyncResp->res);
+ return;
+ }
+
+ std::vector<std::string> functionalSwIds;
+ // example functionalSw:
+ // v as 2 "/xyz/openbmc_project/software/ace821ef"
+ // "/xyz/openbmc_project/software/230fb078"
+ for (const auto& sw : functionalSw)
+ {
+ sdbusplus::message::object_path path(sw);
+ std::string leaf = path.filename();
+ if (leaf.empty())
+ {
+ continue;
+ }
+
+ functionalSwIds.push_back(leaf);
+ }
+
+ constexpr std::array<std::string_view, 1> interfaces = {
+ "xyz.openbmc_project.Software.Version"};
+ dbus::utility::getSubTree(
+ "/xyz/openbmc_project/software", 0, interfaces,
+ [asyncResp, swVersionPurpose, activeVersionPropName,
+ populateLinkToImages, functionalSwIds](
+ const boost::system::error_code& ec2,
+ const dbus::utility::MapperGetSubTreeResponse& subtree) {
+ afterGetSubtree(asyncResp, swVersionPurpose, activeVersionPropName,
+ populateLinkToImages, functionalSwIds, ec2,
+ subtree);
+ });
+}
+
/**
* @brief Populate the running software version and image links
*
@@ -99,193 +300,9 @@
populateLinkToImages](
const boost::system::error_code& ec,
const dbus::utility::MapperEndPoints& functionalSw) {
- BMCWEB_LOG_DEBUG("populateSoftwareInformation enter");
- if (ec)
- {
- BMCWEB_LOG_ERROR("error_code = {}", ec);
- BMCWEB_LOG_ERROR("error msg = {}", ec.message());
- // No functional software for this swVersionPurpose, so just
- // return
- return;
- }
-
- if (functionalSw.empty())
- {
- // Could keep going and try to populate SoftwareImages but
- // something is seriously wrong, so just fail
- BMCWEB_LOG_ERROR("Zero functional software in system");
- messages::internalError(asyncResp->res);
- return;
- }
-
- std::vector<std::string> functionalSwIds;
- // example functionalSw:
- // v as 2 "/xyz/openbmc_project/software/ace821ef"
- // "/xyz/openbmc_project/software/230fb078"
- for (const auto& sw : functionalSw)
- {
- sdbusplus::message::object_path path(sw);
- std::string leaf = path.filename();
- if (leaf.empty())
- {
- continue;
- }
-
- functionalSwIds.push_back(leaf);
- }
-
- constexpr std::array<std::string_view, 1> interfaces = {
- "xyz.openbmc_project.Software.Version"};
- dbus::utility::getSubTree(
- "/xyz/openbmc_project/software", 0, interfaces,
- [asyncResp, swVersionPurpose, activeVersionPropName,
- populateLinkToImages, functionalSwIds](
- const boost::system::error_code& ec2,
- const dbus::utility::MapperGetSubTreeResponse& subtree) {
- if (ec2)
- {
- BMCWEB_LOG_ERROR("error_code = {}", ec2);
- BMCWEB_LOG_ERROR("error msg = {}", ec2.message());
- messages::internalError(asyncResp->res);
- return;
- }
-
- BMCWEB_LOG_DEBUG("Found {} images", subtree.size());
-
- for (const std::pair<
- std::string,
- std::vector<std::pair<
- std::string, std::vector<std::string>>>>& obj :
- subtree)
- {
- sdbusplus::message::object_path path(obj.first);
- std::string swId = path.filename();
- if (swId.empty())
- {
- messages::internalError(asyncResp->res);
- BMCWEB_LOG_ERROR("Invalid software ID");
-
- return;
- }
-
- bool runningImage = false;
- // Look at Ids from
- // /xyz/openbmc_project/software/functional
- // to determine if this is a running image
- if (std::ranges::find(functionalSwIds, swId) !=
- functionalSwIds.end())
- {
- runningImage = true;
- }
-
- // Now grab its version info
- sdbusplus::asio::getAllProperties(
- *crow::connections::systemBus, obj.second[0].first,
- obj.first, "xyz.openbmc_project.Software.Version",
- [asyncResp, swId, runningImage, swVersionPurpose,
- activeVersionPropName, populateLinkToImages](
- const boost::system::error_code& ec3,
- const dbus::utility::DBusPropertiesMap&
- propertiesList) {
- if (ec3)
- {
- BMCWEB_LOG_ERROR("error_code = {}", ec3);
- BMCWEB_LOG_ERROR("error msg = {}",
- ec3.message());
- // Have seen the code update app delete the
- // D-Bus object, during code update, between
- // the call to mapper and here. Just leave
- // these properties off if resource not
- // found.
- if (ec3.value() == EBADR)
- {
- return;
- }
- messages::internalError(asyncResp->res);
- return;
- }
- // example propertiesList
- // a{sv} 2 "Version" s
- // "IBM-witherspoon-OP9-v2.0.10-2.22" "Purpose"
- // s
- // "xyz.openbmc_project.Software.Version.VersionPurpose.Host"
- const std::string* version = nullptr;
- const std::string* swInvPurpose = nullptr;
-
- const bool success =
- sdbusplus::unpackPropertiesNoThrow(
- dbus_utils::UnpackErrorPrinter(),
- propertiesList, "Purpose", swInvPurpose,
- "Version", version);
-
- if (!success)
- {
- messages::internalError(asyncResp->res);
- return;
- }
-
- if (version == nullptr || version->empty())
- {
- messages::internalError(asyncResp->res);
- return;
- }
- if (swInvPurpose == nullptr ||
- *swInvPurpose != swVersionPurpose)
- {
- // Not purpose we're looking for
- return;
- }
-
- BMCWEB_LOG_DEBUG("Image ID: {}", swId);
- BMCWEB_LOG_DEBUG("Running image: {}",
- runningImage);
- BMCWEB_LOG_DEBUG("Image purpose: {}",
- *swInvPurpose);
-
- if (populateLinkToImages)
- {
- nlohmann::json& softwareImageMembers =
- asyncResp->res
- .jsonValue["Links"]
- ["SoftwareImages"];
- // Firmware images are at
- // /redfish/v1/UpdateService/FirmwareInventory/<Id>
- // e.g. .../FirmwareInventory/82d3ec86
- nlohmann::json::object_t member;
- member["@odata.id"] = boost::urls::format(
- "/redfish/v1/UpdateService/FirmwareInventory/{}",
- swId);
- softwareImageMembers.emplace_back(
- std::move(member));
- asyncResp->res.jsonValue
- ["Links"]
- ["SoftwareImages@odata.count"] =
- softwareImageMembers.size();
-
- if (runningImage)
- {
- nlohmann::json::object_t runningMember;
- runningMember["@odata.id"] =
- boost::urls::format(
- "/redfish/v1/UpdateService/FirmwareInventory/{}",
- swId);
- // Create the link to the running image
- asyncResp->res
- .jsonValue["Links"]
- ["ActiveSoftwareImage"] =
- std::move(runningMember);
- }
- }
- if (!activeVersionPropName.empty() &&
- runningImage)
- {
- asyncResp->res
- .jsonValue[activeVersionPropName] =
- *version;
- }
- });
- }
- });
+ afterAssociatedEndpoints(asyncResp, swVersionPurpose,
+ activeVersionPropName,
+ populateLinkToImages, ec, functionalSw);
});
}