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