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/chassis_utils.hpp" 8 9 #include <boost/url/format.hpp> 10 11 #include <memory> 12 #include <optional> 13 #include <string> 14 15 namespace redfish 16 { 17 18 inline void 19 updatePowerSupplyList(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 20 const std::string& chassisId, 21 const std::string& powerSupplyPath) 22 { 23 std::string powerSupplyName = 24 sdbusplus::message::object_path(powerSupplyPath).filename(); 25 if (powerSupplyName.empty()) 26 { 27 return; 28 } 29 30 nlohmann::json item = nlohmann::json::object(); 31 item["@odata.id"] = boost::urls::format( 32 "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 33 powerSupplyName); 34 35 nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"]; 36 powerSupplyList.emplace_back(std::move(item)); 37 asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size(); 38 } 39 40 inline void 41 doPowerSupplyCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 42 const std::string& chassisId, 43 const std::optional<std::string>& validChassisPath) 44 { 45 if (!validChassisPath) 46 { 47 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 48 return; 49 } 50 51 asyncResp->res.addHeader( 52 boost::beast::http::field::link, 53 "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 54 asyncResp->res.jsonValue["@odata.type"] = 55 "#PowerSupplyCollection.PowerSupplyCollection"; 56 asyncResp->res.jsonValue["Name"] = "Power Supply Collection"; 57 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 58 "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId); 59 asyncResp->res.jsonValue["Description"] = 60 "The collection of PowerSupply resource instances."; 61 asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 62 asyncResp->res.jsonValue["Members@odata.count"] = 0; 63 64 std::string powerPath = *validChassisPath + "/powered_by"; 65 dbus::utility::getAssociationEndPoints( 66 powerPath, [asyncResp, chassisId]( 67 const boost::system::error_code& ec, 68 const dbus::utility::MapperEndPoints& endpoints) { 69 if (ec) 70 { 71 if (ec.value() != EBADR) 72 { 73 BMCWEB_LOG_ERROR << "DBUS response error" << ec.value(); 74 messages::internalError(asyncResp->res); 75 } 76 return; 77 } 78 79 for (const auto& endpoint : endpoints) 80 { 81 updatePowerSupplyList(asyncResp, chassisId, endpoint); 82 } 83 }); 84 } 85 86 inline void handlePowerSupplyCollectionHead( 87 App& app, const crow::Request& req, 88 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 89 const std::string& chassisId) 90 { 91 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 92 { 93 return; 94 } 95 96 redfish::chassis_utils::getValidChassisPath( 97 asyncResp, chassisId, 98 [asyncResp, 99 chassisId](const std::optional<std::string>& validChassisPath) { 100 if (!validChassisPath) 101 { 102 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 103 return; 104 } 105 asyncResp->res.addHeader( 106 boost::beast::http::field::link, 107 "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 108 }); 109 } 110 111 inline void handlePowerSupplyCollectionGet( 112 App& app, const crow::Request& req, 113 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 114 const std::string& chassisId) 115 { 116 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 117 { 118 return; 119 } 120 121 redfish::chassis_utils::getValidChassisPath( 122 asyncResp, chassisId, 123 std::bind_front(doPowerSupplyCollection, asyncResp, chassisId)); 124 } 125 126 inline void requestRoutesPowerSupplyCollection(App& app) 127 { 128 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 129 .privileges(redfish::privileges::headPowerSupplyCollection) 130 .methods(boost::beast::http::verb::head)( 131 std::bind_front(handlePowerSupplyCollectionHead, std::ref(app))); 132 133 BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 134 .privileges(redfish::privileges::getPowerSupplyCollection) 135 .methods(boost::beast::http::verb::get)( 136 std::bind_front(handlePowerSupplyCollectionGet, std::ref(app))); 137 } 138 139 inline bool checkPowerSupplyId(const std::string& powerSupplyPath, 140 const std::string& powerSupplyId) 141 { 142 std::string powerSupplyName = 143 sdbusplus::message::object_path(powerSupplyPath).filename(); 144 145 return !(powerSupplyName.empty() || powerSupplyName != powerSupplyId); 146 } 147 148 inline void 149 getValidPowerSupplyPath(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 150 const std::string& validChassisPath, 151 const std::string& powerSupplyId, 152 std::function<void()>&& callback) 153 { 154 std::string powerPath = validChassisPath + "/powered_by"; 155 dbus::utility::getAssociationEndPoints( 156 powerPath, [asyncResp, powerSupplyId, callback{std::move(callback)}]( 157 const boost::system::error_code& ec, 158 const dbus::utility::MapperEndPoints& endpoints) { 159 if (ec) 160 { 161 if (ec.value() != EBADR) 162 { 163 BMCWEB_LOG_ERROR 164 << "DBUS response error for getAssociationEndPoints" 165 << ec.value(); 166 messages::internalError(asyncResp->res); 167 return; 168 } 169 messages::resourceNotFound(asyncResp->res, "PowerSupplies", 170 powerSupplyId); 171 return; 172 } 173 174 for (const auto& endpoint : endpoints) 175 { 176 if (checkPowerSupplyId(endpoint, powerSupplyId)) 177 { 178 callback(); 179 return; 180 } 181 } 182 183 if (!endpoints.empty()) 184 { 185 BMCWEB_LOG_WARNING << "Power supply not found: " 186 << powerSupplyId; 187 messages::resourceNotFound(asyncResp->res, "PowerSupplies", 188 powerSupplyId); 189 return; 190 } 191 }); 192 } 193 194 inline void 195 doPowerSupplyGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 196 const std::string& chassisId, 197 const std::string& powerSupplyId, 198 const std::optional<std::string>& validChassisPath) 199 { 200 if (!validChassisPath) 201 { 202 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 203 return; 204 } 205 206 // Get the correct Path and Service that match the input parameters 207 getValidPowerSupplyPath(asyncResp, *validChassisPath, powerSupplyId, 208 [asyncResp, chassisId, powerSupplyId]() { 209 asyncResp->res.addHeader( 210 boost::beast::http::field::link, 211 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 212 asyncResp->res.jsonValue["@odata.type"] = 213 "#PowerSupply.v1_5_0.PowerSupply"; 214 asyncResp->res.jsonValue["Name"] = "Power Supply"; 215 asyncResp->res.jsonValue["Id"] = powerSupplyId; 216 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 217 "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 218 powerSupplyId); 219 }); 220 } 221 222 inline void 223 handlePowerSupplyHead(App& app, const crow::Request& req, 224 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 225 const std::string& chassisId, 226 const std::string& powerSupplyId) 227 { 228 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 229 { 230 return; 231 } 232 233 redfish::chassis_utils::getValidChassisPath( 234 asyncResp, chassisId, 235 [asyncResp, chassisId, 236 powerSupplyId](const std::optional<std::string>& validChassisPath) { 237 if (!validChassisPath) 238 { 239 messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 240 return; 241 } 242 243 // Get the correct Path and Service that match the input parameters 244 getValidPowerSupplyPath(asyncResp, *validChassisPath, powerSupplyId, 245 [asyncResp]() { 246 asyncResp->res.addHeader( 247 boost::beast::http::field::link, 248 "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 249 }); 250 }); 251 } 252 253 inline void 254 handlePowerSupplyGet(App& app, const crow::Request& req, 255 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 256 const std::string& chassisId, 257 const std::string& powerSupplyId) 258 { 259 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 260 { 261 return; 262 } 263 264 redfish::chassis_utils::getValidChassisPath( 265 asyncResp, chassisId, 266 std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId)); 267 } 268 269 inline void requestRoutesPowerSupply(App& app) 270 { 271 BMCWEB_ROUTE( 272 app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 273 .privileges(redfish::privileges::headPowerSupply) 274 .methods(boost::beast::http::verb::head)( 275 std::bind_front(handlePowerSupplyHead, std::ref(app))); 276 277 BMCWEB_ROUTE( 278 app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 279 .privileges(redfish::privileges::getPowerSupply) 280 .methods(boost::beast::http::verb::get)( 281 std::bind_front(handlePowerSupplyGet, std::ref(app))); 282 } 283 284 } // namespace redfish 285