1 #pragma once 2 3 #include "bmcweb_config.h" 4 5 #include "async_resp.hpp" 6 #include "dbus_utility.hpp" 7 #include "error_messages.hpp" 8 #include "human_sort.hpp" 9 #include "logging.hpp" 10 #include "utility.hpp" 11 12 #include <boost/url/format.hpp> 13 #include <boost/url/url.hpp> 14 #include <sdbusplus/message/native_types.hpp> 15 16 #include <algorithm> 17 #include <array> 18 #include <functional> 19 #include <memory> 20 #include <string> 21 #include <string_view> 22 #include <utility> 23 #include <vector> 24 25 namespace redfish 26 { 27 28 inline void handleSystemCollectionMembers( 29 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 30 const boost::system::error_code& ec, 31 const dbus::utility::MapperGetSubTreePathsResponse& objects) 32 { 33 if (ec == boost::system::errc::io_error) 34 { 35 asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 36 asyncResp->res.jsonValue["Members@odata.count"] = 0; 37 return; 38 } 39 40 if (ec) 41 { 42 BMCWEB_LOG_ERROR("DBUS response error {}", ec.value()); 43 messages::internalError(asyncResp->res); 44 return; 45 } 46 47 nlohmann::json& membersArray = asyncResp->res.jsonValue["Members"]; 48 membersArray = nlohmann::json::array(); 49 50 // consider an empty result as single-host, since single-host systems 51 // do not populate the ManagedHost dbus interface 52 if (objects.empty()) 53 { 54 asyncResp->res.jsonValue["Members@odata.count"] = 1; 55 nlohmann::json::object_t system; 56 system["@odata.id"] = boost::urls::format( 57 "/redfish/v1/Systems/{}", BMCWEB_REDFISH_SYSTEM_URI_NAME); 58 membersArray.emplace_back(std::move(system)); 59 60 if constexpr (BMCWEB_HYPERVISOR_COMPUTER_SYSTEM) 61 { 62 BMCWEB_LOG_DEBUG("Hypervisor is available"); 63 asyncResp->res.jsonValue["Members@odata.count"] = 2; 64 65 nlohmann::json::object_t hypervisor; 66 hypervisor["@odata.id"] = "/redfish/v1/Systems/hypervisor"; 67 membersArray.emplace_back(std::move(hypervisor)); 68 } 69 70 return; 71 } 72 73 std::vector<std::string> pathNames; 74 for (const auto& object : objects) 75 { 76 sdbusplus::message::object_path path(object); 77 std::string leaf = path.filename(); 78 if (leaf.empty()) 79 { 80 continue; 81 } 82 pathNames.emplace_back(leaf); 83 } 84 std::ranges::sort(pathNames, AlphanumLess<std::string>()); 85 86 for (const std::string& systemName : pathNames) 87 { 88 boost::urls::url url("/redfish/v1/Systems"); 89 crow::utility::appendUrlPieces(url, systemName); 90 nlohmann::json::object_t member; 91 member["@odata.id"] = std::move(url); 92 membersArray.emplace_back(std::move(member)); 93 } 94 asyncResp->res.jsonValue["Members@odata.count"] = membersArray.size(); 95 } 96 97 /** 98 * @brief Populate the system collection members from a GetSubTreePaths search 99 * of the inventory based of the ManagedHost dbus interface 100 * 101 * @param[i] asyncResp Async response object 102 * 103 * @return None 104 */ 105 inline void getSystemCollectionMembers( 106 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 107 { 108 constexpr std::array<std::string_view, 1> interfaces{ 109 "xyz.openbmc_project.Inventory.Decorator.ManagedHost", 110 }; 111 112 BMCWEB_LOG_DEBUG("Get system collection members for /redfish/v1/Systems"); 113 114 dbus::utility::getSubTreePaths( 115 "/xyz/openbmc_project/inventory", 0, interfaces, 116 std::bind_front(handleSystemCollectionMembers, asyncResp)); 117 } 118 } // namespace redfish 119