xref: /openbmc/bmcweb/features/redfish/lib/fabric_adapters.hpp (revision 53ffeca5ae50e522338b9e167e5840bf967a429b)
1 #pragma once
2 
3 #include "app.hpp"
4 #include "dbus_utility.hpp"
5 #include "query.hpp"
6 #include "registries/privilege_registry.hpp"
7 #include "utils/collection.hpp"
8 #include "utils/json_utils.hpp"
9 
10 #include <boost/system/error_code.hpp>
11 
12 #include <array>
13 #include <functional>
14 #include <memory>
15 #include <string>
16 #include <string_view>
17 
18 namespace redfish
19 {
20 
21 inline void handleAdapterError(const boost::system::error_code& ec,
22                                crow::Response& res,
23                                const std::string& adapterId)
24 {
25 
26     if (ec.value() == boost::system::errc::io_error)
27     {
28         messages::resourceNotFound(res, "#FabricAdapter.v1_4_0.FabricAdapter",
29                                    adapterId);
30         return;
31     }
32 
33     BMCWEB_LOG_ERROR << "DBus method call failed with error " << ec.value();
34     messages::internalError(res);
35 }
36 
37 inline void
38     getFabricAdapterLocation(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
39                              const std::string& serviceName,
40                              const std::string& fabricAdapterPath)
41 {
42     sdbusplus::asio::getProperty<std::string>(
43         *crow::connections::systemBus, serviceName, fabricAdapterPath,
44         "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode",
45         [aResp](const boost::system::error_code ec,
46                 const std::string& property) {
47         if (ec)
48         {
49             if (ec.value() != EBADR)
50             {
51                 BMCWEB_LOG_ERROR << "DBUS response error for Location";
52                 messages::internalError(aResp->res);
53             }
54             return;
55         }
56 
57         aResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] =
58             property;
59         });
60 }
61 
62 inline void doAdapterGet(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
63                          const std::string& systemName,
64                          const std::string& adapterId,
65                          const std::string& fabricAdapterPath,
66                          const std::string& serviceName)
67 {
68     aResp->res.addHeader(
69         boost::beast::http::field::link,
70         "</redfish/v1/JsonSchemas/FabricAdapter/FabricAdapter.json>; rel=describedby");
71     aResp->res.jsonValue["@odata.type"] = "#FabricAdapter.v1_4_0.FabricAdapter";
72     aResp->res.jsonValue["Name"] = "Fabric Adapter";
73     aResp->res.jsonValue["Id"] = adapterId;
74     aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
75         "redfish", "v1", "Systems", systemName, "FabricAdapters", adapterId);
76 
77     getFabricAdapterLocation(aResp, serviceName, fabricAdapterPath);
78 }
79 
80 inline bool checkFabricAdapterId(const std::string& adapterPath,
81                                  const std::string& adapterId)
82 {
83     std::string fabricAdapterName =
84         sdbusplus::message::object_path(adapterPath).filename();
85 
86     return !(fabricAdapterName.empty() || fabricAdapterName != adapterId);
87 }
88 
89 inline void getValidFabricAdapterPath(
90     const std::string& adapterId, const std::string& systemName,
91     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
92     std::function<void(const std::string& fabricAdapterPath,
93                        const std::string& serviceName)>&& callback)
94 {
95     if (systemName != "system")
96     {
97         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
98         return;
99     }
100     constexpr std::array<std::string_view, 1> interfaces{
101         "xyz.openbmc_project.Inventory.Item.FabricAdapter"};
102 
103     dbus::utility::getSubTree(
104         "/xyz/openbmc_project/inventory", 0, interfaces,
105         [adapterId, aResp,
106          callback](const boost::system::error_code& ec,
107                    const dbus::utility::MapperGetSubTreeResponse& subtree) {
108         if (ec)
109         {
110             handleAdapterError(ec, aResp->res, adapterId);
111             return;
112         }
113         for (const auto& [adapterPath, serviceMap] : subtree)
114         {
115             if (checkFabricAdapterId(adapterPath, adapterId))
116             {
117                 callback(adapterPath, serviceMap.begin()->first);
118                 return;
119             }
120         }
121         BMCWEB_LOG_WARNING << "Adapter not found";
122         messages::resourceNotFound(aResp->res, "FabricAdapter", adapterId);
123         });
124 }
125 
126 inline void
127     handleFabricAdapterGet(App& app, const crow::Request& req,
128                            const std::shared_ptr<bmcweb::AsyncResp>& aResp,
129                            const std::string& systemName,
130                            const std::string& adapterId)
131 {
132     if (!redfish::setUpRedfishRoute(app, req, aResp))
133     {
134         return;
135     }
136 
137     getValidFabricAdapterPath(
138         adapterId, systemName, aResp,
139         [aResp, systemName, adapterId](const std::string& fabricAdapterPath,
140                                        const std::string& serviceName) {
141         doAdapterGet(aResp, systemName, adapterId, fabricAdapterPath,
142                      serviceName);
143         });
144 }
145 
146 inline void handleFabricAdapterCollectionGet(
147     crow::App& app, const crow::Request& req,
148     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
149     const std::string& systemName)
150 {
151     if (!redfish::setUpRedfishRoute(app, req, aResp))
152     {
153         return;
154     }
155     if (systemName != "system")
156     {
157         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
158         return;
159     }
160 
161     aResp->res.addHeader(
162         boost::beast::http::field::link,
163         "</redfish/v1/JsonSchemas/FabricAdapterCollection/FabricAdapterCollection.json>; rel=describedby");
164     aResp->res.jsonValue["@odata.type"] =
165         "#FabricAdapterCollection.FabricAdapterCollection";
166     aResp->res.jsonValue["Name"] = "Fabric Adapter Collection";
167     aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
168         "redfish", "v1", "Systems", systemName, "FabricAdapters");
169 
170     constexpr std::array<std::string_view, 1> interfaces{
171         "xyz.openbmc_project.Inventory.Item.FabricAdapter"};
172     collection_util::getCollectionMembers(
173         aResp, boost::urls::url("/redfish/v1/Systems/system/FabricAdapters"),
174         interfaces);
175 }
176 
177 inline void handleFabricAdapterCollectionHead(
178     crow::App& app, const crow::Request& req,
179     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
180     const std::string& systemName)
181 {
182     if (!redfish::setUpRedfishRoute(app, req, aResp))
183     {
184         return;
185     }
186     if (systemName != "system")
187     {
188         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
189         return;
190     }
191     aResp->res.addHeader(
192         boost::beast::http::field::link,
193         "</redfish/v1/JsonSchemas/FabricAdapterCollection/FabricAdapterCollection.json>; rel=describedby");
194 }
195 
196 inline void
197     handleFabricAdapterHead(crow::App& app, const crow::Request& req,
198                             const std::shared_ptr<bmcweb::AsyncResp>& aResp,
199                             const std::string& systemName,
200                             const std::string& adapterId)
201 {
202     if (!redfish::setUpRedfishRoute(app, req, aResp))
203     {
204         return;
205     }
206 
207     getValidFabricAdapterPath(
208         adapterId, systemName, aResp,
209         [aResp, systemName, adapterId](const std::string&, const std::string&) {
210         aResp->res.addHeader(
211             boost::beast::http::field::link,
212             "</redfish/v1/JsonSchemas/FabricAdapter/FabricAdapter.json>; rel=describedby");
213         });
214 }
215 
216 inline void requestRoutesFabricAdapterCollection(App& app)
217 {
218     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/")
219         .privileges(redfish::privileges::getFabricAdapterCollection)
220         .methods(boost::beast::http::verb::get)(
221             std::bind_front(handleFabricAdapterCollectionGet, std::ref(app)));
222 
223     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/")
224         .privileges(redfish::privileges::headFabricAdapterCollection)
225         .methods(boost::beast::http::verb::head)(
226             std::bind_front(handleFabricAdapterCollectionHead, std::ref(app)));
227 }
228 
229 inline void requestRoutesFabricAdapters(App& app)
230 {
231     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/")
232         .privileges(redfish::privileges::getFabricAdapter)
233         .methods(boost::beast::http::verb::get)(
234             std::bind_front(handleFabricAdapterGet, std::ref(app)));
235 
236     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/")
237         .privileges(redfish::privileges::headFabricAdapter)
238         .methods(boost::beast::http::verb::head)(
239             std::bind_front(handleFabricAdapterHead, std::ref(app)));
240 }
241 } // namespace redfish
242