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