xref: /openbmc/bmcweb/redfish-core/include/utils/collection.hpp (revision d78572018fc2022091ff8b8eb5a7fef2172ba3d6)
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