1a7210020SGeorge Liu #pragma once 2a7210020SGeorge Liu 3a7210020SGeorge Liu #include "app.hpp" 4a7210020SGeorge Liu #include "dbus_utility.hpp" 5539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 6a7210020SGeorge Liu #include "query.hpp" 7a7210020SGeorge Liu #include "registries/privilege_registry.hpp" 8a7210020SGeorge Liu #include "utils/chassis_utils.hpp" 92b45fb3bSGeorge Liu #include "utils/dbus_utils.hpp" 102b45fb3bSGeorge Liu #include "utils/json_utils.hpp" 11a7210020SGeorge Liu 1234dfcb94SGeorge Liu #include <boost/system/error_code.hpp> 13ef4c65b7SEd Tanous #include <boost/url/format.hpp> 14ef4c65b7SEd Tanous 15a7210020SGeorge Liu #include <memory> 16a7210020SGeorge Liu #include <optional> 17a7210020SGeorge Liu #include <string> 18a7210020SGeorge Liu 19a7210020SGeorge Liu namespace redfish 20a7210020SGeorge Liu { 21a7210020SGeorge Liu 22788fe6cfSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> powerSupplyInterface = { 23788fe6cfSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 24788fe6cfSLakshmi Yadlapati 25788fe6cfSLakshmi Yadlapati inline void updatePowerSupplyList( 26788fe6cfSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2700ef5dc6SGeorge Liu const std::string& chassisId, 28788fe6cfSLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths) 29788fe6cfSLakshmi Yadlapati { 30788fe6cfSLakshmi Yadlapati nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"]; 31788fe6cfSLakshmi Yadlapati for (const std::string& powerSupplyPath : powerSupplyPaths) 32a7210020SGeorge Liu { 3300ef5dc6SGeorge Liu std::string powerSupplyName = 3400ef5dc6SGeorge Liu sdbusplus::message::object_path(powerSupplyPath).filename(); 3500ef5dc6SGeorge Liu if (powerSupplyName.empty()) 3600ef5dc6SGeorge Liu { 37788fe6cfSLakshmi Yadlapati continue; 3800ef5dc6SGeorge Liu } 3900ef5dc6SGeorge Liu 4000ef5dc6SGeorge Liu nlohmann::json item = nlohmann::json::object(); 4100ef5dc6SGeorge Liu item["@odata.id"] = boost::urls::format( 4200ef5dc6SGeorge Liu "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 4300ef5dc6SGeorge Liu powerSupplyName); 4400ef5dc6SGeorge Liu 4500ef5dc6SGeorge Liu powerSupplyList.emplace_back(std::move(item)); 46788fe6cfSLakshmi Yadlapati } 4700ef5dc6SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size(); 48a7210020SGeorge Liu } 49a7210020SGeorge Liu 50a7210020SGeorge Liu inline void 51a7210020SGeorge Liu doPowerSupplyCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 52a7210020SGeorge Liu const std::string& chassisId, 53a7210020SGeorge Liu const std::optional<std::string>& validChassisPath) 54a7210020SGeorge Liu { 55a7210020SGeorge Liu if (!validChassisPath) 56a7210020SGeorge Liu { 57a7210020SGeorge Liu messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 58a7210020SGeorge Liu return; 59a7210020SGeorge Liu } 60a7210020SGeorge Liu 61a7210020SGeorge Liu asyncResp->res.addHeader( 62a7210020SGeorge Liu boost::beast::http::field::link, 63a7210020SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 64a7210020SGeorge Liu asyncResp->res.jsonValue["@odata.type"] = 65a7210020SGeorge Liu "#PowerSupplyCollection.PowerSupplyCollection"; 66a7210020SGeorge Liu asyncResp->res.jsonValue["Name"] = "Power Supply Collection"; 67ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 68ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId); 69a7210020SGeorge Liu asyncResp->res.jsonValue["Description"] = 70a7210020SGeorge Liu "The collection of PowerSupply resource instances."; 717a2bb2c9SGeorge Liu asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 727a2bb2c9SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = 0; 73a7210020SGeorge Liu 74a7210020SGeorge Liu std::string powerPath = *validChassisPath + "/powered_by"; 75788fe6cfSLakshmi Yadlapati dbus::utility::getAssociatedSubTreePaths( 76788fe6cfSLakshmi Yadlapati powerPath, 77788fe6cfSLakshmi Yadlapati sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 78788fe6cfSLakshmi Yadlapati powerSupplyInterface, 79788fe6cfSLakshmi Yadlapati [asyncResp, chassisId]( 80a7210020SGeorge Liu const boost::system::error_code& ec, 81788fe6cfSLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) { 82a7210020SGeorge Liu if (ec) 83a7210020SGeorge Liu { 84a7210020SGeorge Liu if (ec.value() != EBADR) 85a7210020SGeorge Liu { 8662598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error{}", ec.value()); 87a7210020SGeorge Liu messages::internalError(asyncResp->res); 88a7210020SGeorge Liu } 89a7210020SGeorge Liu return; 90a7210020SGeorge Liu } 91a7210020SGeorge Liu 92788fe6cfSLakshmi Yadlapati updatePowerSupplyList(asyncResp, chassisId, subtreePaths); 93a7210020SGeorge Liu }); 94a7210020SGeorge Liu } 95a7210020SGeorge Liu 96a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead( 97a7210020SGeorge Liu App& app, const crow::Request& req, 98a7210020SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 99a7210020SGeorge Liu const std::string& chassisId) 100a7210020SGeorge Liu { 101a7210020SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 102a7210020SGeorge Liu { 103a7210020SGeorge Liu return; 104a7210020SGeorge Liu } 105a7210020SGeorge Liu 106a7210020SGeorge Liu redfish::chassis_utils::getValidChassisPath( 107a7210020SGeorge Liu asyncResp, chassisId, 108a7210020SGeorge Liu [asyncResp, 109a7210020SGeorge Liu chassisId](const std::optional<std::string>& validChassisPath) { 110a7210020SGeorge Liu if (!validChassisPath) 111a7210020SGeorge Liu { 112*bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 113*bd79bce8SPatrick Williams chassisId); 114a7210020SGeorge Liu return; 115a7210020SGeorge Liu } 116a7210020SGeorge Liu asyncResp->res.addHeader( 117a7210020SGeorge Liu boost::beast::http::field::link, 118a7210020SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 119a7210020SGeorge Liu }); 120a7210020SGeorge Liu } 121a7210020SGeorge Liu 122a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet( 123a7210020SGeorge Liu App& app, const crow::Request& req, 124a7210020SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 125a7210020SGeorge Liu const std::string& chassisId) 126a7210020SGeorge Liu { 127a7210020SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 128a7210020SGeorge Liu { 129a7210020SGeorge Liu return; 130a7210020SGeorge Liu } 131a7210020SGeorge Liu 132a7210020SGeorge Liu redfish::chassis_utils::getValidChassisPath( 133a7210020SGeorge Liu asyncResp, chassisId, 134a7210020SGeorge Liu std::bind_front(doPowerSupplyCollection, asyncResp, chassisId)); 135a7210020SGeorge Liu } 136a7210020SGeorge Liu 137a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app) 138a7210020SGeorge Liu { 139a7210020SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 140a7210020SGeorge Liu .privileges(redfish::privileges::headPowerSupplyCollection) 141a7210020SGeorge Liu .methods(boost::beast::http::verb::head)( 142a7210020SGeorge Liu std::bind_front(handlePowerSupplyCollectionHead, std::ref(app))); 143a7210020SGeorge Liu 144a7210020SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 145a7210020SGeorge Liu .privileges(redfish::privileges::getPowerSupplyCollection) 146a7210020SGeorge Liu .methods(boost::beast::http::verb::get)( 147a7210020SGeorge Liu std::bind_front(handlePowerSupplyCollectionGet, std::ref(app))); 148a7210020SGeorge Liu } 149a7210020SGeorge Liu 15000ef5dc6SGeorge Liu inline bool checkPowerSupplyId(const std::string& powerSupplyPath, 15100ef5dc6SGeorge Liu const std::string& powerSupplyId) 15200ef5dc6SGeorge Liu { 15300ef5dc6SGeorge Liu std::string powerSupplyName = 15400ef5dc6SGeorge Liu sdbusplus::message::object_path(powerSupplyPath).filename(); 15500ef5dc6SGeorge Liu 15600ef5dc6SGeorge Liu return !(powerSupplyName.empty() || powerSupplyName != powerSupplyId); 15700ef5dc6SGeorge Liu } 15800ef5dc6SGeorge Liu 15934dfcb94SGeorge Liu inline void getValidPowerSupplyPath( 16034dfcb94SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 16134dfcb94SGeorge Liu const std::string& validChassisPath, const std::string& powerSupplyId, 16234dfcb94SGeorge Liu std::function<void(const std::string& powerSupplyPath)>&& callback) 16300ef5dc6SGeorge Liu { 16400ef5dc6SGeorge Liu std::string powerPath = validChassisPath + "/powered_by"; 165788fe6cfSLakshmi Yadlapati dbus::utility::getAssociatedSubTreePaths( 166788fe6cfSLakshmi Yadlapati powerPath, 167788fe6cfSLakshmi Yadlapati sdbusplus::message::object_path("/xyz/openbmc_project/inventory"), 0, 168788fe6cfSLakshmi Yadlapati powerSupplyInterface, 169788fe6cfSLakshmi Yadlapati [asyncResp, powerSupplyId, callback{std::move(callback)}]( 17000ef5dc6SGeorge Liu const boost::system::error_code& ec, 171788fe6cfSLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) { 17200ef5dc6SGeorge Liu if (ec) 17300ef5dc6SGeorge Liu { 17400ef5dc6SGeorge Liu if (ec.value() != EBADR) 17500ef5dc6SGeorge Liu { 17662598e31SEd Tanous BMCWEB_LOG_ERROR( 17762598e31SEd Tanous "DBUS response error for getAssociatedSubTreePaths{}", 17862598e31SEd Tanous ec.value()); 17900ef5dc6SGeorge Liu messages::internalError(asyncResp->res); 18000ef5dc6SGeorge Liu return; 18100ef5dc6SGeorge Liu } 18200ef5dc6SGeorge Liu messages::resourceNotFound(asyncResp->res, "PowerSupplies", 18300ef5dc6SGeorge Liu powerSupplyId); 18400ef5dc6SGeorge Liu return; 18500ef5dc6SGeorge Liu } 18600ef5dc6SGeorge Liu 187788fe6cfSLakshmi Yadlapati for (const std::string& path : subtreePaths) 18800ef5dc6SGeorge Liu { 189788fe6cfSLakshmi Yadlapati if (checkPowerSupplyId(path, powerSupplyId)) 19000ef5dc6SGeorge Liu { 191788fe6cfSLakshmi Yadlapati callback(path); 19200ef5dc6SGeorge Liu return; 19300ef5dc6SGeorge Liu } 19400ef5dc6SGeorge Liu } 19500ef5dc6SGeorge Liu 196788fe6cfSLakshmi Yadlapati if (!subtreePaths.empty()) 19700ef5dc6SGeorge Liu { 19862598e31SEd Tanous BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId); 19900ef5dc6SGeorge Liu messages::resourceNotFound(asyncResp->res, "PowerSupplies", 20000ef5dc6SGeorge Liu powerSupplyId); 20100ef5dc6SGeorge Liu return; 20200ef5dc6SGeorge Liu } 20300ef5dc6SGeorge Liu }); 20400ef5dc6SGeorge Liu } 20500ef5dc6SGeorge Liu 20600ef5dc6SGeorge Liu inline void 20734dfcb94SGeorge Liu getPowerSupplyState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 20834dfcb94SGeorge Liu const std::string& service, const std::string& path) 20934dfcb94SGeorge Liu { 21034dfcb94SGeorge Liu sdbusplus::asio::getProperty<bool>( 21134dfcb94SGeorge Liu *crow::connections::systemBus, service, path, 21234dfcb94SGeorge Liu "xyz.openbmc_project.Inventory.Item", "Present", 21334dfcb94SGeorge Liu [asyncResp](const boost::system::error_code& ec, const bool value) { 21434dfcb94SGeorge Liu if (ec) 21534dfcb94SGeorge Liu { 21634dfcb94SGeorge Liu if (ec.value() != EBADR) 21734dfcb94SGeorge Liu { 21862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State {}", 21962598e31SEd Tanous ec.value()); 22034dfcb94SGeorge Liu messages::internalError(asyncResp->res); 22134dfcb94SGeorge Liu } 22234dfcb94SGeorge Liu return; 22334dfcb94SGeorge Liu } 22434dfcb94SGeorge Liu 22534dfcb94SGeorge Liu if (!value) 22634dfcb94SGeorge Liu { 227539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 228539d8c6bSEd Tanous resource::State::Absent; 22934dfcb94SGeorge Liu } 23034dfcb94SGeorge Liu }); 23134dfcb94SGeorge Liu } 23234dfcb94SGeorge Liu 23334dfcb94SGeorge Liu inline void 23434dfcb94SGeorge Liu getPowerSupplyHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 23534dfcb94SGeorge Liu const std::string& service, const std::string& path) 23634dfcb94SGeorge Liu { 23734dfcb94SGeorge Liu sdbusplus::asio::getProperty<bool>( 23834dfcb94SGeorge Liu *crow::connections::systemBus, service, path, 23934dfcb94SGeorge Liu "xyz.openbmc_project.State.Decorator.OperationalStatus", "Functional", 24034dfcb94SGeorge Liu [asyncResp](const boost::system::error_code& ec, const bool value) { 24134dfcb94SGeorge Liu if (ec) 24234dfcb94SGeorge Liu { 24334dfcb94SGeorge Liu if (ec.value() != EBADR) 24434dfcb94SGeorge Liu { 24562598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 24662598e31SEd Tanous ec.value()); 24734dfcb94SGeorge Liu messages::internalError(asyncResp->res); 24834dfcb94SGeorge Liu } 24934dfcb94SGeorge Liu return; 25034dfcb94SGeorge Liu } 25134dfcb94SGeorge Liu 25234dfcb94SGeorge Liu if (!value) 25334dfcb94SGeorge Liu { 254539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = 255539d8c6bSEd Tanous resource::Health::Critical; 25634dfcb94SGeorge Liu } 25734dfcb94SGeorge Liu }); 25834dfcb94SGeorge Liu } 25934dfcb94SGeorge Liu 26034dfcb94SGeorge Liu inline void 2612b45fb3bSGeorge Liu getPowerSupplyAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2622b45fb3bSGeorge Liu const std::string& service, const std::string& path) 2632b45fb3bSGeorge Liu { 2642b45fb3bSGeorge Liu sdbusplus::asio::getAllProperties( 2652b45fb3bSGeorge Liu *crow::connections::systemBus, service, path, 2662b45fb3bSGeorge Liu "xyz.openbmc_project.Inventory.Decorator.Asset", 2672b45fb3bSGeorge Liu [asyncResp](const boost::system::error_code& ec, 2682b45fb3bSGeorge Liu const dbus::utility::DBusPropertiesMap& propertiesList) { 2692b45fb3bSGeorge Liu if (ec) 2702b45fb3bSGeorge Liu { 2712b45fb3bSGeorge Liu if (ec.value() != EBADR) 2722b45fb3bSGeorge Liu { 27362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Asset {}", 27462598e31SEd Tanous ec.value()); 2752b45fb3bSGeorge Liu messages::internalError(asyncResp->res); 2762b45fb3bSGeorge Liu } 2772b45fb3bSGeorge Liu return; 2782b45fb3bSGeorge Liu } 2792b45fb3bSGeorge Liu 2802b45fb3bSGeorge Liu const std::string* partNumber = nullptr; 2812b45fb3bSGeorge Liu const std::string* serialNumber = nullptr; 2822b45fb3bSGeorge Liu const std::string* manufacturer = nullptr; 2832b45fb3bSGeorge Liu const std::string* model = nullptr; 2842b45fb3bSGeorge Liu const std::string* sparePartNumber = nullptr; 2852b45fb3bSGeorge Liu 2862b45fb3bSGeorge Liu const bool success = sdbusplus::unpackPropertiesNoThrow( 2872b45fb3bSGeorge Liu dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 2882b45fb3bSGeorge Liu partNumber, "SerialNumber", serialNumber, "Manufacturer", 289*bd79bce8SPatrick Williams manufacturer, "Model", model, "SparePartNumber", 290*bd79bce8SPatrick Williams sparePartNumber); 2912b45fb3bSGeorge Liu 2922b45fb3bSGeorge Liu if (!success) 2932b45fb3bSGeorge Liu { 2942b45fb3bSGeorge Liu messages::internalError(asyncResp->res); 2952b45fb3bSGeorge Liu return; 2962b45fb3bSGeorge Liu } 2972b45fb3bSGeorge Liu 2982b45fb3bSGeorge Liu if (partNumber != nullptr) 2992b45fb3bSGeorge Liu { 3002b45fb3bSGeorge Liu asyncResp->res.jsonValue["PartNumber"] = *partNumber; 3012b45fb3bSGeorge Liu } 3022b45fb3bSGeorge Liu 3032b45fb3bSGeorge Liu if (serialNumber != nullptr) 3042b45fb3bSGeorge Liu { 3052b45fb3bSGeorge Liu asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 3062b45fb3bSGeorge Liu } 3072b45fb3bSGeorge Liu 3082b45fb3bSGeorge Liu if (manufacturer != nullptr) 3092b45fb3bSGeorge Liu { 3102b45fb3bSGeorge Liu asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 3112b45fb3bSGeorge Liu } 3122b45fb3bSGeorge Liu 3132b45fb3bSGeorge Liu if (model != nullptr) 3142b45fb3bSGeorge Liu { 3152b45fb3bSGeorge Liu asyncResp->res.jsonValue["Model"] = *model; 3162b45fb3bSGeorge Liu } 3172b45fb3bSGeorge Liu 3182b45fb3bSGeorge Liu // SparePartNumber is optional on D-Bus so skip if it is empty 3192b45fb3bSGeorge Liu if (sparePartNumber != nullptr && !sparePartNumber->empty()) 3202b45fb3bSGeorge Liu { 3212b45fb3bSGeorge Liu asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 3222b45fb3bSGeorge Liu } 3232b45fb3bSGeorge Liu }); 3242b45fb3bSGeorge Liu } 3252b45fb3bSGeorge Liu 326a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion( 327a0dba87bSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 328a0dba87bSGeorge Liu const std::string& service, const std::string& path) 329a0dba87bSGeorge Liu { 330a0dba87bSGeorge Liu sdbusplus::asio::getProperty<std::string>( 331a0dba87bSGeorge Liu *crow::connections::systemBus, service, path, 332a0dba87bSGeorge Liu "xyz.openbmc_project.Software.Version", "Version", 333a0dba87bSGeorge Liu [asyncResp](const boost::system::error_code& ec, 334a0dba87bSGeorge Liu const std::string& value) { 335a0dba87bSGeorge Liu if (ec) 336a0dba87bSGeorge Liu { 337a0dba87bSGeorge Liu if (ec.value() != EBADR) 338a0dba87bSGeorge Liu { 339*bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 340*bd79bce8SPatrick Williams "DBUS response error for FirmwareVersion {}", 34162598e31SEd Tanous ec.value()); 342a0dba87bSGeorge Liu messages::internalError(asyncResp->res); 343a0dba87bSGeorge Liu } 344a0dba87bSGeorge Liu return; 345a0dba87bSGeorge Liu } 346a0dba87bSGeorge Liu asyncResp->res.jsonValue["FirmwareVersion"] = value; 347a0dba87bSGeorge Liu }); 348a0dba87bSGeorge Liu } 349a0dba87bSGeorge Liu 3502b45fb3bSGeorge Liu inline void 35144845e5fSGeorge Liu getPowerSupplyLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 35244845e5fSGeorge Liu const std::string& service, const std::string& path) 35344845e5fSGeorge Liu { 35444845e5fSGeorge Liu sdbusplus::asio::getProperty<std::string>( 35544845e5fSGeorge Liu *crow::connections::systemBus, service, path, 35644845e5fSGeorge Liu "xyz.openbmc_project.Inventory.Decorator.LocationCode", "LocationCode", 35744845e5fSGeorge Liu [asyncResp](const boost::system::error_code& ec, 35844845e5fSGeorge Liu const std::string& value) { 35944845e5fSGeorge Liu if (ec) 36044845e5fSGeorge Liu { 36144845e5fSGeorge Liu if (ec.value() != EBADR) 36244845e5fSGeorge Liu { 36362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location {}", 36462598e31SEd Tanous ec.value()); 36544845e5fSGeorge Liu messages::internalError(asyncResp->res); 36644845e5fSGeorge Liu } 36744845e5fSGeorge Liu return; 36844845e5fSGeorge Liu } 369*bd79bce8SPatrick Williams asyncResp->res 370*bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value; 37144845e5fSGeorge Liu }); 37244845e5fSGeorge Liu } 37344845e5fSGeorge Liu 374ddceee07SGeorge Liu inline void handleGetEfficiencyResponse( 375ddceee07SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 376ddceee07SGeorge Liu const boost::system::error_code& ec, uint32_t value) 377ddceee07SGeorge Liu { 378ddceee07SGeorge Liu if (ec) 379ddceee07SGeorge Liu { 380ddceee07SGeorge Liu if (ec.value() != EBADR) 381ddceee07SGeorge Liu { 38262598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for DeratingFactor {}", 38362598e31SEd Tanous ec.value()); 384ddceee07SGeorge Liu messages::internalError(asyncResp->res); 385ddceee07SGeorge Liu } 386ddceee07SGeorge Liu return; 387ddceee07SGeorge Liu } 388ddceee07SGeorge Liu // The PDI default value is 0, if it hasn't been set leave off 389ddceee07SGeorge Liu if (value == 0) 390ddceee07SGeorge Liu { 391ddceee07SGeorge Liu return; 392ddceee07SGeorge Liu } 393ddceee07SGeorge Liu 394ddceee07SGeorge Liu nlohmann::json::array_t efficiencyRatings; 395ddceee07SGeorge Liu nlohmann::json::object_t efficiencyPercent; 396ddceee07SGeorge Liu efficiencyPercent["EfficiencyPercent"] = value; 397ddceee07SGeorge Liu efficiencyRatings.emplace_back(std::move(efficiencyPercent)); 398ddceee07SGeorge Liu asyncResp->res.jsonValue["EfficiencyRatings"] = 399ddceee07SGeorge Liu std::move(efficiencyRatings); 400ddceee07SGeorge Liu } 401ddceee07SGeorge Liu 402ddceee07SGeorge Liu inline void handlePowerSupplyAttributesSubTreeResponse( 403ddceee07SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 404ddceee07SGeorge Liu const boost::system::error_code& ec, 405ddceee07SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) 406ddceee07SGeorge Liu { 407ddceee07SGeorge Liu if (ec) 408ddceee07SGeorge Liu { 409ddceee07SGeorge Liu if (ec.value() != EBADR) 410ddceee07SGeorge Liu { 41162598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}", 41262598e31SEd Tanous ec.value()); 413ddceee07SGeorge Liu messages::internalError(asyncResp->res); 414ddceee07SGeorge Liu } 415ddceee07SGeorge Liu return; 416ddceee07SGeorge Liu } 417ddceee07SGeorge Liu 418ddceee07SGeorge Liu if (subtree.empty()) 419ddceee07SGeorge Liu { 42062598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!"); 421ddceee07SGeorge Liu return; 422ddceee07SGeorge Liu } 423ddceee07SGeorge Liu 424ddceee07SGeorge Liu if (subtree.size() != 1) 425ddceee07SGeorge Liu { 42662598e31SEd Tanous BMCWEB_LOG_ERROR( 42762598e31SEd Tanous "Unexpected number of paths returned by getSubTree: {}", 42862598e31SEd Tanous subtree.size()); 429ddceee07SGeorge Liu messages::internalError(asyncResp->res); 430ddceee07SGeorge Liu return; 431ddceee07SGeorge Liu } 432ddceee07SGeorge Liu 433ddceee07SGeorge Liu const auto& [path, serviceMap] = *subtree.begin(); 434ddceee07SGeorge Liu const auto& [service, interfaces] = *serviceMap.begin(); 435ddceee07SGeorge Liu sdbusplus::asio::getProperty<uint32_t>( 436ddceee07SGeorge Liu *crow::connections::systemBus, service, path, 437ddceee07SGeorge Liu "xyz.openbmc_project.Control.PowerSupplyAttributes", "DeratingFactor", 438ddceee07SGeorge Liu [asyncResp](const boost::system::error_code& ec1, uint32_t value) { 439ddceee07SGeorge Liu handleGetEfficiencyResponse(asyncResp, ec1, value); 440ddceee07SGeorge Liu }); 441ddceee07SGeorge Liu } 442ddceee07SGeorge Liu 443ddceee07SGeorge Liu inline void 444ddceee07SGeorge Liu getEfficiencyPercent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 445ddceee07SGeorge Liu { 446ddceee07SGeorge Liu constexpr std::array<std::string_view, 1> efficiencyIntf = { 447ddceee07SGeorge Liu "xyz.openbmc_project.Control.PowerSupplyAttributes"}; 448ddceee07SGeorge Liu 449ddceee07SGeorge Liu dbus::utility::getSubTree( 450ddceee07SGeorge Liu "/xyz/openbmc_project", 0, efficiencyIntf, 451ddceee07SGeorge Liu [asyncResp](const boost::system::error_code& ec, 452ddceee07SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) { 453ddceee07SGeorge Liu handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree); 454ddceee07SGeorge Liu }); 455ddceee07SGeorge Liu } 456ddceee07SGeorge Liu 457*bd79bce8SPatrick Williams inline void doPowerSupplyGet( 458*bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 459*bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId, 46000ef5dc6SGeorge Liu const std::optional<std::string>& validChassisPath) 46100ef5dc6SGeorge Liu { 46200ef5dc6SGeorge Liu if (!validChassisPath) 46300ef5dc6SGeorge Liu { 46400ef5dc6SGeorge Liu messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); 46500ef5dc6SGeorge Liu return; 46600ef5dc6SGeorge Liu } 46700ef5dc6SGeorge Liu 46800ef5dc6SGeorge Liu // Get the correct Path and Service that match the input parameters 469*bd79bce8SPatrick Williams getValidPowerSupplyPath( 470*bd79bce8SPatrick Williams asyncResp, *validChassisPath, powerSupplyId, 471*bd79bce8SPatrick Williams [asyncResp, chassisId, 472*bd79bce8SPatrick Williams powerSupplyId](const std::string& powerSupplyPath) { 47300ef5dc6SGeorge Liu asyncResp->res.addHeader( 47400ef5dc6SGeorge Liu boost::beast::http::field::link, 47500ef5dc6SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 47600ef5dc6SGeorge Liu asyncResp->res.jsonValue["@odata.type"] = 47700ef5dc6SGeorge Liu "#PowerSupply.v1_5_0.PowerSupply"; 47800ef5dc6SGeorge Liu asyncResp->res.jsonValue["Name"] = "Power Supply"; 47900ef5dc6SGeorge Liu asyncResp->res.jsonValue["Id"] = powerSupplyId; 48000ef5dc6SGeorge Liu asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 481*bd79bce8SPatrick Williams "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", 482*bd79bce8SPatrick Williams chassisId, powerSupplyId); 48334dfcb94SGeorge Liu 484*bd79bce8SPatrick Williams asyncResp->res.jsonValue["Status"]["State"] = 485*bd79bce8SPatrick Williams resource::State::Enabled; 486539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK; 48734dfcb94SGeorge Liu 48834dfcb94SGeorge Liu dbus::utility::getDbusObject( 489788fe6cfSLakshmi Yadlapati powerSupplyPath, powerSupplyInterface, 490*bd79bce8SPatrick Williams [asyncResp, powerSupplyPath]( 491*bd79bce8SPatrick Williams const boost::system::error_code& ec, 49234dfcb94SGeorge Liu const dbus::utility::MapperGetObject& object) { 49334dfcb94SGeorge Liu if (ec || object.empty()) 49434dfcb94SGeorge Liu { 49534dfcb94SGeorge Liu messages::internalError(asyncResp->res); 49634dfcb94SGeorge Liu return; 49734dfcb94SGeorge Liu } 49834dfcb94SGeorge Liu 49934dfcb94SGeorge Liu getPowerSupplyState(asyncResp, object.begin()->first, 50034dfcb94SGeorge Liu powerSupplyPath); 50134dfcb94SGeorge Liu getPowerSupplyHealth(asyncResp, object.begin()->first, 50234dfcb94SGeorge Liu powerSupplyPath); 5032b45fb3bSGeorge Liu getPowerSupplyAsset(asyncResp, object.begin()->first, 5042b45fb3bSGeorge Liu powerSupplyPath); 505*bd79bce8SPatrick Williams getPowerSupplyFirmwareVersion( 506*bd79bce8SPatrick Williams asyncResp, object.begin()->first, powerSupplyPath); 50744845e5fSGeorge Liu getPowerSupplyLocation(asyncResp, object.begin()->first, 50844845e5fSGeorge Liu powerSupplyPath); 50934dfcb94SGeorge Liu }); 510ddceee07SGeorge Liu 511ddceee07SGeorge Liu getEfficiencyPercent(asyncResp); 51200ef5dc6SGeorge Liu }); 51300ef5dc6SGeorge Liu } 51400ef5dc6SGeorge Liu 515*bd79bce8SPatrick Williams inline void handlePowerSupplyHead( 516*bd79bce8SPatrick Williams App& app, const crow::Request& req, 51700ef5dc6SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 518*bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId) 51900ef5dc6SGeorge Liu { 52000ef5dc6SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 52100ef5dc6SGeorge Liu { 52200ef5dc6SGeorge Liu return; 52300ef5dc6SGeorge Liu } 52400ef5dc6SGeorge Liu 52500ef5dc6SGeorge Liu redfish::chassis_utils::getValidChassisPath( 52600ef5dc6SGeorge Liu asyncResp, chassisId, 52700ef5dc6SGeorge Liu [asyncResp, chassisId, 52800ef5dc6SGeorge Liu powerSupplyId](const std::optional<std::string>& validChassisPath) { 52900ef5dc6SGeorge Liu if (!validChassisPath) 53000ef5dc6SGeorge Liu { 531*bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 532*bd79bce8SPatrick Williams chassisId); 53300ef5dc6SGeorge Liu return; 53400ef5dc6SGeorge Liu } 53500ef5dc6SGeorge Liu 53600ef5dc6SGeorge Liu // Get the correct Path and Service that match the input parameters 537*bd79bce8SPatrick Williams getValidPowerSupplyPath( 538*bd79bce8SPatrick Williams asyncResp, *validChassisPath, powerSupplyId, 53934dfcb94SGeorge Liu [asyncResp](const std::string&) { 54000ef5dc6SGeorge Liu asyncResp->res.addHeader( 54100ef5dc6SGeorge Liu boost::beast::http::field::link, 54200ef5dc6SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 54300ef5dc6SGeorge Liu }); 54400ef5dc6SGeorge Liu }); 54500ef5dc6SGeorge Liu } 54600ef5dc6SGeorge Liu 547*bd79bce8SPatrick Williams inline void handlePowerSupplyGet( 548*bd79bce8SPatrick Williams App& app, const crow::Request& req, 54900ef5dc6SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 550*bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId) 55100ef5dc6SGeorge Liu { 55200ef5dc6SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 55300ef5dc6SGeorge Liu { 55400ef5dc6SGeorge Liu return; 55500ef5dc6SGeorge Liu } 55600ef5dc6SGeorge Liu 55700ef5dc6SGeorge Liu redfish::chassis_utils::getValidChassisPath( 55800ef5dc6SGeorge Liu asyncResp, chassisId, 55900ef5dc6SGeorge Liu std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId)); 56000ef5dc6SGeorge Liu } 56100ef5dc6SGeorge Liu 56200ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app) 56300ef5dc6SGeorge Liu { 56400ef5dc6SGeorge Liu BMCWEB_ROUTE( 56500ef5dc6SGeorge Liu app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 56600ef5dc6SGeorge Liu .privileges(redfish::privileges::headPowerSupply) 56700ef5dc6SGeorge Liu .methods(boost::beast::http::verb::head)( 56800ef5dc6SGeorge Liu std::bind_front(handlePowerSupplyHead, std::ref(app))); 56900ef5dc6SGeorge Liu 57000ef5dc6SGeorge Liu BMCWEB_ROUTE( 57100ef5dc6SGeorge Liu app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 57200ef5dc6SGeorge Liu .privileges(redfish::privileges::getPowerSupply) 57300ef5dc6SGeorge Liu .methods(boost::beast::http::verb::get)( 57400ef5dc6SGeorge Liu std::bind_front(handlePowerSupplyGet, std::ref(app))); 57500ef5dc6SGeorge Liu } 57600ef5dc6SGeorge Liu 577a7210020SGeorge Liu } // namespace redfish 578