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 148 getFabricAdapterHealth(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 149 const std::string& serviceName, 150 const std::string& fabricAdapterPath) 151 { 152 sdbusplus::asio::getProperty<bool>( 153 *crow::connections::systemBus, serviceName, fabricAdapterPath, 154 "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 155 [aResp](const boost::system::error_code ec, const bool functional) { 156 if (ec) 157 { 158 if (ec.value() != EBADR) 159 { 160 BMCWEB_LOG_ERROR << "DBUS response error for Health"; 161 messages::internalError(aResp->res); 162 } 163 return; 164 } 165 166 if (!functional) 167 { 168 aResp->res.jsonValue["Status"]["Health"] = "Critical"; 169 } 170 }); 171 } 172 173 inline void doAdapterGet(const std::shared_ptr<bmcweb::AsyncResp>& aResp, 174 const std::string& systemName, 175 const std::string& adapterId, 176 const std::string& fabricAdapterPath, 177 const std::string& serviceName) 178 { 179 aResp->res.addHeader( 180 boost::beast::http::field::link, 181 "</redfish/v1/JsonSchemas/FabricAdapter/FabricAdapter.json>; rel=describedby"); 182 aResp->res.jsonValue["@odata.type"] = "#FabricAdapter.v1_4_0.FabricAdapter"; 183 aResp->res.jsonValue["Name"] = "Fabric Adapter"; 184 aResp->res.jsonValue["Id"] = adapterId; 185 aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 186 "redfish", "v1", "Systems", systemName, "FabricAdapters", adapterId); 187 188 aResp->res.jsonValue["Status"]["State"] = "Enabled"; 189 aResp->res.jsonValue["Status"]["Health"] = "OK"; 190 191 getFabricAdapterLocation(aResp, serviceName, fabricAdapterPath); 192 getFabricAdapterAsset(aResp, serviceName, fabricAdapterPath); 193 getFabricAdapterState(aResp, serviceName, fabricAdapterPath); 194 getFabricAdapterHealth(aResp, serviceName, fabricAdapterPath); 195 } 196 197 inline bool checkFabricAdapterId(const std::string& adapterPath, 198 const std::string& adapterId) 199 { 200 std::string fabricAdapterName = 201 sdbusplus::message::object_path(adapterPath).filename(); 202 203 return !(fabricAdapterName.empty() || fabricAdapterName != adapterId); 204 } 205 206 inline void getValidFabricAdapterPath( 207 const std::string& adapterId, const std::string& systemName, 208 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 209 std::function<void(const std::string& fabricAdapterPath, 210 const std::string& serviceName)>&& callback) 211 { 212 if (systemName != "system") 213 { 214 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 215 return; 216 } 217 constexpr std::array<std::string_view, 1> interfaces{ 218 "xyz.openbmc_project.Inventory.Item.FabricAdapter"}; 219 220 dbus::utility::getSubTree( 221 "/xyz/openbmc_project/inventory", 0, interfaces, 222 [adapterId, aResp, 223 callback](const boost::system::error_code& ec, 224 const dbus::utility::MapperGetSubTreeResponse& subtree) { 225 if (ec) 226 { 227 handleAdapterError(ec, aResp->res, adapterId); 228 return; 229 } 230 for (const auto& [adapterPath, serviceMap] : subtree) 231 { 232 if (checkFabricAdapterId(adapterPath, adapterId)) 233 { 234 callback(adapterPath, serviceMap.begin()->first); 235 return; 236 } 237 } 238 BMCWEB_LOG_WARNING << "Adapter not found"; 239 messages::resourceNotFound(aResp->res, "FabricAdapter", adapterId); 240 }); 241 } 242 243 inline void 244 handleFabricAdapterGet(App& app, const crow::Request& req, 245 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 246 const std::string& systemName, 247 const std::string& adapterId) 248 { 249 if (!redfish::setUpRedfishRoute(app, req, aResp)) 250 { 251 return; 252 } 253 254 getValidFabricAdapterPath( 255 adapterId, systemName, aResp, 256 [aResp, systemName, adapterId](const std::string& fabricAdapterPath, 257 const std::string& serviceName) { 258 doAdapterGet(aResp, systemName, adapterId, fabricAdapterPath, 259 serviceName); 260 }); 261 } 262 263 inline void handleFabricAdapterCollectionGet( 264 crow::App& app, const crow::Request& req, 265 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 266 const std::string& systemName) 267 { 268 if (!redfish::setUpRedfishRoute(app, req, aResp)) 269 { 270 return; 271 } 272 if (systemName != "system") 273 { 274 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 275 return; 276 } 277 278 aResp->res.addHeader( 279 boost::beast::http::field::link, 280 "</redfish/v1/JsonSchemas/FabricAdapterCollection/FabricAdapterCollection.json>; rel=describedby"); 281 aResp->res.jsonValue["@odata.type"] = 282 "#FabricAdapterCollection.FabricAdapterCollection"; 283 aResp->res.jsonValue["Name"] = "Fabric Adapter Collection"; 284 aResp->res.jsonValue["@odata.id"] = crow::utility::urlFromPieces( 285 "redfish", "v1", "Systems", systemName, "FabricAdapters"); 286 287 constexpr std::array<std::string_view, 1> interfaces{ 288 "xyz.openbmc_project.Inventory.Item.FabricAdapter"}; 289 collection_util::getCollectionMembers( 290 aResp, boost::urls::url("/redfish/v1/Systems/system/FabricAdapters"), 291 interfaces); 292 } 293 294 inline void handleFabricAdapterCollectionHead( 295 crow::App& app, const crow::Request& req, 296 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 297 const std::string& systemName) 298 { 299 if (!redfish::setUpRedfishRoute(app, req, aResp)) 300 { 301 return; 302 } 303 if (systemName != "system") 304 { 305 messages::resourceNotFound(aResp->res, "ComputerSystem", systemName); 306 return; 307 } 308 aResp->res.addHeader( 309 boost::beast::http::field::link, 310 "</redfish/v1/JsonSchemas/FabricAdapterCollection/FabricAdapterCollection.json>; rel=describedby"); 311 } 312 313 inline void 314 handleFabricAdapterHead(crow::App& app, const crow::Request& req, 315 const std::shared_ptr<bmcweb::AsyncResp>& aResp, 316 const std::string& systemName, 317 const std::string& adapterId) 318 { 319 if (!redfish::setUpRedfishRoute(app, req, aResp)) 320 { 321 return; 322 } 323 324 getValidFabricAdapterPath( 325 adapterId, systemName, aResp, 326 [aResp, systemName, adapterId](const std::string&, const std::string&) { 327 aResp->res.addHeader( 328 boost::beast::http::field::link, 329 "</redfish/v1/JsonSchemas/FabricAdapter/FabricAdapter.json>; rel=describedby"); 330 }); 331 } 332 333 inline void requestRoutesFabricAdapterCollection(App& app) 334 { 335 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/") 336 .privileges(redfish::privileges::getFabricAdapterCollection) 337 .methods(boost::beast::http::verb::get)( 338 std::bind_front(handleFabricAdapterCollectionGet, std::ref(app))); 339 340 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/") 341 .privileges(redfish::privileges::headFabricAdapterCollection) 342 .methods(boost::beast::http::verb::head)( 343 std::bind_front(handleFabricAdapterCollectionHead, std::ref(app))); 344 } 345 346 inline void requestRoutesFabricAdapters(App& app) 347 { 348 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/") 349 .privileges(redfish::privileges::getFabricAdapter) 350 .methods(boost::beast::http::verb::get)( 351 std::bind_front(handleFabricAdapterGet, std::ref(app))); 352 353 BMCWEB_ROUTE(app, "/redfish/v1/Systems/<str>/FabricAdapters/<str>/") 354 .privileges(redfish::privileges::headFabricAdapter) 355 .methods(boost::beast::http::verb::head)( 356 std::bind_front(handleFabricAdapterHead, std::ref(app))); 357 } 358 } // namespace redfish 359