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