1 // SPDX-License-Identifier: Apache-2.0
2 // SPDX-FileCopyrightText: Copyright OpenBMC Authors
3 #pragma once
4
5 #include "async_resp.hpp"
6 #include "dbus_utility.hpp"
7 #include "error_messages.hpp"
8 #include "http/utility.hpp"
9 #include "human_sort.hpp"
10 #include "logging.hpp"
11
12 #include <boost/url/url.hpp>
13 #include <nlohmann/json.hpp>
14 #include <sdbusplus/message/native_types.hpp>
15
16 #include <algorithm>
17 #include <functional>
18 #include <memory>
19 #include <ranges>
20 #include <span>
21 #include <string>
22 #include <string_view>
23 #include <utility>
24 #include <vector>
25
26 namespace redfish
27 {
28 namespace collection_util
29 {
30
handleCollectionMembers(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::urls::url & collectionPath,const nlohmann::json::json_pointer & jsonKeyName,const boost::system::error_code & ec,const dbus::utility::MapperGetSubTreePathsResponse & objects)31 inline void handleCollectionMembers(
32 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
33 const boost::urls::url& collectionPath,
34 const nlohmann::json::json_pointer& jsonKeyName,
35 const boost::system::error_code& ec,
36 const dbus::utility::MapperGetSubTreePathsResponse& objects)
37 {
38 if (jsonKeyName.empty())
39 {
40 messages::internalError(asyncResp->res);
41 BMCWEB_LOG_ERROR("Json Key called empty. Did you mean /Members?");
42 return;
43 }
44 nlohmann::json::json_pointer jsonCountKeyName = jsonKeyName;
45 std::string back = jsonCountKeyName.back();
46 jsonCountKeyName.pop_back();
47 jsonCountKeyName /= back + "@odata.count";
48
49 if (ec == boost::system::errc::io_error)
50 {
51 asyncResp->res.jsonValue[jsonKeyName] = nlohmann::json::array();
52 asyncResp->res.jsonValue[jsonCountKeyName] = 0;
53 return;
54 }
55
56 if (ec)
57 {
58 BMCWEB_LOG_DEBUG("DBUS response error {}", ec.value());
59 messages::internalError(asyncResp->res);
60 return;
61 }
62
63 std::vector<std::string> pathNames;
64 for (const auto& object : objects)
65 {
66 sdbusplus::message::object_path path(object);
67 std::string leaf = path.filename();
68 if (leaf.empty())
69 {
70 continue;
71 }
72 pathNames.push_back(leaf);
73 }
74 std::ranges::sort(pathNames, AlphanumLess<std::string>());
75
76 nlohmann::json& members = asyncResp->res.jsonValue[jsonKeyName];
77 members = nlohmann::json::array();
78 for (const std::string& leaf : pathNames)
79 {
80 boost::urls::url url = collectionPath;
81 crow::utility::appendUrlPieces(url, leaf);
82 nlohmann::json::object_t member;
83 member["@odata.id"] = std::move(url);
84 members.emplace_back(std::move(member));
85 }
86 asyncResp->res.jsonValue[jsonCountKeyName] = members.size();
87 }
88
89 /**
90 * @brief Populate the collection members from a GetSubTreePaths search of
91 * inventory
92 *
93 * @param[i,o] asyncResp Async response object
94 * @param[i] collectionPath Redfish collection path which is used for the
95 * Members Redfish Path
96 * @param[i] interfaces List of interfaces to constrain the GetSubTree search
97 * @param[in] subtree D-Bus base path to constrain search to.
98 * @param[in] jsonKeyName Key name in which the collection members will be
99 * stored.
100 *
101 * @return void
102 */
getCollectionToKey(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::urls::url & collectionPath,std::span<const std::string_view> interfaces,const std::string & subtree,const nlohmann::json::json_pointer & jsonKeyName)103 inline void getCollectionToKey(
104 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
105 const boost::urls::url& collectionPath,
106 std::span<const std::string_view> interfaces, const std::string& subtree,
107 const nlohmann::json::json_pointer& jsonKeyName)
108 {
109 BMCWEB_LOG_DEBUG("Get collection members for: {}", collectionPath.buffer());
110 dbus::utility::getSubTreePaths(
111 subtree, 0, interfaces,
112 std::bind_front(handleCollectionMembers, asyncResp, collectionPath,
113 jsonKeyName));
114 }
getCollectionMembers(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const boost::urls::url & collectionPath,std::span<const std::string_view> interfaces,const std::string & subtree)115 inline void getCollectionMembers(
116 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
117 const boost::urls::url& collectionPath,
118 std::span<const std::string_view> interfaces, const std::string& subtree)
119 {
120 getCollectionToKey(asyncResp, collectionPath, interfaces, subtree,
121 nlohmann::json::json_pointer("/Members"));
122 }
123
124 } // namespace collection_util
125 } // namespace redfish
126