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