diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp index c2e336e86..bedfe0030 100644 --- a/redfish-core/include/redfish.hpp +++ b/redfish-core/include/redfish.hpp @@ -4,7 +4,6 @@ #include "app.hpp" #include "async_resp.hpp" -#include "http_request.hpp" #include "redfish_oem_routing.hpp" #include "sub_request.hpp" #include "verb.hpp" @@ -48,10 +47,9 @@ class RedfishService } void handleSubRoute( - const crow::Request& req, + const std::shared_ptr& subReq, const std::shared_ptr& asyncResp) const { - auto subReq = std::make_shared(req); if (!subReq->needHandling()) { return; diff --git a/redfish-core/include/utils/manager_utils.hpp b/redfish-core/include/utils/manager_utils.hpp index 7430fe323..a06dd1681 100644 --- a/redfish-core/include/utils/manager_utils.hpp +++ b/redfish-core/include/utils/manager_utils.hpp @@ -2,19 +2,28 @@ // SPDX-FileCopyrightText: Copyright OpenBMC Authors #pragma once +#include "bmcweb_config.h" + #include "async_resp.hpp" +#include "dbus_utility.hpp" #include "error_messages.hpp" +#include "logging.hpp" #include "persistent_data.hpp" #include +#include #include +#include #include #include +#include namespace redfish { +constexpr std::array bmcInterfaces = { + "xyz.openbmc_project.Inventory.Item.Bmc"}; namespace manager_utils { @@ -60,6 +69,69 @@ inline void getServiceIdentification( asyncResp->res.jsonValue["ServiceIdentification"] = serviceIdentification; } +inline void afterGetValidManagerPath( + const std::shared_ptr& asyncResp, + const std::string& managerId, + const std::function< + void(const std::string& managerPath, + const dbus::utility::MapperServiceMap& serviceMap)>& callback, + const boost::system::error_code& ec, + const dbus::utility::MapperGetSubTreeResponse& subtree) +{ + if (ec) + { + if (ec == boost::system::errc::io_error) + { + // Not found + BMCWEB_LOG_WARNING("Manager {} not found", managerId); + messages::resourceNotFound(asyncResp->res, "Manager", managerId); + return; + } + BMCWEB_LOG_ERROR("D-Bus response error {}", ec.value()); + messages::internalError(asyncResp->res); + return; + } + if (subtree.empty()) + { + BMCWEB_LOG_WARNING("Manager {} not found", managerId); + messages::resourceNotFound(asyncResp->res, "Manager", managerId); + return; + } + + if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) + { + messages::resourceNotFound(asyncResp->res, "Manager", managerId); + return; + } + // Assume only 1 bmc D-Bus object + // Throw an error if there is more than 1 + if (subtree.size() > 1) + { + BMCWEB_LOG_ERROR("Found more than 1 bmc D-Bus object!"); + messages::internalError(asyncResp->res); + return; + } + + callback(subtree[0].first, subtree[0].second); +} + +inline void getValidManagerPath( + const std::shared_ptr& asyncResp, + const std::string& managerId, + std::function&& + callback) +{ + dbus::utility::getSubTree( + "/xyz/openbmc_project/inventory", 0, bmcInterfaces, + [asyncResp, managerId, callback = std::move(callback)]( + const boost::system::error_code& ec, + const dbus::utility::MapperGetSubTreeResponse& subtree) { + afterGetValidManagerPath(asyncResp, managerId, callback, ec, + subtree); + }); +} + } // namespace manager_utils } // namespace redfish diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp index 540943a83..bb3e8dfc8 100644 --- a/redfish-core/lib/managers.hpp +++ b/redfish-core/lib/managers.hpp @@ -22,6 +22,7 @@ #include "redfish.hpp" #include "redfish_util.hpp" #include "registries/privilege_registry.hpp" +#include "sub_request.hpp" #include "utils/dbus_utils.hpp" #include "utils/json_utils.hpp" #include "utils/manager_utils.hpp" @@ -42,7 +43,6 @@ #include #include -#include #include #include #include @@ -58,63 +58,6 @@ namespace redfish { -inline void handleSetLocationIndicatorActive( - const std::shared_ptr& asyncResp, - bool locationIndicatorActive, const std::string& managerId, - const boost::system::error_code& ec, - const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) -{ - if (ec) - { - if (ec == boost::system::errc::io_error) - { - // Not found - BMCWEB_LOG_WARNING("Manager {} not found", managerId); - messages::resourceNotFound(asyncResp->res, "Manager", managerId); - return; - } - BMCWEB_LOG_ERROR("D-Bus response error {}", ec.value()); - messages::internalError(asyncResp->res); - return; - } - if (subtreePaths.empty()) - { - BMCWEB_LOG_WARNING("Manager {} not found", managerId); - messages::resourceNotFound(asyncResp->res, "Manager", managerId); - return; - } - // Assume only 1 bmc D-Bus object - // Throw an error if there is more than 1 - if (subtreePaths.size() != 1) - { - BMCWEB_LOG_ERROR("Found {} Bmc D-Bus paths", subtreePaths.size()); - messages::internalError(asyncResp->res); - return; - } - - setLocationIndicatorActive(asyncResp, subtreePaths[0], - locationIndicatorActive); -} - -/** - * Set the locationIndicatorActive. - * - * @param[in,out] asyncResp Async HTTP response. - * @param[in] locationIndicatorActive Value of the property - */ -inline void setLocationIndicatorActiveState( - const std::shared_ptr& asyncResp, - bool locationIndicatorActive, const std::string& managerId) -{ - // GetSubTree on all interfaces which provide info about a Manager - constexpr std::array interfaces = { - "xyz.openbmc_project.Inventory.Item.Bmc"}; - dbus::utility::getSubTreePaths( - "/xyz/openbmc_project/inventory", 0, interfaces, - std::bind_front(handleSetLocationIndicatorActive, asyncResp, - locationIndicatorActive, managerId)); -} - inline std::string getBMCUpdateServiceName() { if constexpr (BMCWEB_REDFISH_UPDATESERVICE_USE_DBUS) @@ -701,9 +644,11 @@ inline void getPhysicalAssets( } } -inline void getManagerData(const std::shared_ptr& asyncResp, - const std::string& managerPath, - const dbus::utility::MapperServiceMap& serviceMap) +inline void getManagerData( + RedfishService& rfService, const std::shared_ptr& subReq, + const std::shared_ptr& asyncResp, + const std::string& managerId, const std::string& managerPath, + const dbus::utility::MapperServiceMap& serviceMap) { if (managerPath.empty() || serviceMap.size() != 1) { @@ -712,102 +657,12 @@ inline void getManagerData(const std::shared_ptr& asyncResp, return; } - for (const auto& [connectionName, interfaces] : serviceMap) - { - for (const auto& interfaceName : interfaces) - { - if (interfaceName == - "xyz.openbmc_project.Inventory.Decorator.Asset") - { - dbus::utility::getAllProperties( - *crow::connections::systemBus, connectionName, managerPath, - "xyz.openbmc_project.Inventory.Decorator.Asset", - std::bind_front(getPhysicalAssets, asyncResp)); - } - else if (interfaceName == - "xyz.openbmc_project.Inventory.Decorator.LocationCode") - { - getLocation(asyncResp, connectionName, managerPath); - } - else if (interfaceName == - "xyz.openbmc_project.Association.Definitions") - { - getLocationIndicatorActive(asyncResp, managerPath); - } - } - } -} - -inline void afterGetManagerObject( - const std::shared_ptr& asyncResp, - const boost::system::error_code& ec, - const dbus::utility::MapperGetSubTreeResponse& subtree, - const std::function< - void(const std::string& managerPath, - const dbus::utility::MapperServiceMap& serviceMap)>& callback) -{ - if (ec) - { - BMCWEB_LOG_DEBUG("D-Bus response error on GetSubTree {}", ec); - return; - } - if (subtree.empty()) - { - BMCWEB_LOG_DEBUG("Can't find bmc D-Bus object!"); - return; - } - // Assume only 1 bmc D-Bus object - // Throw an error if there is more than 1 - if (subtree.size() > 1) - { - BMCWEB_LOG_ERROR("Found more than 1 bmc D-Bus object!"); - messages::internalError(asyncResp->res); - return; - } - - callback(subtree[0].first, subtree[0].second); -} - -inline void getManagerObject( - const std::shared_ptr& asyncResp, - const std::string& /* managerId */, - std::function&& - callback) -{ - constexpr std::array interfaces = { - "xyz.openbmc_project.Inventory.Item.Bmc"}; - dbus::utility::getSubTree( - "/xyz/openbmc_project/inventory", 0, interfaces, - [asyncResp, callback{std::move(callback)}]( - const boost::system::error_code& ec, - const dbus::utility::MapperGetSubTreeResponse& subtree) { - afterGetManagerObject(asyncResp, ec, subtree, callback); - }); -} - -inline void handleManagerGet( - App& app, const crow::Request& req, - const std::shared_ptr& asyncResp, - const std::string& managerId) -{ - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } - - if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) - { - messages::resourceNotFound(asyncResp->res, "Manager", managerId); - return; - } - std::string uuid = persistent_data::getConfig().systemUuid; - asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( - "/redfish/v1/Managers/{}", BMCWEB_REDFISH_MANAGER_URI_NAME); + asyncResp->res.jsonValue["@odata.id"] = + boost::urls::format("/redfish/v1/Managers/{}", managerId); asyncResp->res.jsonValue["@odata.type"] = "#Manager.v1_15_0.Manager"; - asyncResp->res.jsonValue["Id"] = BMCWEB_REDFISH_MANAGER_URI_NAME; + asyncResp->res.jsonValue["Id"] = managerId; asyncResp->res.jsonValue["Name"] = "OpenBmc Manager"; asyncResp->res.jsonValue["Description"] = "Baseboard Management Controller"; getBMCState(asyncResp); @@ -817,14 +672,14 @@ inline void handleManagerGet( asyncResp->res.jsonValue["ServiceEntryPointUUID"] = uuid; asyncResp->res.jsonValue["Model"] = "OpenBmc"; // TODO(ed), get model - asyncResp->res.jsonValue["LogServices"]["@odata.id"] = boost::urls::format( - "/redfish/v1/Managers/{}/LogServices", BMCWEB_REDFISH_MANAGER_URI_NAME); + asyncResp->res.jsonValue["LogServices"]["@odata.id"] = + boost::urls::format("/redfish/v1/Managers/{}/LogServices", managerId); asyncResp->res.jsonValue["NetworkProtocol"]["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}/NetworkProtocol", - BMCWEB_REDFISH_MANAGER_URI_NAME); + managerId); asyncResp->res.jsonValue["EthernetInterfaces"]["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}/EthernetInterfaces", - BMCWEB_REDFISH_MANAGER_URI_NAME); + managerId); manager_utils::getServiceIdentification(asyncResp, false); @@ -832,19 +687,17 @@ inline void handleManagerGet( { asyncResp->res.jsonValue["VirtualMedia"]["@odata.id"] = boost::urls::format("/redfish/v1/Managers/{}/VirtualMedia", - BMCWEB_REDFISH_MANAGER_URI_NAME); + managerId); } // Manager.Reset (an action) can be many values, OpenBMC only // supports BMC reboot. nlohmann::json& managerReset = asyncResp->res.jsonValue["Actions"]["#Manager.Reset"]; - managerReset["target"] = - boost::urls::format("/redfish/v1/Managers/{}/Actions/Manager.Reset", - BMCWEB_REDFISH_MANAGER_URI_NAME); - managerReset["@Redfish.ActionInfo"] = - boost::urls::format("/redfish/v1/Managers/{}/ResetActionInfo", - BMCWEB_REDFISH_MANAGER_URI_NAME); + managerReset["target"] = boost::urls::format( + "/redfish/v1/Managers/{}/Actions/Manager.Reset", managerId); + managerReset["@Redfish.ActionInfo"] = boost::urls::format( + "/redfish/v1/Managers/{}/ResetActionInfo", managerId); // ResetToDefaults (Factory Reset) has values like // PreserveNetworkAndUsers and PreserveNetwork that aren't supported @@ -852,8 +705,7 @@ inline void handleManagerGet( nlohmann::json& resetToDefaults = asyncResp->res.jsonValue["Actions"]["#Manager.ResetToDefaults"]; resetToDefaults["target"] = boost::urls::format( - "/redfish/v1/Managers/{}/Actions/Manager.ResetToDefaults", - BMCWEB_REDFISH_MANAGER_URI_NAME); + "/redfish/v1/Managers/{}/Actions/Manager.ResetToDefaults", managerId); resetToDefaults["ResetType@Redfish.AllowableValues"] = nlohmann::json::array_t({"ResetAll"}); @@ -900,9 +752,8 @@ inline void handleManagerGet( // ManagerDiagnosticData is added for all BMCs. nlohmann::json& managerDiagnosticData = asyncResp->res.jsonValue["ManagerDiagnosticData"]; - managerDiagnosticData["@odata.id"] = - boost::urls::format("/redfish/v1/Managers/{}/ManagerDiagnosticData", - BMCWEB_REDFISH_MANAGER_URI_NAME); + managerDiagnosticData["@odata.id"] = boost::urls::format( + "/redfish/v1/Managers/{}/ManagerDiagnosticData", managerId); getMainChassisId( asyncResp, [](const std::string& chassisId, @@ -920,10 +771,111 @@ inline void handleManagerGet( chassiUrl; }); - getManagerObject(asyncResp, managerId, - std::bind_front(getManagerData, asyncResp)); + for (const auto& [connectionName, interfaces] : serviceMap) + { + for (const auto& interfaceName : interfaces) + { + if (interfaceName == + "xyz.openbmc_project.Inventory.Decorator.Asset") + { + dbus::utility::getAllProperties( + *crow::connections::systemBus, connectionName, managerPath, + "xyz.openbmc_project.Inventory.Decorator.Asset", + std::bind_front(getPhysicalAssets, asyncResp)); + } + else if (interfaceName == + "xyz.openbmc_project.Inventory.Decorator.LocationCode") + { + getLocation(asyncResp, connectionName, managerPath); + } + else if (interfaceName == + "xyz.openbmc_project.Association.Definitions") + { + getLocationIndicatorActive(asyncResp, managerPath); + } + } + } + + rfService.handleSubRoute(subReq, asyncResp); +} + +inline void handleManagerGet( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp, + const std::string& managerId) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + + if (managerId != BMCWEB_REDFISH_MANAGER_URI_NAME) + { + messages::resourceNotFound(asyncResp->res, "Manager", managerId); + return; + } + + RedfishService& rfService = RedfishService::getInstance(app); + std::shared_ptr subReq = std::make_shared(req); + manager_utils::getValidManagerPath( + asyncResp, managerId, + std::bind_front(getManagerData, std::ref(rfService), subReq, asyncResp, + managerId)); +} + +inline void afterHandleManagerPatch( + RedfishService& rfService, const std::shared_ptr& subReq, + const std::shared_ptr& asyncResp, + const std::optional& usbCodeUpdateEnabled, + const std::optional& activeSoftwareImageOdataId, + const std::optional& datetime, + const std::optional& locationIndicatorActive, + const std::optional& serviceIdentification, + const std::string& managerPath, + const dbus::utility::MapperServiceMap& serviceMap) +{ + if (usbCodeUpdateEnabled) + { + if constexpr (BMCWEB_IBM_USB_CODE_UPDATE) + { + setUSBCodeUpdateState(asyncResp, *usbCodeUpdateEnabled); + } + else + { + messages::propertyUnknown(asyncResp->res, "Oem"); + return; + } + } + if (activeSoftwareImageOdataId) + { + setActiveFirmwareImage(asyncResp, *activeSoftwareImageOdataId); + } + + if (datetime) + { + setDateTime(asyncResp, *datetime); + } + + if (locationIndicatorActive) + { + if (managerPath.empty() || serviceMap.size() != 1) + { + BMCWEB_LOG_DEBUG("Error getting bmc D-Bus object!"); + messages::internalError(asyncResp->res); + return; + } - RedfishService::getInstance(app).handleSubRoute(req, asyncResp); + setLocationIndicatorActive(asyncResp, managerPath, + *locationIndicatorActive); + } + + if (serviceIdentification) + { + manager_utils::setServiceIdentification(asyncResp, + serviceIdentification.value()); + } + + rfService.handleSubRoute(subReq, asyncResp); } inline void handleManagerPatch( @@ -974,42 +926,15 @@ inline void handleManagerPatch( return; } - if (usbCodeUpdateEnabled) - { - if constexpr (BMCWEB_IBM_USB_CODE_UPDATE) - { - setUSBCodeUpdateState(asyncResp, *usbCodeUpdateEnabled); - } - else - { - messages::propertyUnknown(asyncResp->res, "Oem"); - return; - } - } - - if (activeSoftwareImageOdataId) - { - setActiveFirmwareImage(asyncResp, *activeSoftwareImageOdataId); - } - - if (datetime) - { - setDateTime(asyncResp, *datetime); - } - - if (locationIndicatorActive) - { - setLocationIndicatorActiveState(asyncResp, *locationIndicatorActive, - managerId); - } - - if (serviceIdentification) - { - manager_utils::setServiceIdentification(asyncResp, - serviceIdentification.value()); - } + RedfishService& rfService = RedfishService::getInstance(app); + std::shared_ptr subReq = std::make_shared(req); - RedfishService::getInstance(app).handleSubRoute(req, asyncResp); + manager_utils::getValidManagerPath( + asyncResp, managerId, + std::bind_front(afterHandleManagerPatch, std::ref(rfService), subReq, + asyncResp, usbCodeUpdateEnabled, + activeSoftwareImageOdataId, datetime, + locationIndicatorActive, serviceIdentification)); } inline void handleManagerCollectionGet( diff --git a/test/redfish-core/include/redfish_oem_routing_test.cpp b/test/redfish-core/include/redfish_oem_routing_test.cpp index dae7e79c2..d6eed4f85 100644 --- a/test/redfish-core/include/redfish_oem_routing_test.cpp +++ b/test/redfish-core/include/redfish_oem_routing_test.cpp @@ -41,7 +41,8 @@ TEST(OemRouter, FragmentRoutes) &service](const crow::Request& req, const std::shared_ptr& asyncResp, const std::string& bar) { - service.handleSubRoute(req, asyncResp); + auto subReq = std::make_shared(req); + service.handleSubRoute(subReq, asyncResp); standardCalled = true; EXPECT_EQ(bar, "bar"); }; @@ -119,7 +120,8 @@ TEST(OemRouter, PatchHandlerWithJsonObject) &service](const crow::Request& req, const std::shared_ptr& asyncResp, const std::string& bar) { - service.handleSubRoute(req, asyncResp); + auto subReq = std::make_shared(req); + service.handleSubRoute(subReq, asyncResp); standardCalled = true; EXPECT_EQ(bar, "bar"); };