| #ifndef THIRD_PARTY_GBMCWEB_REDFISH_CORE_LIB_OTHER_SOFTWARE_SERVICE_H_ |
| #define THIRD_PARTY_GBMCWEB_REDFISH_CORE_LIB_OTHER_SOFTWARE_SERVICE_H_ |
| |
| #include <array> |
| #include <memory> |
| #include <string> |
| #include <string_view> |
| #include <utility> |
| #include <vector> |
| |
| #include "logging.hpp" |
| #include "utility.hpp" |
| #include "async_resp.hpp" |
| #include "dbus_utility.hpp" |
| #include "error_messages.hpp" |
| #include "dbus_utils.hpp" |
| #include <nlohmann/json.hpp> |
| #include "managed_store.hpp" |
| #include "managed_store_types.hpp" |
| #include "sdbusplus/message/native_types.hpp" |
| |
| 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"]; |
| // Flags to track which categories this association belongs to. |
| bool isDrive = false; |
| bool isProcessor = false; |
| bool isChassis = false; |
| bool isStorageController = false; |
| |
| for (const auto& [serviceName, interfaceList] : objects) { |
| for (const std::string& interface : interfaceList) { |
| if (interface == "xyz.openbmc_project.Inventory.Item.Drive") { |
| isDrive = true; |
| } |
| if (interface == "xyz.openbmc_project.Inventory.Item.Accelerator" || |
| interface == "xyz.openbmc_project.Inventory.Item.Cpu") { |
| isProcessor = true; |
| } |
| if (interface == "xyz.openbmc_project.Inventory.Item.Board" || |
| interface == "xyz.openbmc_project.Inventory.Item.Chassis") { |
| isChassis = true; |
| } |
| if (interface == |
| "xyz.openbmc_project.Inventory." |
| "Item.StorageController") { |
| isStorageController = true; |
| } |
| } |
| } |
| |
| // Apply findings exactly once per association. |
| if (isDrive) { |
| getRelatedItemsDrive(aResp, association); |
| } |
| if (isProcessor) { |
| relatedItem.emplace_back(nlohmann::json( |
| {{"@odata.id", "/redfish/v1/Systems/system/Processors/" + |
| association.filename()}})); |
| } |
| if (isChassis) { |
| relatedItem.emplace_back( |
| nlohmann::json({{"@odata.id", "/redfish/v1/Chassis/" + |
| association.filename()}})); |
| } |
| if (isStorageController) { |
| 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 |
| |
| #endif // THIRD_PARTY_GBMCWEB_REDFISH_CORE_LIB_OTHER_SOFTWARE_SERVICE_H_ |