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" 82b45fb3bSGeorge Liu #include "utils/dbus_utils.hpp" 92b45fb3bSGeorge Liu #include "utils/json_utils.hpp" 10a7210020SGeorge Liu 1134dfcb94SGeorge Liu #include <boost/system/error_code.hpp> 12ef4c65b7SEd Tanous #include <boost/url/format.hpp> 13ef4c65b7SEd Tanous 14a7210020SGeorge Liu #include <memory> 15a7210020SGeorge Liu #include <optional> 16a7210020SGeorge Liu #include <string> 17a7210020SGeorge Liu 18a7210020SGeorge Liu namespace redfish 19a7210020SGeorge Liu { 20a7210020SGeorge Liu 21788fe6cfSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> powerSupplyInterface = { 22788fe6cfSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 23788fe6cfSLakshmi Yadlapati 24788fe6cfSLakshmi Yadlapati inline void updatePowerSupplyList( 25788fe6cfSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2600ef5dc6SGeorge Liu const std::string& chassisId, 27788fe6cfSLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths) 28788fe6cfSLakshmi Yadlapati { 29788fe6cfSLakshmi Yadlapati nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"]; 30788fe6cfSLakshmi Yadlapati for (const std::string& powerSupplyPath : powerSupplyPaths) 31a7210020SGeorge Liu { 3200ef5dc6SGeorge Liu std::string powerSupplyName = 3300ef5dc6SGeorge Liu sdbusplus::message::object_path(powerSupplyPath).filename(); 3400ef5dc6SGeorge Liu if (powerSupplyName.empty()) 3500ef5dc6SGeorge Liu { 36788fe6cfSLakshmi Yadlapati continue; 3700ef5dc6SGeorge Liu } 3800ef5dc6SGeorge Liu 3900ef5dc6SGeorge Liu nlohmann::json item = nlohmann::json::object(); 4000ef5dc6SGeorge Liu item["@odata.id"] = boost::urls::format( 4100ef5dc6SGeorge Liu "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 4200ef5dc6SGeorge Liu powerSupplyName); 4300ef5dc6SGeorge Liu 4400ef5dc6SGeorge Liu powerSupplyList.emplace_back(std::move(item)); 45788fe6cfSLakshmi Yadlapati } 4600ef5dc6SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size(); 47a7210020SGeorge Liu } 48a7210020SGeorge Liu 49a7210020SGeorge Liu inline void 50a7210020SGeorge Liu doPowerSupplyCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 51a7210020SGeorge Liu const std::string& chassisId, 52a7210020SGeorge Liu const std::optional<std::string>& validChassisPath) 53a7210020SGeorge Liu { 54a7210020SGeorge Liu if (!validChassisPath) 55a7210020SGeorge Liu { 56a7210020SGeorge Liu messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 57a7210020SGeorge Liu return; 58a7210020SGeorge Liu } 59a7210020SGeorge Liu 60a7210020SGeorge Liu asyncResp->res.addHeader( 61a7210020SGeorge Liu boost::beast::http::field::link, 62a7210020SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 63a7210020SGeorge Liu asyncResp->res.jsonValue["@odata.type"] = 64a7210020SGeorge Liu "#PowerSupplyCollection.PowerSupplyCollection"; 65a7210020SGeorge Liu asyncResp->res.jsonValue["Name"] = "Power Supply Collection"; 66ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 67ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId); 68a7210020SGeorge Liu asyncResp->res.jsonValue["Description"] = 69a7210020SGeorge Liu "The collection of PowerSupply resource instances."; 707a2bb2c9SGeorge Liu asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 717a2bb2c9SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = 0; 72a7210020SGeorge Liu 73a7210020SGeorge Liu std::string powerPath = *validChassisPath + "/powered_by"; 74788fe6cfSLakshmi Yadlapati dbus::utility::getAssociatedSubTreePaths( 75788fe6cfSLakshmi Yadlapati powerPath, 76788fe6cfSLakshmi Yadlapati sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 77788fe6cfSLakshmi Yadlapati powerSupplyInterface, 78788fe6cfSLakshmi Yadlapati [asyncResp, chassisId]( 79a7210020SGeorge Liu const boost::system::error_code& ec, 80788fe6cfSLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) { 81a7210020SGeorge Liu if (ec) 82a7210020SGeorge Liu { 83a7210020SGeorge Liu if (ec.value() != EBADR) 84a7210020SGeorge Liu { 85a7210020SGeorge Liu BMCWEB_LOG_ERROR << "DBUS response error" << ec.value(); 86a7210020SGeorge Liu messages::internalError(asyncResp->res); 87a7210020SGeorge Liu } 88a7210020SGeorge Liu return; 89a7210020SGeorge Liu } 90a7210020SGeorge Liu 91788fe6cfSLakshmi Yadlapati updatePowerSupplyList(asyncResp, chassisId, subtreePaths); 92a7210020SGeorge Liu }); 93a7210020SGeorge Liu } 94a7210020SGeorge Liu 95a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead( 96a7210020SGeorge Liu App& app, const crow::Request& req, 97a7210020SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 98a7210020SGeorge Liu const std::string& chassisId) 99a7210020SGeorge Liu { 100a7210020SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 101a7210020SGeorge Liu { 102a7210020SGeorge Liu return; 103a7210020SGeorge Liu } 104a7210020SGeorge Liu 105a7210020SGeorge Liu redfish::chassis_utils::getValidChassisPath( 106a7210020SGeorge Liu asyncResp, chassisId, 107a7210020SGeorge Liu [asyncResp, 108a7210020SGeorge Liu chassisId](const std::optional<std::string>& validChassisPath) { 109a7210020SGeorge Liu if (!validChassisPath) 110a7210020SGeorge Liu { 111a7210020SGeorge Liu messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 112a7210020SGeorge Liu return; 113a7210020SGeorge Liu } 114a7210020SGeorge Liu asyncResp->res.addHeader( 115a7210020SGeorge Liu boost::beast::http::field::link, 116a7210020SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 117a7210020SGeorge Liu }); 118a7210020SGeorge Liu } 119a7210020SGeorge Liu 120a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet( 121a7210020SGeorge Liu App& app, const crow::Request& req, 122a7210020SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 123a7210020SGeorge Liu const std::string& chassisId) 124a7210020SGeorge Liu { 125a7210020SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 126a7210020SGeorge Liu { 127a7210020SGeorge Liu return; 128a7210020SGeorge Liu } 129a7210020SGeorge Liu 130a7210020SGeorge Liu redfish::chassis_utils::getValidChassisPath( 131a7210020SGeorge Liu asyncResp, chassisId, 132a7210020SGeorge Liu std::bind_front(doPowerSupplyCollection, asyncResp, chassisId)); 133a7210020SGeorge Liu } 134a7210020SGeorge Liu 135a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app) 136a7210020SGeorge Liu { 137a7210020SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 138a7210020SGeorge Liu .privileges(redfish::privileges::headPowerSupplyCollection) 139a7210020SGeorge Liu .methods(boost::beast::http::verb::head)( 140a7210020SGeorge Liu std::bind_front(handlePowerSupplyCollectionHead, std::ref(app))); 141a7210020SGeorge Liu 142a7210020SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 143a7210020SGeorge Liu .privileges(redfish::privileges::getPowerSupplyCollection) 144a7210020SGeorge Liu .methods(boost::beast::http::verb::get)( 145a7210020SGeorge Liu std::bind_front(handlePowerSupplyCollectionGet, std::ref(app))); 146a7210020SGeorge Liu } 147a7210020SGeorge Liu 14800ef5dc6SGeorge Liu inline bool checkPowerSupplyId(const std::string& powerSupplyPath, 14900ef5dc6SGeorge Liu const std::string& powerSupplyId) 15000ef5dc6SGeorge Liu { 15100ef5dc6SGeorge Liu std::string powerSupplyName = 15200ef5dc6SGeorge Liu sdbusplus::message::object_path(powerSupplyPath).filename(); 15300ef5dc6SGeorge Liu 15400ef5dc6SGeorge Liu return !(powerSupplyName.empty() || powerSupplyName != powerSupplyId); 15500ef5dc6SGeorge Liu } 15600ef5dc6SGeorge Liu 15734dfcb94SGeorge Liu inline void getValidPowerSupplyPath( 15834dfcb94SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 15934dfcb94SGeorge Liu const std::string& validChassisPath, const std::string& powerSupplyId, 16034dfcb94SGeorge Liu std::function<void(const std::string& powerSupplyPath)>&& callback) 16100ef5dc6SGeorge Liu { 16200ef5dc6SGeorge Liu std::string powerPath = validChassisPath + "/powered_by"; 163788fe6cfSLakshmi Yadlapati dbus::utility::getAssociatedSubTreePaths( 164788fe6cfSLakshmi Yadlapati powerPath, 165788fe6cfSLakshmi Yadlapati sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 166788fe6cfSLakshmi Yadlapati powerSupplyInterface, 167788fe6cfSLakshmi Yadlapati [asyncResp, powerSupplyId, callback{std::move(callback)}]( 16800ef5dc6SGeorge Liu const boost::system::error_code& ec, 169788fe6cfSLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) { 17000ef5dc6SGeorge Liu if (ec) 17100ef5dc6SGeorge Liu { 17200ef5dc6SGeorge Liu if (ec.value() != EBADR) 17300ef5dc6SGeorge Liu { 17400ef5dc6SGeorge Liu BMCWEB_LOG_ERROR 175788fe6cfSLakshmi Yadlapati << "DBUS response error for getAssociatedSubTreePaths" 17600ef5dc6SGeorge Liu << ec.value(); 17700ef5dc6SGeorge Liu messages::internalError(asyncResp->res); 17800ef5dc6SGeorge Liu return; 17900ef5dc6SGeorge Liu } 18000ef5dc6SGeorge Liu messages::resourceNotFound(asyncResp->res, "PowerSupplies", 18100ef5dc6SGeorge Liu powerSupplyId); 18200ef5dc6SGeorge Liu return; 18300ef5dc6SGeorge Liu } 18400ef5dc6SGeorge Liu 185788fe6cfSLakshmi Yadlapati for (const std::string& path : subtreePaths) 18600ef5dc6SGeorge Liu { 187788fe6cfSLakshmi Yadlapati if (checkPowerSupplyId(path, powerSupplyId)) 18800ef5dc6SGeorge Liu { 189788fe6cfSLakshmi Yadlapati callback(path); 19000ef5dc6SGeorge Liu return; 19100ef5dc6SGeorge Liu } 19200ef5dc6SGeorge Liu } 19300ef5dc6SGeorge Liu 194788fe6cfSLakshmi Yadlapati if (!subtreePaths.empty()) 19500ef5dc6SGeorge Liu { 196788fe6cfSLakshmi Yadlapati BMCWEB_LOG_WARNING << "Power supply not found: " << powerSupplyId; 19700ef5dc6SGeorge Liu messages::resourceNotFound(asyncResp->res, "PowerSupplies", 19800ef5dc6SGeorge Liu powerSupplyId); 19900ef5dc6SGeorge Liu return; 20000ef5dc6SGeorge Liu } 20100ef5dc6SGeorge Liu }); 20200ef5dc6SGeorge Liu } 20300ef5dc6SGeorge Liu 20400ef5dc6SGeorge Liu inline void 20534dfcb94SGeorge Liu getPowerSupplyState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 20634dfcb94SGeorge Liu const std::string& service, const std::string& path) 20734dfcb94SGeorge Liu { 20834dfcb94SGeorge Liu sdbusplus::asio::getProperty<bool>( 20934dfcb94SGeorge Liu *crow::connections::systemBus, service, path, 21034dfcb94SGeorge Liu "xyz.openbmc_project.Inventory.Item", "Present", 21134dfcb94SGeorge Liu [asyncResp](const boost::system::error_code& ec, const bool value) { 21234dfcb94SGeorge Liu if (ec) 21334dfcb94SGeorge Liu { 21434dfcb94SGeorge Liu if (ec.value() != EBADR) 21534dfcb94SGeorge Liu { 21634dfcb94SGeorge Liu BMCWEB_LOG_ERROR << "DBUS response error for State " 21734dfcb94SGeorge Liu << ec.value(); 21834dfcb94SGeorge Liu messages::internalError(asyncResp->res); 21934dfcb94SGeorge Liu } 22034dfcb94SGeorge Liu return; 22134dfcb94SGeorge Liu } 22234dfcb94SGeorge Liu 22334dfcb94SGeorge Liu if (!value) 22434dfcb94SGeorge Liu { 22534dfcb94SGeorge Liu asyncResp->res.jsonValue["Status"]["State"] = "Absent"; 22634dfcb94SGeorge Liu } 22734dfcb94SGeorge Liu }); 22834dfcb94SGeorge Liu } 22934dfcb94SGeorge Liu 23034dfcb94SGeorge Liu inline void 23134dfcb94SGeorge Liu getPowerSupplyHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 23234dfcb94SGeorge Liu const std::string& service, const std::string& path) 23334dfcb94SGeorge Liu { 23434dfcb94SGeorge Liu sdbusplus::asio::getProperty<bool>( 23534dfcb94SGeorge Liu *crow::connections::systemBus, service, path, 23634dfcb94SGeorge Liu "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 23734dfcb94SGeorge Liu [asyncResp](const boost::system::error_code& ec, const bool value) { 23834dfcb94SGeorge Liu if (ec) 23934dfcb94SGeorge Liu { 24034dfcb94SGeorge Liu if (ec.value() != EBADR) 24134dfcb94SGeorge Liu { 24234dfcb94SGeorge Liu BMCWEB_LOG_ERROR << "DBUS response error for Health " 24334dfcb94SGeorge Liu << ec.value(); 24434dfcb94SGeorge Liu messages::internalError(asyncResp->res); 24534dfcb94SGeorge Liu } 24634dfcb94SGeorge Liu return; 24734dfcb94SGeorge Liu } 24834dfcb94SGeorge Liu 24934dfcb94SGeorge Liu if (!value) 25034dfcb94SGeorge Liu { 25134dfcb94SGeorge Liu asyncResp->res.jsonValue["Status"]["Health"] = "Critical"; 25234dfcb94SGeorge Liu } 25334dfcb94SGeorge Liu }); 25434dfcb94SGeorge Liu } 25534dfcb94SGeorge Liu 25634dfcb94SGeorge Liu inline void 2572b45fb3bSGeorge Liu getPowerSupplyAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2582b45fb3bSGeorge Liu const std::string& service, const std::string& path) 2592b45fb3bSGeorge Liu { 2602b45fb3bSGeorge Liu sdbusplus::asio::getAllProperties( 2612b45fb3bSGeorge Liu *crow::connections::systemBus, service, path, 2622b45fb3bSGeorge Liu "xyz.openbmc_project.Inventory.Decorator.Asset", 2632b45fb3bSGeorge Liu [asyncResp](const boost::system::error_code& ec, 2642b45fb3bSGeorge Liu const dbus::utility::DBusPropertiesMap& propertiesList) { 2652b45fb3bSGeorge Liu if (ec) 2662b45fb3bSGeorge Liu { 2672b45fb3bSGeorge Liu if (ec.value() != EBADR) 2682b45fb3bSGeorge Liu { 2692b45fb3bSGeorge Liu BMCWEB_LOG_ERROR << "DBUS response error for Asset " 2702b45fb3bSGeorge Liu << ec.value(); 2712b45fb3bSGeorge Liu messages::internalError(asyncResp->res); 2722b45fb3bSGeorge Liu } 2732b45fb3bSGeorge Liu return; 2742b45fb3bSGeorge Liu } 2752b45fb3bSGeorge Liu 2762b45fb3bSGeorge Liu const std::string* partNumber = nullptr; 2772b45fb3bSGeorge Liu const std::string* serialNumber = nullptr; 2782b45fb3bSGeorge Liu const std::string* manufacturer = nullptr; 2792b45fb3bSGeorge Liu const std::string* model = nullptr; 2802b45fb3bSGeorge Liu const std::string* sparePartNumber = nullptr; 2812b45fb3bSGeorge Liu 2822b45fb3bSGeorge Liu const bool success = sdbusplus::unpackPropertiesNoThrow( 2832b45fb3bSGeorge Liu dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 2842b45fb3bSGeorge Liu partNumber, "SerialNumber", serialNumber, "Manufacturer", 2852b45fb3bSGeorge Liu manufacturer, "Model", model, "SparePartNumber", sparePartNumber); 2862b45fb3bSGeorge Liu 2872b45fb3bSGeorge Liu if (!success) 2882b45fb3bSGeorge Liu { 2892b45fb3bSGeorge Liu messages::internalError(asyncResp->res); 2902b45fb3bSGeorge Liu return; 2912b45fb3bSGeorge Liu } 2922b45fb3bSGeorge Liu 2932b45fb3bSGeorge Liu if (partNumber != nullptr) 2942b45fb3bSGeorge Liu { 2952b45fb3bSGeorge Liu asyncResp->res.jsonValue["PartNumber"] = *partNumber; 2962b45fb3bSGeorge Liu } 2972b45fb3bSGeorge Liu 2982b45fb3bSGeorge Liu if (serialNumber != nullptr) 2992b45fb3bSGeorge Liu { 3002b45fb3bSGeorge Liu asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 3012b45fb3bSGeorge Liu } 3022b45fb3bSGeorge Liu 3032b45fb3bSGeorge Liu if (manufacturer != nullptr) 3042b45fb3bSGeorge Liu { 3052b45fb3bSGeorge Liu asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 3062b45fb3bSGeorge Liu } 3072b45fb3bSGeorge Liu 3082b45fb3bSGeorge Liu if (model != nullptr) 3092b45fb3bSGeorge Liu { 3102b45fb3bSGeorge Liu asyncResp->res.jsonValue["Model"] = *model; 3112b45fb3bSGeorge Liu } 3122b45fb3bSGeorge Liu 3132b45fb3bSGeorge Liu // SparePartNumber is optional on D-Bus so skip if it is empty 3142b45fb3bSGeorge Liu if (sparePartNumber != nullptr && !sparePartNumber->empty()) 3152b45fb3bSGeorge Liu { 3162b45fb3bSGeorge Liu asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 3172b45fb3bSGeorge Liu } 3182b45fb3bSGeorge Liu }); 3192b45fb3bSGeorge Liu } 3202b45fb3bSGeorge Liu 321a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion( 322a0dba87bSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 323a0dba87bSGeorge Liu const std::string& service, const std::string& path) 324a0dba87bSGeorge Liu { 325a0dba87bSGeorge Liu sdbusplus::asio::getProperty<std::string>( 326a0dba87bSGeorge Liu *crow::connections::systemBus, service, path, 327a0dba87bSGeorge Liu "xyz.openbmc_project.Software.Version", "Version", 328a0dba87bSGeorge Liu [asyncResp](const boost::system::error_code& ec, 329a0dba87bSGeorge Liu const std::string& value) { 330a0dba87bSGeorge Liu if (ec) 331a0dba87bSGeorge Liu { 332a0dba87bSGeorge Liu if (ec.value() != EBADR) 333a0dba87bSGeorge Liu { 334a0dba87bSGeorge Liu BMCWEB_LOG_ERROR << "DBUS response error for FirmwareVersion " 335a0dba87bSGeorge Liu << ec.value(); 336a0dba87bSGeorge Liu messages::internalError(asyncResp->res); 337a0dba87bSGeorge Liu } 338a0dba87bSGeorge Liu return; 339a0dba87bSGeorge Liu } 340a0dba87bSGeorge Liu asyncResp->res.jsonValue["FirmwareVersion"] = value; 341a0dba87bSGeorge Liu }); 342a0dba87bSGeorge Liu } 343a0dba87bSGeorge Liu 3442b45fb3bSGeorge Liu inline void 34544845e5fSGeorge Liu getPowerSupplyLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 34644845e5fSGeorge Liu const std::string& service, const std::string& path) 34744845e5fSGeorge Liu { 34844845e5fSGeorge Liu sdbusplus::asio::getProperty<std::string>( 34944845e5fSGeorge Liu *crow::connections::systemBus, service, path, 35044845e5fSGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 35144845e5fSGeorge Liu [asyncResp](const boost::system::error_code& ec, 35244845e5fSGeorge Liu const std::string& value) { 35344845e5fSGeorge Liu if (ec) 35444845e5fSGeorge Liu { 35544845e5fSGeorge Liu if (ec.value() != EBADR) 35644845e5fSGeorge Liu { 35744845e5fSGeorge Liu BMCWEB_LOG_ERROR << "DBUS response error for Location " 35844845e5fSGeorge Liu << ec.value(); 35944845e5fSGeorge Liu messages::internalError(asyncResp->res); 36044845e5fSGeorge Liu } 36144845e5fSGeorge Liu return; 36244845e5fSGeorge Liu } 36344845e5fSGeorge Liu asyncResp->res.jsonValue["Location"]["PartLocation"]["ServiceLabel"] = 36444845e5fSGeorge Liu value; 36544845e5fSGeorge Liu }); 36644845e5fSGeorge Liu } 36744845e5fSGeorge Liu 368*ddceee07SGeorge Liu inline void handleGetEfficiencyResponse( 369*ddceee07SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 370*ddceee07SGeorge Liu const boost::system::error_code& ec, uint32_t value) 371*ddceee07SGeorge Liu { 372*ddceee07SGeorge Liu if (ec) 373*ddceee07SGeorge Liu { 374*ddceee07SGeorge Liu if (ec.value() != EBADR) 375*ddceee07SGeorge Liu { 376*ddceee07SGeorge Liu BMCWEB_LOG_ERROR << "DBUS response error for DeratingFactor " 377*ddceee07SGeorge Liu << ec.value(); 378*ddceee07SGeorge Liu messages::internalError(asyncResp->res); 379*ddceee07SGeorge Liu } 380*ddceee07SGeorge Liu return; 381*ddceee07SGeorge Liu } 382*ddceee07SGeorge Liu // The PDI default value is 0, if it hasn't been set leave off 383*ddceee07SGeorge Liu if (value == 0) 384*ddceee07SGeorge Liu { 385*ddceee07SGeorge Liu return; 386*ddceee07SGeorge Liu } 387*ddceee07SGeorge Liu 388*ddceee07SGeorge Liu nlohmann::json::array_t efficiencyRatings; 389*ddceee07SGeorge Liu nlohmann::json::object_t efficiencyPercent; 390*ddceee07SGeorge Liu efficiencyPercent["EfficiencyPercent"] = value; 391*ddceee07SGeorge Liu efficiencyRatings.emplace_back(std::move(efficiencyPercent)); 392*ddceee07SGeorge Liu asyncResp->res.jsonValue["EfficiencyRatings"] = 393*ddceee07SGeorge Liu std::move(efficiencyRatings); 394*ddceee07SGeorge Liu } 395*ddceee07SGeorge Liu 396*ddceee07SGeorge Liu inline void handlePowerSupplyAttributesSubTreeResponse( 397*ddceee07SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 398*ddceee07SGeorge Liu const boost::system::error_code& ec, 399*ddceee07SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) 400*ddceee07SGeorge Liu { 401*ddceee07SGeorge Liu if (ec) 402*ddceee07SGeorge Liu { 403*ddceee07SGeorge Liu if (ec.value() != EBADR) 404*ddceee07SGeorge Liu { 405*ddceee07SGeorge Liu BMCWEB_LOG_ERROR << "DBUS response error for EfficiencyPercent " 406*ddceee07SGeorge Liu << ec.value(); 407*ddceee07SGeorge Liu messages::internalError(asyncResp->res); 408*ddceee07SGeorge Liu } 409*ddceee07SGeorge Liu return; 410*ddceee07SGeorge Liu } 411*ddceee07SGeorge Liu 412*ddceee07SGeorge Liu if (subtree.empty()) 413*ddceee07SGeorge Liu { 414*ddceee07SGeorge Liu BMCWEB_LOG_DEBUG << "Can't find Power Supply Attributes!"; 415*ddceee07SGeorge Liu return; 416*ddceee07SGeorge Liu } 417*ddceee07SGeorge Liu 418*ddceee07SGeorge Liu if (subtree.size() != 1) 419*ddceee07SGeorge Liu { 420*ddceee07SGeorge Liu BMCWEB_LOG_ERROR 421*ddceee07SGeorge Liu << "Unexpected number of paths returned by getSubTree: " 422*ddceee07SGeorge Liu << subtree.size(); 423*ddceee07SGeorge Liu messages::internalError(asyncResp->res); 424*ddceee07SGeorge Liu return; 425*ddceee07SGeorge Liu } 426*ddceee07SGeorge Liu 427*ddceee07SGeorge Liu const auto& [path, serviceMap] = *subtree.begin(); 428*ddceee07SGeorge Liu const auto& [service, interfaces] = *serviceMap.begin(); 429*ddceee07SGeorge Liu sdbusplus::asio::getProperty<uint32_t>( 430*ddceee07SGeorge Liu *crow::connections::systemBus, service, path, 431*ddceee07SGeorge Liu "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor", 432*ddceee07SGeorge Liu [asyncResp](const boost::system::error_code& ec1, uint32_t value) { 433*ddceee07SGeorge Liu handleGetEfficiencyResponse(asyncResp, ec1, value); 434*ddceee07SGeorge Liu }); 435*ddceee07SGeorge Liu } 436*ddceee07SGeorge Liu 437*ddceee07SGeorge Liu inline void 438*ddceee07SGeorge Liu getEfficiencyPercent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 439*ddceee07SGeorge Liu { 440*ddceee07SGeorge Liu constexpr std::array<std::string_view, 1> efficiencyIntf = { 441*ddceee07SGeorge Liu "xyz.openbmc_project.Control.PowerSupplyAttributes"}; 442*ddceee07SGeorge Liu 443*ddceee07SGeorge Liu dbus::utility::getSubTree( 444*ddceee07SGeorge Liu "/xyz/openbmc_project", 0, efficiencyIntf, 445*ddceee07SGeorge Liu [asyncResp](const boost::system::error_code& ec, 446*ddceee07SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) { 447*ddceee07SGeorge Liu handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree); 448*ddceee07SGeorge Liu }); 449*ddceee07SGeorge Liu } 450*ddceee07SGeorge Liu 45144845e5fSGeorge Liu inline void 45200ef5dc6SGeorge Liu doPowerSupplyGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 45300ef5dc6SGeorge Liu const std::string& chassisId, 45400ef5dc6SGeorge Liu const std::string& powerSupplyId, 45500ef5dc6SGeorge Liu const std::optional<std::string>& validChassisPath) 45600ef5dc6SGeorge Liu { 45700ef5dc6SGeorge Liu if (!validChassisPath) 45800ef5dc6SGeorge Liu { 45900ef5dc6SGeorge Liu messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 46000ef5dc6SGeorge Liu return; 46100ef5dc6SGeorge Liu } 46200ef5dc6SGeorge Liu 46300ef5dc6SGeorge Liu // Get the correct Path and Service that match the input parameters 46400ef5dc6SGeorge Liu getValidPowerSupplyPath(asyncResp, *validChassisPath, powerSupplyId, 46534dfcb94SGeorge Liu [asyncResp, chassisId, powerSupplyId]( 46634dfcb94SGeorge Liu const std::string& powerSupplyPath) { 46700ef5dc6SGeorge Liu asyncResp->res.addHeader( 46800ef5dc6SGeorge Liu boost::beast::http::field::link, 46900ef5dc6SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 47000ef5dc6SGeorge Liu asyncResp->res.jsonValue["@odata.type"] = 47100ef5dc6SGeorge Liu "#PowerSupply.v1_5_0.PowerSupply"; 47200ef5dc6SGeorge Liu asyncResp->res.jsonValue["Name"] = "Power Supply"; 47300ef5dc6SGeorge Liu asyncResp->res.jsonValue["Id"] = powerSupplyId; 47400ef5dc6SGeorge Liu asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 47500ef5dc6SGeorge Liu "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 47600ef5dc6SGeorge Liu powerSupplyId); 47734dfcb94SGeorge Liu 47834dfcb94SGeorge Liu asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; 47934dfcb94SGeorge Liu asyncResp->res.jsonValue["Status"]["Health"] = "OK"; 48034dfcb94SGeorge Liu 48134dfcb94SGeorge Liu dbus::utility::getDbusObject( 482788fe6cfSLakshmi Yadlapati powerSupplyPath, powerSupplyInterface, 48334dfcb94SGeorge Liu [asyncResp, 48434dfcb94SGeorge Liu powerSupplyPath](const boost::system::error_code& ec, 48534dfcb94SGeorge Liu const dbus::utility::MapperGetObject& object) { 48634dfcb94SGeorge Liu if (ec || object.empty()) 48734dfcb94SGeorge Liu { 48834dfcb94SGeorge Liu messages::internalError(asyncResp->res); 48934dfcb94SGeorge Liu return; 49034dfcb94SGeorge Liu } 49134dfcb94SGeorge Liu 49234dfcb94SGeorge Liu getPowerSupplyState(asyncResp, object.begin()->first, 49334dfcb94SGeorge Liu powerSupplyPath); 49434dfcb94SGeorge Liu getPowerSupplyHealth(asyncResp, object.begin()->first, 49534dfcb94SGeorge Liu powerSupplyPath); 4962b45fb3bSGeorge Liu getPowerSupplyAsset(asyncResp, object.begin()->first, 4972b45fb3bSGeorge Liu powerSupplyPath); 498a0dba87bSGeorge Liu getPowerSupplyFirmwareVersion(asyncResp, object.begin()->first, 499a0dba87bSGeorge Liu powerSupplyPath); 50044845e5fSGeorge Liu getPowerSupplyLocation(asyncResp, object.begin()->first, 50144845e5fSGeorge Liu powerSupplyPath); 50234dfcb94SGeorge Liu }); 503*ddceee07SGeorge Liu 504*ddceee07SGeorge Liu getEfficiencyPercent(asyncResp); 50500ef5dc6SGeorge Liu }); 50600ef5dc6SGeorge Liu } 50700ef5dc6SGeorge Liu 50800ef5dc6SGeorge Liu inline void 50900ef5dc6SGeorge Liu handlePowerSupplyHead(App& app, const crow::Request& req, 51000ef5dc6SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 51100ef5dc6SGeorge Liu const std::string& chassisId, 51200ef5dc6SGeorge Liu const std::string& powerSupplyId) 51300ef5dc6SGeorge Liu { 51400ef5dc6SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 51500ef5dc6SGeorge Liu { 51600ef5dc6SGeorge Liu return; 51700ef5dc6SGeorge Liu } 51800ef5dc6SGeorge Liu 51900ef5dc6SGeorge Liu redfish::chassis_utils::getValidChassisPath( 52000ef5dc6SGeorge Liu asyncResp, chassisId, 52100ef5dc6SGeorge Liu [asyncResp, chassisId, 52200ef5dc6SGeorge Liu powerSupplyId](const std::optional<std::string>& validChassisPath) { 52300ef5dc6SGeorge Liu if (!validChassisPath) 52400ef5dc6SGeorge Liu { 52500ef5dc6SGeorge Liu messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 52600ef5dc6SGeorge Liu return; 52700ef5dc6SGeorge Liu } 52800ef5dc6SGeorge Liu 52900ef5dc6SGeorge Liu // Get the correct Path and Service that match the input parameters 53000ef5dc6SGeorge Liu getValidPowerSupplyPath(asyncResp, *validChassisPath, powerSupplyId, 53134dfcb94SGeorge Liu [asyncResp](const std::string&) { 53200ef5dc6SGeorge Liu asyncResp->res.addHeader( 53300ef5dc6SGeorge Liu boost::beast::http::field::link, 53400ef5dc6SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 53500ef5dc6SGeorge Liu }); 53600ef5dc6SGeorge Liu }); 53700ef5dc6SGeorge Liu } 53800ef5dc6SGeorge Liu 53900ef5dc6SGeorge Liu inline void 54000ef5dc6SGeorge Liu handlePowerSupplyGet(App& app, const crow::Request& req, 54100ef5dc6SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 54200ef5dc6SGeorge Liu const std::string& chassisId, 54300ef5dc6SGeorge Liu const std::string& powerSupplyId) 54400ef5dc6SGeorge Liu { 54500ef5dc6SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 54600ef5dc6SGeorge Liu { 54700ef5dc6SGeorge Liu return; 54800ef5dc6SGeorge Liu } 54900ef5dc6SGeorge Liu 55000ef5dc6SGeorge Liu redfish::chassis_utils::getValidChassisPath( 55100ef5dc6SGeorge Liu asyncResp, chassisId, 55200ef5dc6SGeorge Liu std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId)); 55300ef5dc6SGeorge Liu } 55400ef5dc6SGeorge Liu 55500ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app) 55600ef5dc6SGeorge Liu { 55700ef5dc6SGeorge Liu BMCWEB_ROUTE( 55800ef5dc6SGeorge Liu app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 55900ef5dc6SGeorge Liu .privileges(redfish::privileges::headPowerSupply) 56000ef5dc6SGeorge Liu .methods(boost::beast::http::verb::head)( 56100ef5dc6SGeorge Liu std::bind_front(handlePowerSupplyHead, std::ref(app))); 56200ef5dc6SGeorge Liu 56300ef5dc6SGeorge Liu BMCWEB_ROUTE( 56400ef5dc6SGeorge Liu app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 56500ef5dc6SGeorge Liu .privileges(redfish::privileges::getPowerSupply) 56600ef5dc6SGeorge Liu .methods(boost::beast::http::verb::get)( 56700ef5dc6SGeorge Liu std::bind_front(handlePowerSupplyGet, std::ref(app))); 56800ef5dc6SGeorge Liu } 56900ef5dc6SGeorge Liu 570a7210020SGeorge Liu } // namespace redfish 571