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