xref: /openbmc/bmcweb/features/redfish/lib/fabric_adapters.hpp (revision 6369421d5a3abea181b28a61f806465be1ba517a)
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 doAdapterGet(const std::shared_ptr<bmcweb::AsyncResp>& aResp,
122                          const std::string& systemName,
123                          const std::string& adapterId,
124                          const std::string& fabricAdapterPath,
125                          const std::string& serviceName)
126 {
127     aResp->res.addHeader(
128         boost::beast::http::field::link,
129         "</redfish/v1/JsonSchemas/FabricAdapter/FabricAdapter.json>; rel=describedby");
130     aResp->res.jsonValue["@odata.type"] = "#FabricAdapter.v1_4_0.FabricAdapter";
131     aResp->res.jsonValue["Name"] = "Fabric Adapter";
132     aResp->res.jsonValue["Id"] = adapterId;
133     aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
134         "redfish", "v1", "Systems", systemName, "FabricAdapters", adapterId);
135 
136     getFabricAdapterLocation(aResp, serviceName, fabricAdapterPath);
137     getFabricAdapterAsset(aResp, serviceName, fabricAdapterPath);
138 }
139 
140 inline bool checkFabricAdapterId(const std::string& adapterPath,
141                                  const std::string& adapterId)
142 {
143     std::string fabricAdapterName =
144         sdbusplus::message::object_path(adapterPath).filename();
145 
146     return !(fabricAdapterName.empty() || fabricAdapterName != adapterId);
147 }
148 
149 inline void getValidFabricAdapterPath(
150     const std::string& adapterId, const std::string& systemName,
151     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
152     std::function<void(const std::string& fabricAdapterPath,
153                        const std::string& serviceName)>&& callback)
154 {
155     if (systemName != "system")
156     {
157         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
158         return;
159     }
160     constexpr std::array<std::string_view, 1> interfaces{
161         "xyz.openbmc_project.Inventory.Item.FabricAdapter"};
162 
163     dbus::utility::getSubTree(
164         "/xyz/openbmc_project/inventory", 0, interfaces,
165         [adapterId, aResp,
166          callback](const boost::system::error_code& ec,
167                    const dbus::utility::MapperGetSubTreeResponse& subtree) {
168         if (ec)
169         {
170             handleAdapterError(ec, aResp->res, adapterId);
171             return;
172         }
173         for (const auto& [adapterPath, serviceMap] : subtree)
174         {
175             if (checkFabricAdapterId(adapterPath, adapterId))
176             {
177                 callback(adapterPath, serviceMap.begin()->first);
178                 return;
179             }
180         }
181         BMCWEB_LOG_WARNING << "Adapter not found";
182         messages::resourceNotFound(aResp->res, "FabricAdapter", adapterId);
183         });
184 }
185 
186 inline void
187     handleFabricAdapterGet(App& app, const crow::Request& req,
188                            const std::shared_ptr<bmcweb::AsyncResp>& aResp,
189                            const std::string& systemName,
190                            const std::string& adapterId)
191 {
192     if (!redfish::setUpRedfishRoute(app, req, aResp))
193     {
194         return;
195     }
196 
197     getValidFabricAdapterPath(
198         adapterId, systemName, aResp,
199         [aResp, systemName, adapterId](const std::string& fabricAdapterPath,
200                                        const std::string& serviceName) {
201         doAdapterGet(aResp, systemName, adapterId, fabricAdapterPath,
202                      serviceName);
203         });
204 }
205 
206 inline void handleFabricAdapterCollectionGet(
207     crow::App& app, const crow::Request& req,
208     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
209     const std::string& systemName)
210 {
211     if (!redfish::setUpRedfishRoute(app, req, aResp))
212     {
213         return;
214     }
215     if (systemName != "system")
216     {
217         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
218         return;
219     }
220 
221     aResp->res.addHeader(
222         boost::beast::http::field::link,
223         "</redfish/v1/JsonSchemas/FabricAdapterCollection/FabricAdapterCollection.json>; rel=describedby");
224     aResp->res.jsonValue["@odata.type"] =
225         "#FabricAdapterCollection.FabricAdapterCollection";
226     aResp->res.jsonValue["Name"] = "Fabric Adapter Collection";
227     aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces(
228         "redfish", "v1", "Systems", systemName, "FabricAdapters");
229 
230     constexpr std::array<std::string_view, 1> interfaces{
231         "xyz.openbmc_project.Inventory.Item.FabricAdapter"};
232     collection_util::getCollectionMembers(
233         aResp, boost::urls::url("/redfish/v1/Systems/system/FabricAdapters"),
234         interfaces);
235 }
236 
237 inline void handleFabricAdapterCollectionHead(
238     crow::App& app, const crow::Request& req,
239     const std::shared_ptr<bmcweb::AsyncResp>& aResp,
240     const std::string& systemName)
241 {
242     if (!redfish::setUpRedfishRoute(app, req, aResp))
243     {
244         return;
245     }
246     if (systemName != "system")
247     {
248         messages::resourceNotFound(aResp->res, "ComputerSystem", systemName);
249         return;
250     }
251     aResp->res.addHeader(
252         boost::beast::http::field::link,
253         "</redfish/v1/JsonSchemas/FabricAdapterCollection/FabricAdapterCollection.json>; rel=describedby");
254 }
255 
256 inline void
257     handleFabricAdapterHead(crow::App& app, const crow::Request& req,
258                             const std::shared_ptr<bmcweb::AsyncResp>& aResp,
259                             const std::string& systemName,
260                             const std::string& adapterId)
261 {
262     if (!redfish::setUpRedfishRoute(app, req, aResp))
263     {
264         return;
265     }
266 
267     getValidFabricAdapterPath(
268         adapterId, systemName, aResp,
269         [aResp, systemName, adapterId](const std::string&, const std::string&) {
270         aResp->res.addHeader(
271             boost::beast::http::field::link,
272             "</redfish/v1/JsonSchemas/FabricAdapter/FabricAdapter.json>; rel=describedby");
273         });
274 }
275 
276 inline void requestRoutesFabricAdapterCollection(App& app)
277 {
278     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/")
279         .privileges(redfish::privileges::getFabricAdapterCollection)
280         .methods(boost::beast::http::verb::get)(
281             std::bind_front(handleFabricAdapterCollectionGet, std::ref(app)));
282 
283     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/")
284         .privileges(redfish::privileges::headFabricAdapterCollection)
285         .methods(boost::beast::http::verb::head)(
286             std::bind_front(handleFabricAdapterCollectionHead, std::ref(app)));
287 }
288 
289 inline void requestRoutesFabricAdapters(App& app)
290 {
291     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/")
292         .privileges(redfish::privileges::getFabricAdapter)
293         .methods(boost::beast::http::verb::get)(
294             std::bind_front(handleFabricAdapterGet, std::ref(app)));
295 
296     BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/")
297         .privileges(redfish::privileges::headFabricAdapter)
298         .methods(boost::beast::http::verb::head)(
299             std::bind_front(handleFabricAdapterHead, std::ref(app)));
300 }
301 } // namespace redfish
302