xref: /openbmc/bmcweb/features/redfish/lib/fabric_adapters.hpp (revision cd7af44f12a56813a464b77828502138ed3eacf2)
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
63     getFabricAdapterAsset(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
64                           const std::string& serviceName,
65                           const std::string& fabricAdapterPath)
66 {
67     sdbusplus::asio::getAllProperties(
68         *crow::connections::systemBus, serviceName, fabricAdapterPath,
69         "xyz.openbmc_project.Inventory.Decorator.Asset",
70         [fabricAdapterPath,
71          aResp{aResp}](const boost::system::error_code ec,
72                        const dbus::utility::DBusPropertiesMap& propertiesList) {
73         if (ec)
74         {
75             if (ec.value() != EBADR)
76             {
77                 BMCWEB_LOG_ERROR << "DBUS response error for Properties";
78                 messages::internalError(aResp->res);
79             }
80             return;
81         }
82 
83         const std::string* serialNumber = nullptr;
84         const std::string* model = nullptr;
85         const std::string* partNumber = nullptr;
86         const std::string* sparePartNumber = nullptr;
87 
88         const bool success = sdbusplus::unpackPropertiesNoThrow(
89             dbus_utils::UnpackErrorPrinter(), propertiesList, "SerialNumber",
90             serialNumber, "Model", model, "PartNumber", partNumber,
91             "SparePartNumber", sparePartNumber);
92 
93         if (!success)
94         {
95             messages::internalError(aResp->res);
96             return;
97         }
98 
99         if (serialNumber != nullptr)
100         {
101             aResp->res.jsonValue["SerialNumber"] = *serialNumber;
102         }
103 
104         if (model != nullptr)
105         {
106             aResp->res.jsonValue["Model"] = *model;
107         }
108 
109         if (partNumber != nullptr)
110         {
111             aResp->res.jsonValue["PartNumber"] = *partNumber;
112         }
113 
114         if (sparePartNumber != nullptr && !sparePartNumber->empty())
115         {
116             aResp->res.jsonValue["SparePartNumber"] = *sparePartNumber;
117         }
118         });
119 }
120 
121 inline void
122     getFabricAdapterState(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
123                           const std::string& serviceName,
124                           const std::string& fabricAdapterPath)
125 {
126     sdbusplus::asio::getProperty<bool>(
127         *crow::connections::systemBus, serviceName, fabricAdapterPath,
128         "xyz.openbmc_project.Inventory.Item", "Present",
129         [aResp](const boost::system::error_code ec, const bool present) {
130         if (ec)
131         {
132             if (ec.value() != EBADR)
133             {
134                 BMCWEB_LOG_ERROR << "DBUS response error for State";
135                 messages::internalError(aResp->res);
136             }
137             return;
138         }
139 
140         if (!present)
141         {
142             aResp->res.jsonValue["Status"]["State"] = "Absent";
143         }
144         });
145 }
146 
147 inline void doAdapterGet(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
148                          const std::string& systemName,
149                          const std::string& adapterId,
150                          const std::string& fabricAdapterPath,
151                          const std::string& serviceName)
152 {
153     aResp->res.addHeader(
154         boost::beast::http::field::link,
155         "</redfish/v1/JsonSchemas/FabricAdapter/FabricAdapter.json>; rel=describedby");
156     aResp->res.jsonValue["@odata.type"] = "#FabricAdapter.v1_4_0.FabricAdapter";
157     aResp->res.jsonValue["Name"] = "Fabric Adapter";
158     aResp->res.jsonValue["Id"] = adapterId;
159     aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
160         "redfish", "v1", "Systems", systemName, "FabricAdapters", adapterId);
161 
162     aResp->res.jsonValue["Status"]["State"] = "Enabled";
163 
164     getFabricAdapterLocation(aResp, serviceName, fabricAdapterPath);
165     getFabricAdapterAsset(aResp, serviceName, fabricAdapterPath);
166     getFabricAdapterState(aResp, serviceName, fabricAdapterPath);
167 }
168 
169 inline bool checkFabricAdapterId(const std::string& adapterPath,
170                                  const std::string& adapterId)
171 {
172     std::string fabricAdapterName =
173         sdbusplus::message::object_path(adapterPath).filename();
174 
175     return !(fabricAdapterName.empty() || fabricAdapterName != adapterId);
176 }
177 
178 inline void getValidFabricAdapterPath(
179     const std::string& adapterId, const std::string& systemName,
180     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
181     std::function<void(const std::string& fabricAdapterPath,
182                        const std::string& serviceName)>&& callback)
183 {
184     if (systemName != "system")
185     {
186         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
187         return;
188     }
189     constexpr std::array<std::string_view, 1> interfaces{
190         "xyz.openbmc_project.Inventory.Item.FabricAdapter"};
191 
192     dbus::utility::getSubTree(
193         "/xyz/openbmc_project/inventory", 0, interfaces,
194         [adapterId, aResp,
195          callback](const boost::system::error_code& ec,
196                    const dbus::utility::MapperGetSubTreeResponse& subtree) {
197         if (ec)
198         {
199             handleAdapterError(ec, aResp->res, adapterId);
200             return;
201         }
202         for (const auto& [adapterPath, serviceMap] : subtree)
203         {
204             if (checkFabricAdapterId(adapterPath, adapterId))
205             {
206                 callback(adapterPath, serviceMap.begin()->first);
207                 return;
208             }
209         }
210         BMCWEB_LOG_WARNING << "Adapter not found";
211         messages::resourceNotFound(aResp->res, "FabricAdapter", adapterId);
212         });
213 }
214 
215 inline void
216     handleFabricAdapterGet(App& app, const crow::Request& req,
217                            const std::shared_ptr<bmcweb::AsyncResp>& aResp,
218                            const std::string& systemName,
219                            const std::string& adapterId)
220 {
221     if (!redfish::setUpRedfishRoute(app, req, aResp))
222     {
223         return;
224     }
225 
226     getValidFabricAdapterPath(
227         adapterId, systemName, aResp,
228         [aResp, systemName, adapterId](const std::string& fabricAdapterPath,
229                                        const std::string& serviceName) {
230         doAdapterGet(aResp, systemName, adapterId, fabricAdapterPath,
231                      serviceName);
232         });
233 }
234 
235 inline void handleFabricAdapterCollectionGet(
236     crow::App& app, const crow::Request& req,
237     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
238     const std::string& systemName)
239 {
240     if (!redfish::setUpRedfishRoute(app, req, aResp))
241     {
242         return;
243     }
244     if (systemName != "system")
245     {
246         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
247         return;
248     }
249 
250     aResp->res.addHeader(
251         boost::beast::http::field::link,
252         "</redfish/v1/JsonSchemas/FabricAdapterCollection/FabricAdapterCollection.json>; rel=describedby");
253     aResp->res.jsonValue["@odata.type"] =
254         "#FabricAdapterCollection.FabricAdapterCollection";
255     aResp->res.jsonValue["Name"] = "Fabric Adapter Collection";
256     aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
257         "redfish", "v1", "Systems", systemName, "FabricAdapters");
258 
259     constexpr std::array<std::string_view, 1> interfaces{
260         "xyz.openbmc_project.Inventory.Item.FabricAdapter"};
261     collection_util::getCollectionMembers(
262         aResp, boost::urls::url("/redfish/v1/Systems/system/FabricAdapters"),
263         interfaces);
264 }
265 
266 inline void handleFabricAdapterCollectionHead(
267     crow::App& app, const crow::Request& req,
268     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
269     const std::string& systemName)
270 {
271     if (!redfish::setUpRedfishRoute(app, req, aResp))
272     {
273         return;
274     }
275     if (systemName != "system")
276     {
277         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
278         return;
279     }
280     aResp->res.addHeader(
281         boost::beast::http::field::link,
282         "</redfish/v1/JsonSchemas/FabricAdapterCollection/FabricAdapterCollection.json>; rel=describedby");
283 }
284 
285 inline void
286     handleFabricAdapterHead(crow::App& app, const crow::Request& req,
287                             const std::shared_ptr<bmcweb::AsyncResp>& aResp,
288                             const std::string& systemName,
289                             const std::string& adapterId)
290 {
291     if (!redfish::setUpRedfishRoute(app, req, aResp))
292     {
293         return;
294     }
295 
296     getValidFabricAdapterPath(
297         adapterId, systemName, aResp,
298         [aResp, systemName, adapterId](const std::string&, const std::string&) {
299         aResp->res.addHeader(
300             boost::beast::http::field::link,
301             "</redfish/v1/JsonSchemas/FabricAdapter/FabricAdapter.json>; rel=describedby");
302         });
303 }
304 
305 inline void requestRoutesFabricAdapterCollection(App& app)
306 {
307     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/")
308         .privileges(redfish::privileges::getFabricAdapterCollection)
309         .methods(boost::beast::http::verb::get)(
310             std::bind_front(handleFabricAdapterCollectionGet, std::ref(app)));
311 
312     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/")
313         .privileges(redfish::privileges::headFabricAdapterCollection)
314         .methods(boost::beast::http::verb::head)(
315             std::bind_front(handleFabricAdapterCollectionHead, std::ref(app)));
316 }
317 
318 inline void requestRoutesFabricAdapters(App& app)
319 {
320     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/")
321         .privileges(redfish::privileges::getFabricAdapter)
322         .methods(boost::beast::http::verb::get)(
323             std::bind_front(handleFabricAdapterGet, std::ref(app)));
324 
325     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/")
326         .privileges(redfish::privileges::headFabricAdapter)
327         .methods(boost::beast::http::verb::head)(
328             std::bind_front(handleFabricAdapterHead, std::ref(app)));
329 }
330 } // namespace redfish
331