| |
| #pragma once |
| |
| #include "bmcweb_config.h" |
| |
| #include "error_messages.hpp" |
| #include "managed_store_types.hpp" |
| |
| // TODO(wltu): Move to a different file until this is fully cleaned up. |
| #include <sdbusplus/asio/property.hpp> |
| |
| #include "managed_store.hpp" |
| #include "utility.hpp" |
| #include "utils/dbus_utils.hpp" |
| |
| #ifdef UNIT_TEST_BUILD |
| #include "test/g3/mock_managed_store.hpp" // NOLINT |
| #endif |
| namespace redfish |
| { |
| inline static void |
| getRelatedItemsDrive(const std::shared_ptr<bmcweb::AsyncResp>& aResp, |
| const sdbusplus::message::object_path& objPath) |
| { |
| // Drive is expected to be under a Chassis |
| constexpr std::array<std::string_view, 2> interfaces = { |
| "xyz.openbmc_project.Inventory.Item.Board", |
| "xyz.openbmc_project.Inventory.Item.Chassis"}; |
| managedStore::ManagedObjectStoreContext requestContext(aResp); |
| managedStore::GetManagedObjectStore()->getAssociatedSubTreePaths( |
| objPath / "chassis", |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, |
| interfaces, requestContext, |
| [aResp, objPath]( |
| const boost::system::error_code& ec, |
| const dbus::utility::MapperGetSubTreePathsResponse& chassisList) { |
| if (ec) |
| { |
| BMCWEB_LOG_DEBUG |
| << "Failed to call getProperty for Drive -> Chassis Association: " |
| << ec; |
| messages::internalError(aResp->res); |
| return; |
| } |
| |
| if (chassisList.empty()) |
| { |
| BMCWEB_LOG_DEBUG << "Can not find the Chassis containing the drive"; |
| return; |
| } |
| |
| if (chassisList.size() != 1) |
| { |
| BMCWEB_LOG_ERROR << "Resource can only be included in one storage"; |
| messages::internalError(aResp->res); |
| return; |
| } |
| |
| nlohmann::json::array_t relatedItems; |
| nlohmann::json::object_t relatedItem; |
| relatedItem["@odata.id"] = crow::utility::urlFromPieces( |
| "redfish", "v1", "Chassis", |
| sdbusplus::message::object_path(chassisList[0]).filename(), |
| "Drives", objPath.filename()); |
| relatedItems.emplace_back(std::move(relatedItem)); |
| aResp->res.jsonValue["RelatedItem@odata.count"] = relatedItems.size(); |
| aResp->res.jsonValue["RelatedItem"] = std::move(relatedItems); |
| }); |
| } |
| |
| inline static void getRelatedItemsStorageController( |
| const std::shared_ptr<bmcweb::AsyncResp>& aResp, |
| const sdbusplus::message::object_path& objPath) |
| { |
| constexpr std::array<std::string_view, 1> interfaces = { |
| "xyz.openbmc_project.Inventory.Item.Storage"}; |
| managedStore::ManagedObjectStoreContext requestContext(aResp); |
| managedStore::GetManagedObjectStore()->getAssociatedSubTreePaths( |
| objPath / "storage", |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, |
| interfaces, requestContext, |
| [aResp, objPath, |
| requestContext](const boost::system::error_code ec, |
| const std::vector<std::string>& storageList) { |
| if (ec) |
| { |
| BMCWEB_LOG_DEBUG |
| << "Failed to call getProperty for Storage Association: " << ec; |
| return; |
| } |
| |
| if (storageList.size() != 1) |
| { |
| BMCWEB_LOG_ERROR << "Resource can only be included in one storage"; |
| messages::internalError(aResp->res); |
| return; |
| } |
| |
| sdbusplus::message::object_path storage(storageList[0]); |
| |
| constexpr std::array<std::string_view, 1> storageControllerInterfaces = |
| {"xyz.openbmc_project.Inventory.Item.StorageController"}; |
| managedStore::GetManagedObjectStore()->getAssociatedSubTreePaths( |
| storage / "storage_controller", |
| sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), |
| 0, storageControllerInterfaces, requestContext, |
| [aResp, storage, |
| objPath](const boost::system::error_code ec2, |
| const std::vector<std::string>& storageControllerList) { |
| if (ec2) |
| { |
| BMCWEB_LOG_DEBUG |
| << "Failed to call getProperty for Storage -> StorageController Association: " |
| << ec2; |
| return; |
| } |
| |
| for (const std::string& storageController : storageControllerList) |
| { |
| const std::string& id = |
| sdbusplus::message::object_path(storageController) |
| .filename(); |
| if (id.empty()) |
| { |
| BMCWEB_LOG_ERROR << "filename() is empty in " |
| << storageController; |
| continue; |
| } |
| |
| if (storageController != objPath.str) |
| { |
| continue; |
| } |
| |
| nlohmann::json::array_t relatedItems; |
| nlohmann::json::object_t relatedItem; |
| relatedItem["@odata.id"] = crow::utility::urlFromPieces( |
| "redfish", "v1", "Systems", "system", "Storage", |
| storage.filename(), "Controllers", id); |
| relatedItems.emplace_back(std::move(relatedItem)); |
| aResp->res.jsonValue["RelatedItem@odata.count"] = |
| relatedItems.size(); |
| aResp->res.jsonValue["RelatedItem"] = std::move(relatedItems); |
| |
| break; |
| } |
| }); |
| }); |
| } |
| |
| inline static void |
| getRelatedItemsOther(const std::shared_ptr<bmcweb::AsyncResp>& aResp, |
| const sdbusplus::message::object_path& association) |
| { |
| constexpr std::array<std::string_view, 6> inventoryInterfaces = { |
| "xyz.openbmc_project.Inventory.Item.Accelerator", |
| "xyz.openbmc_project.Inventory.Item.Cpu", |
| "xyz.openbmc_project.Inventory.Item.Drive", |
| "xyz.openbmc_project.Inventory.Item.Board", |
| "xyz.openbmc_project.Inventory.Item.Chassis", |
| "xyz.openbmc_project.Inventory.Item.StorageController"}; |
| |
| // Find supported device types. |
| managedStore::ManagedObjectStoreContext context(aResp); |
| managedStore::GetManagedObjectStore()->getDbusObject( |
| association.str, inventoryInterfaces, context, |
| [aResp, association]( |
| const boost::system::error_code ec, |
| const std::vector<std::pair<std::string, std::vector<std::string>>>& |
| objects) { |
| if (ec) |
| { |
| BMCWEB_LOG_ERROR << "error_code = " << ec |
| << ", error msg = " << ec.message(); |
| return; |
| } |
| if (objects.empty()) |
| { |
| return; |
| } |
| |
| nlohmann::json& relatedItem = aResp->res.jsonValue["RelatedItem"]; |
| nlohmann::json& relatedItemCount = |
| aResp->res.jsonValue["RelatedItem@odata.count"]; |
| |
| for (const std::pair<std::string, std::vector<std::string>>& object : |
| objects) |
| { |
| for (const std::string& interfaces : object.second) |
| { |
| if (interfaces == "xyz.openbmc_project.Inventory.Item.Drive") |
| { |
| getRelatedItemsDrive(aResp, association); |
| } |
| |
| if (interfaces == |
| "xyz.openbmc_project.Inventory.Item.Accelerator" || |
| interfaces == "xyz.openbmc_project.Inventory.Item.Cpu") |
| { |
| relatedItem.emplace_back( |
| nlohmann::json({{"@odata.id", |
| "/redfish/v1/Systems/system/Processors/" + |
| association.filename()}})); |
| } |
| |
| if (interfaces == "xyz.openbmc_project.Inventory.Item.Board" || |
| interfaces == "xyz.openbmc_project.Inventory.Item.Chassis") |
| { |
| relatedItem.emplace_back( |
| nlohmann::json({{"@odata.id", |
| "/redfish/v1/Chassis/" + association.filename()}})); |
| } |
| |
| if (interfaces == "xyz.openbmc_project.Inventory." |
| "Item.StorageController") |
| { |
| getRelatedItemsStorageController(aResp, association); |
| } |
| } |
| } |
| |
| relatedItemCount = relatedItem.size(); |
| }); |
| } |
| |
| /* |
| Fill related item links for Software with other purposes. |
| Use other purpose for device level softwares. |
| */ |
| inline static void |
| getRelatedItemsOthers(const std::shared_ptr<bmcweb::AsyncResp>& aResp, |
| std::string_view path) |
| { |
| BMCWEB_LOG_DEBUG << "getRelatedItemsOthers enter"; |
| |
| aResp->res.jsonValue["RelatedItem"] = nlohmann::json::array(); |
| aResp->res.jsonValue["RelatedItem@odata.count"] = 0; |
| |
| BMCWEB_LOG_DEBUG << "GetReltatedItemsOthers for " << std::string(path) |
| << "/software_related"; |
| |
| managedStore::ManagedObjectStoreContext requestContext(aResp); |
| dbus_utils::getProperty<std::vector<std::string>>( |
| "xyz.openbmc_project.ObjectMapper", |
| std::string(path) + "/software_related", |
| "xyz.openbmc_project.Association", "endpoints", requestContext, |
| [aResp](const boost::system::error_code ec, |
| const std::vector<std::string>& relatedList) { |
| if (ec) |
| { |
| BMCWEB_LOG_DEBUG << "Failed to call dbus for getLogEntry"; |
| return; |
| } |
| |
| for (const auto& item : relatedList) |
| { |
| sdbusplus::message::object_path itemPath(item); |
| if (itemPath.filename().empty()) |
| { |
| continue; |
| } |
| |
| getRelatedItemsOther(aResp, itemPath); |
| } |
| }); |
| } |
| } // namespace redfish |