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