140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 3a7210020SGeorge Liu #pragma once 4a7210020SGeorge Liu 5a7210020SGeorge Liu #include "app.hpp" 6*d7857201SEd Tanous #include "async_resp.hpp" 7a7210020SGeorge Liu #include "dbus_utility.hpp" 8*d7857201SEd Tanous #include "error_messages.hpp" 9539d8c6bSEd Tanous #include "generated/enums/resource.hpp" 10*d7857201SEd Tanous #include "http_request.hpp" 11*d7857201SEd Tanous #include "logging.hpp" 12a7210020SGeorge Liu #include "query.hpp" 13a7210020SGeorge Liu #include "registries/privilege_registry.hpp" 14a7210020SGeorge Liu #include "utils/chassis_utils.hpp" 152b45fb3bSGeorge Liu #include "utils/dbus_utils.hpp" 16b5190062SHieu Huynh #include "utils/time_utils.hpp" 17a7210020SGeorge Liu 18*d7857201SEd Tanous #include <asm-generic/errno.h> 19*d7857201SEd Tanous 20*d7857201SEd Tanous #include <boost/beast/http/field.hpp> 21*d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 2234dfcb94SGeorge Liu #include <boost/system/error_code.hpp> 23ef4c65b7SEd Tanous #include <boost/url/format.hpp> 24*d7857201SEd Tanous #include <nlohmann/json.hpp> 25*d7857201SEd Tanous #include <sdbusplus/unpack_properties.hpp> 26ef4c65b7SEd Tanous 27*d7857201SEd Tanous #include <array> 28*d7857201SEd Tanous #include <cstdint> 29*d7857201SEd Tanous #include <functional> 30a7210020SGeorge Liu #include <memory> 31a7210020SGeorge Liu #include <optional> 32a7210020SGeorge Liu #include <string> 33*d7857201SEd Tanous #include <string_view> 34*d7857201SEd Tanous #include <utility> 35a7210020SGeorge Liu 36a7210020SGeorge Liu namespace redfish 37a7210020SGeorge Liu { 38a7210020SGeorge Liu 39788fe6cfSLakshmi Yadlapati static constexpr std::array<std::string_view, 1> powerSupplyInterface = { 40788fe6cfSLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.PowerSupply"}; 41788fe6cfSLakshmi Yadlapati 42788fe6cfSLakshmi Yadlapati inline void updatePowerSupplyList( 43788fe6cfSLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 4400ef5dc6SGeorge Liu const std::string& chassisId, 45788fe6cfSLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& powerSupplyPaths) 46788fe6cfSLakshmi Yadlapati { 47788fe6cfSLakshmi Yadlapati nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"]; 48788fe6cfSLakshmi Yadlapati for (const std::string& powerSupplyPath : powerSupplyPaths) 49a7210020SGeorge Liu { 5000ef5dc6SGeorge Liu std::string powerSupplyName = 5100ef5dc6SGeorge Liu sdbusplus::message::object_path(powerSupplyPath).filename(); 5200ef5dc6SGeorge Liu if (powerSupplyName.empty()) 5300ef5dc6SGeorge Liu { 54788fe6cfSLakshmi Yadlapati continue; 5500ef5dc6SGeorge Liu } 5600ef5dc6SGeorge Liu 5700ef5dc6SGeorge Liu nlohmann::json item = nlohmann::json::object(); 5800ef5dc6SGeorge Liu item["@odata.id"] = boost::urls::format( 5900ef5dc6SGeorge Liu "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 6000ef5dc6SGeorge Liu powerSupplyName); 6100ef5dc6SGeorge Liu 6200ef5dc6SGeorge Liu powerSupplyList.emplace_back(std::move(item)); 63788fe6cfSLakshmi Yadlapati } 6400ef5dc6SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size(); 65a7210020SGeorge Liu } 66a7210020SGeorge Liu 673e42a329SLakshmi Yadlapati inline void doPowerSupplyCollection( 683e42a329SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 693e42a329SLakshmi Yadlapati const std::string& chassisId, const boost::system::error_code& ec, 703e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) 71a7210020SGeorge Liu { 723e42a329SLakshmi Yadlapati if (ec) 73a7210020SGeorge Liu { 743e42a329SLakshmi Yadlapati if (ec.value() != EBADR) 753e42a329SLakshmi Yadlapati { 763e42a329SLakshmi Yadlapati BMCWEB_LOG_ERROR("DBUS response error{}", ec.value()); 773e42a329SLakshmi Yadlapati messages::internalError(asyncResp->res); 783e42a329SLakshmi Yadlapati } 79a7210020SGeorge Liu return; 80a7210020SGeorge Liu } 81a7210020SGeorge Liu asyncResp->res.addHeader( 82a7210020SGeorge Liu boost::beast::http::field::link, 83a7210020SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 84a7210020SGeorge Liu asyncResp->res.jsonValue["@odata.type"] = 85a7210020SGeorge Liu "#PowerSupplyCollection.PowerSupplyCollection"; 86a7210020SGeorge Liu asyncResp->res.jsonValue["Name"] = "Power Supply Collection"; 87ef4c65b7SEd Tanous asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 88ef4c65b7SEd Tanous "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies", chassisId); 89a7210020SGeorge Liu asyncResp->res.jsonValue["Description"] = 90a7210020SGeorge Liu "The collection of PowerSupply resource instances."; 917a2bb2c9SGeorge Liu asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); 927a2bb2c9SGeorge Liu asyncResp->res.jsonValue["Members@odata.count"] = 0; 93a7210020SGeorge Liu 94788fe6cfSLakshmi Yadlapati updatePowerSupplyList(asyncResp, chassisId, subtreePaths); 95a7210020SGeorge Liu } 96a7210020SGeorge Liu 97a7210020SGeorge Liu inline void handlePowerSupplyCollectionHead( 98a7210020SGeorge Liu App& app, const crow::Request& req, 99a7210020SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 100a7210020SGeorge Liu const std::string& chassisId) 101a7210020SGeorge Liu { 102a7210020SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 103a7210020SGeorge Liu { 104a7210020SGeorge Liu return; 105a7210020SGeorge Liu } 106a7210020SGeorge Liu 107a7210020SGeorge Liu redfish::chassis_utils::getValidChassisPath( 108a7210020SGeorge Liu asyncResp, chassisId, 109a7210020SGeorge Liu [asyncResp, 110a7210020SGeorge Liu chassisId](const std::optional<std::string>& validChassisPath) { 111a7210020SGeorge Liu if (!validChassisPath) 112a7210020SGeorge Liu { 113bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, "Chassis", 114bd79bce8SPatrick Williams chassisId); 115a7210020SGeorge Liu return; 116a7210020SGeorge Liu } 117a7210020SGeorge Liu asyncResp->res.addHeader( 118a7210020SGeorge Liu boost::beast::http::field::link, 119a7210020SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupplyCollection/PowerSupplyCollection.json>; rel=describedby"); 120a7210020SGeorge Liu }); 121a7210020SGeorge Liu } 122a7210020SGeorge Liu 123a7210020SGeorge Liu inline void handlePowerSupplyCollectionGet( 124a7210020SGeorge Liu App& app, const crow::Request& req, 125a7210020SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 126a7210020SGeorge Liu const std::string& chassisId) 127a7210020SGeorge Liu { 128a7210020SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 129a7210020SGeorge Liu { 130a7210020SGeorge Liu return; 131a7210020SGeorge Liu } 132a7210020SGeorge Liu 1333e42a329SLakshmi Yadlapati constexpr std::array<std::string_view, 2> chasisInterfaces = { 1343e42a329SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.Board", 1353e42a329SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.Chassis"}; 1363e42a329SLakshmi Yadlapati const std::string reqpath = "/xyz/openbmc_project/inventory"; 1373e42a329SLakshmi Yadlapati 1383e42a329SLakshmi Yadlapati dbus::utility::getAssociatedSubTreePathsById( 1393e42a329SLakshmi Yadlapati chassisId, reqpath, chasisInterfaces, "powered_by", 1403e42a329SLakshmi Yadlapati powerSupplyInterface, 1413e42a329SLakshmi Yadlapati [asyncResp, chassisId]( 1423e42a329SLakshmi Yadlapati const boost::system::error_code& ec, 1433e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreePathsResponse& subtreePaths) { 1443e42a329SLakshmi Yadlapati doPowerSupplyCollection(asyncResp, chassisId, ec, subtreePaths); 1453e42a329SLakshmi Yadlapati }); 146a7210020SGeorge Liu } 147a7210020SGeorge Liu 148a7210020SGeorge Liu inline void requestRoutesPowerSupplyCollection(App& app) 149a7210020SGeorge Liu { 150a7210020SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 151a7210020SGeorge Liu .privileges(redfish::privileges::headPowerSupplyCollection) 152a7210020SGeorge Liu .methods(boost::beast::http::verb::head)( 153a7210020SGeorge Liu std::bind_front(handlePowerSupplyCollectionHead, std::ref(app))); 154a7210020SGeorge Liu 155a7210020SGeorge Liu BMCWEB_ROUTE(app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/") 156a7210020SGeorge Liu .privileges(redfish::privileges::getPowerSupplyCollection) 157a7210020SGeorge Liu .methods(boost::beast::http::verb::get)( 158a7210020SGeorge Liu std::bind_front(handlePowerSupplyCollectionGet, std::ref(app))); 159a7210020SGeorge Liu } 160a7210020SGeorge Liu 1613e42a329SLakshmi Yadlapati inline void afterGetValidPowerSupplyPath( 16234dfcb94SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1633e42a329SLakshmi Yadlapati const std::string& powerSupplyId, const boost::system::error_code& ec, 1643e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreeResponse& subtree, 1653e42a329SLakshmi Yadlapati const std::function<void(const std::string& powerSupplyPath, 1663e42a329SLakshmi Yadlapati const std::string& service)>& callback) 16700ef5dc6SGeorge Liu { 16800ef5dc6SGeorge Liu if (ec) 16900ef5dc6SGeorge Liu { 17000ef5dc6SGeorge Liu if (ec.value() != EBADR) 17100ef5dc6SGeorge Liu { 1723e42a329SLakshmi Yadlapati BMCWEB_LOG_ERROR("DBUS response error{}", ec.value()); 17300ef5dc6SGeorge Liu messages::internalError(asyncResp->res); 1743e42a329SLakshmi Yadlapati } 17500ef5dc6SGeorge Liu return; 17600ef5dc6SGeorge Liu } 1773e42a329SLakshmi Yadlapati for (const auto& [objectPath, service] : subtree) 17800ef5dc6SGeorge Liu { 1793e42a329SLakshmi Yadlapati sdbusplus::message::object_path path(objectPath); 180d8e2b618SMyung Bae if (path.filename() == powerSupplyId) 18100ef5dc6SGeorge Liu { 1823e42a329SLakshmi Yadlapati callback(path, service.begin()->first); 18300ef5dc6SGeorge Liu return; 18400ef5dc6SGeorge Liu } 18500ef5dc6SGeorge Liu } 18600ef5dc6SGeorge Liu 18762598e31SEd Tanous BMCWEB_LOG_WARNING("Power supply not found: {}", powerSupplyId); 1883e42a329SLakshmi Yadlapati messages::resourceNotFound(asyncResp->res, "PowerSupplies", powerSupplyId); 18900ef5dc6SGeorge Liu } 1903e42a329SLakshmi Yadlapati 1913e42a329SLakshmi Yadlapati inline void getValidPowerSupplyPath( 1923e42a329SLakshmi Yadlapati const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1933e42a329SLakshmi Yadlapati const std::string& chassisId, const std::string& powerSupplyId, 1943e42a329SLakshmi Yadlapati std::function<void(const std::string& powerSupplyPath, 1953e42a329SLakshmi Yadlapati const std::string& service)>&& callback) 1963e42a329SLakshmi Yadlapati { 1973e42a329SLakshmi Yadlapati constexpr std::array<std::string_view, 2> chasisInterfaces = { 1983e42a329SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.Board", 1993e42a329SLakshmi Yadlapati "xyz.openbmc_project.Inventory.Item.Chassis"}; 2003e42a329SLakshmi Yadlapati const std::string reqpath = "/xyz/openbmc_project/inventory"; 2013e42a329SLakshmi Yadlapati 2023e42a329SLakshmi Yadlapati dbus::utility::getAssociatedSubTreeById( 2033e42a329SLakshmi Yadlapati chassisId, reqpath, chasisInterfaces, "powered_by", 2043e42a329SLakshmi Yadlapati powerSupplyInterface, 2053e42a329SLakshmi Yadlapati [asyncResp, chassisId, powerSupplyId, callback{std::move(callback)}]( 2063e42a329SLakshmi Yadlapati const boost::system::error_code& ec, 2073e42a329SLakshmi Yadlapati const dbus::utility::MapperGetSubTreeResponse& subtree) { 2083e42a329SLakshmi Yadlapati afterGetValidPowerSupplyPath(asyncResp, powerSupplyId, ec, subtree, 2093e42a329SLakshmi Yadlapati callback); 21000ef5dc6SGeorge Liu }); 21100ef5dc6SGeorge Liu } 21200ef5dc6SGeorge Liu 21300ef5dc6SGeorge Liu inline void 21434dfcb94SGeorge Liu getPowerSupplyState(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 21534dfcb94SGeorge Liu const std::string& service, const std::string& path) 21634dfcb94SGeorge Liu { 217deae6a78SEd Tanous dbus::utility::getProperty<bool>( 218deae6a78SEd Tanous service, path, "xyz.openbmc_project.Inventory.Item", "Present", 21934dfcb94SGeorge Liu [asyncResp](const boost::system::error_code& ec, const bool value) { 22034dfcb94SGeorge Liu if (ec) 22134dfcb94SGeorge Liu { 22234dfcb94SGeorge Liu if (ec.value() != EBADR) 22334dfcb94SGeorge Liu { 22462598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for State {}", 22562598e31SEd Tanous ec.value()); 22634dfcb94SGeorge Liu messages::internalError(asyncResp->res); 22734dfcb94SGeorge Liu } 22834dfcb94SGeorge Liu return; 22934dfcb94SGeorge Liu } 23034dfcb94SGeorge Liu 23134dfcb94SGeorge Liu if (!value) 23234dfcb94SGeorge Liu { 233539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["State"] = 234539d8c6bSEd Tanous resource::State::Absent; 23534dfcb94SGeorge Liu } 23634dfcb94SGeorge Liu }); 23734dfcb94SGeorge Liu } 23834dfcb94SGeorge Liu 23934dfcb94SGeorge Liu inline void 24034dfcb94SGeorge Liu getPowerSupplyHealth(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 24134dfcb94SGeorge Liu const std::string& service, const std::string& path) 24234dfcb94SGeorge Liu { 243deae6a78SEd Tanous dbus::utility::getProperty<bool>( 244deae6a78SEd Tanous service, path, "xyz.openbmc_project.State.Decorator.OperationalStatus", 245deae6a78SEd Tanous "Functional", 24634dfcb94SGeorge Liu [asyncResp](const boost::system::error_code& ec, const bool value) { 24734dfcb94SGeorge Liu if (ec) 24834dfcb94SGeorge Liu { 24934dfcb94SGeorge Liu if (ec.value() != EBADR) 25034dfcb94SGeorge Liu { 25162598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Health {}", 25262598e31SEd Tanous ec.value()); 25334dfcb94SGeorge Liu messages::internalError(asyncResp->res); 25434dfcb94SGeorge Liu } 25534dfcb94SGeorge Liu return; 25634dfcb94SGeorge Liu } 25734dfcb94SGeorge Liu 25834dfcb94SGeorge Liu if (!value) 25934dfcb94SGeorge Liu { 260539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = 261539d8c6bSEd Tanous resource::Health::Critical; 26234dfcb94SGeorge Liu } 26334dfcb94SGeorge Liu }); 26434dfcb94SGeorge Liu } 26534dfcb94SGeorge Liu 26634dfcb94SGeorge Liu inline void 2672b45fb3bSGeorge Liu getPowerSupplyAsset(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2682b45fb3bSGeorge Liu const std::string& service, const std::string& path) 2692b45fb3bSGeorge Liu { 270deae6a78SEd Tanous dbus::utility::getAllProperties( 271deae6a78SEd Tanous service, path, "xyz.openbmc_project.Inventory.Decorator.Asset", 2722b45fb3bSGeorge Liu [asyncResp](const boost::system::error_code& ec, 2732b45fb3bSGeorge Liu const dbus::utility::DBusPropertiesMap& propertiesList) { 2742b45fb3bSGeorge Liu if (ec) 2752b45fb3bSGeorge Liu { 2762b45fb3bSGeorge Liu if (ec.value() != EBADR) 2772b45fb3bSGeorge Liu { 27862598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Asset {}", 27962598e31SEd Tanous ec.value()); 2802b45fb3bSGeorge Liu messages::internalError(asyncResp->res); 2812b45fb3bSGeorge Liu } 2822b45fb3bSGeorge Liu return; 2832b45fb3bSGeorge Liu } 2842b45fb3bSGeorge Liu 2852b45fb3bSGeorge Liu const std::string* partNumber = nullptr; 2862b45fb3bSGeorge Liu const std::string* serialNumber = nullptr; 2872b45fb3bSGeorge Liu const std::string* manufacturer = nullptr; 2882b45fb3bSGeorge Liu const std::string* model = nullptr; 2892b45fb3bSGeorge Liu const std::string* sparePartNumber = nullptr; 290b5190062SHieu Huynh const std::string* buildDate = nullptr; 2912b45fb3bSGeorge Liu 2922b45fb3bSGeorge Liu const bool success = sdbusplus::unpackPropertiesNoThrow( 2932b45fb3bSGeorge Liu dbus_utils::UnpackErrorPrinter(), propertiesList, "PartNumber", 2942b45fb3bSGeorge Liu partNumber, "SerialNumber", serialNumber, "Manufacturer", 295bd79bce8SPatrick Williams manufacturer, "Model", model, "SparePartNumber", 296b5190062SHieu Huynh sparePartNumber, "BuildDate", buildDate); 2972b45fb3bSGeorge Liu 2982b45fb3bSGeorge Liu if (!success) 2992b45fb3bSGeorge Liu { 3002b45fb3bSGeorge Liu messages::internalError(asyncResp->res); 3012b45fb3bSGeorge Liu return; 3022b45fb3bSGeorge Liu } 3032b45fb3bSGeorge Liu 3042b45fb3bSGeorge Liu if (partNumber != nullptr) 3052b45fb3bSGeorge Liu { 3062b45fb3bSGeorge Liu asyncResp->res.jsonValue["PartNumber"] = *partNumber; 3072b45fb3bSGeorge Liu } 3082b45fb3bSGeorge Liu 3092b45fb3bSGeorge Liu if (serialNumber != nullptr) 3102b45fb3bSGeorge Liu { 3112b45fb3bSGeorge Liu asyncResp->res.jsonValue["SerialNumber"] = *serialNumber; 3122b45fb3bSGeorge Liu } 3132b45fb3bSGeorge Liu 3142b45fb3bSGeorge Liu if (manufacturer != nullptr) 3152b45fb3bSGeorge Liu { 3162b45fb3bSGeorge Liu asyncResp->res.jsonValue["Manufacturer"] = *manufacturer; 3172b45fb3bSGeorge Liu } 3182b45fb3bSGeorge Liu 3192b45fb3bSGeorge Liu if (model != nullptr) 3202b45fb3bSGeorge Liu { 3212b45fb3bSGeorge Liu asyncResp->res.jsonValue["Model"] = *model; 3222b45fb3bSGeorge Liu } 3232b45fb3bSGeorge Liu 3242b45fb3bSGeorge Liu // SparePartNumber is optional on D-Bus so skip if it is empty 3252b45fb3bSGeorge Liu if (sparePartNumber != nullptr && !sparePartNumber->empty()) 3262b45fb3bSGeorge Liu { 3272b45fb3bSGeorge Liu asyncResp->res.jsonValue["SparePartNumber"] = *sparePartNumber; 3282b45fb3bSGeorge Liu } 329b5190062SHieu Huynh 330b5190062SHieu Huynh if (buildDate != nullptr) 331b5190062SHieu Huynh { 332b5190062SHieu Huynh time_utils::productionDateReport(asyncResp->res, *buildDate); 333b5190062SHieu Huynh } 3342b45fb3bSGeorge Liu }); 3352b45fb3bSGeorge Liu } 3362b45fb3bSGeorge Liu 337a0dba87bSGeorge Liu inline void getPowerSupplyFirmwareVersion( 338a0dba87bSGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 339a0dba87bSGeorge Liu const std::string& service, const std::string& path) 340a0dba87bSGeorge Liu { 341deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 342deae6a78SEd Tanous service, path, "xyz.openbmc_project.Software.Version", "Version", 343a0dba87bSGeorge Liu [asyncResp](const boost::system::error_code& ec, 344a0dba87bSGeorge Liu const std::string& value) { 345a0dba87bSGeorge Liu if (ec) 346a0dba87bSGeorge Liu { 347a0dba87bSGeorge Liu if (ec.value() != EBADR) 348a0dba87bSGeorge Liu { 349bd79bce8SPatrick Williams BMCWEB_LOG_ERROR( 350bd79bce8SPatrick Williams "DBUS response error for FirmwareVersion {}", 35162598e31SEd Tanous ec.value()); 352a0dba87bSGeorge Liu messages::internalError(asyncResp->res); 353a0dba87bSGeorge Liu } 354a0dba87bSGeorge Liu return; 355a0dba87bSGeorge Liu } 356a0dba87bSGeorge Liu asyncResp->res.jsonValue["FirmwareVersion"] = value; 357a0dba87bSGeorge Liu }); 358a0dba87bSGeorge Liu } 359a0dba87bSGeorge Liu 3602b45fb3bSGeorge Liu inline void 36144845e5fSGeorge Liu getPowerSupplyLocation(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 36244845e5fSGeorge Liu const std::string& service, const std::string& path) 36344845e5fSGeorge Liu { 364deae6a78SEd Tanous dbus::utility::getProperty<std::string>( 365deae6a78SEd Tanous service, path, "xyz.openbmc_project.Inventory.Decorator.LocationCode", 366deae6a78SEd Tanous "LocationCode", 36744845e5fSGeorge Liu [asyncResp](const boost::system::error_code& ec, 36844845e5fSGeorge Liu const std::string& value) { 36944845e5fSGeorge Liu if (ec) 37044845e5fSGeorge Liu { 37144845e5fSGeorge Liu if (ec.value() != EBADR) 37244845e5fSGeorge Liu { 37362598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for Location {}", 37462598e31SEd Tanous ec.value()); 37544845e5fSGeorge Liu messages::internalError(asyncResp->res); 37644845e5fSGeorge Liu } 37744845e5fSGeorge Liu return; 37844845e5fSGeorge Liu } 379bd79bce8SPatrick Williams asyncResp->res 380bd79bce8SPatrick Williams .jsonValue["Location"]["PartLocation"]["ServiceLabel"] = value; 38144845e5fSGeorge Liu }); 38244845e5fSGeorge Liu } 38344845e5fSGeorge Liu 384ddceee07SGeorge Liu inline void handleGetEfficiencyResponse( 385ddceee07SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 386ddceee07SGeorge Liu const boost::system::error_code& ec, uint32_t value) 387ddceee07SGeorge Liu { 388ddceee07SGeorge Liu if (ec) 389ddceee07SGeorge Liu { 390ddceee07SGeorge Liu if (ec.value() != EBADR) 391ddceee07SGeorge Liu { 39262598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for DeratingFactor {}", 39362598e31SEd Tanous ec.value()); 394ddceee07SGeorge Liu messages::internalError(asyncResp->res); 395ddceee07SGeorge Liu } 396ddceee07SGeorge Liu return; 397ddceee07SGeorge Liu } 398ddceee07SGeorge Liu // The PDI default value is 0, if it hasn't been set leave off 399ddceee07SGeorge Liu if (value == 0) 400ddceee07SGeorge Liu { 401ddceee07SGeorge Liu return; 402ddceee07SGeorge Liu } 403ddceee07SGeorge Liu 404ddceee07SGeorge Liu nlohmann::json::array_t efficiencyRatings; 405ddceee07SGeorge Liu nlohmann::json::object_t efficiencyPercent; 406ddceee07SGeorge Liu efficiencyPercent["EfficiencyPercent"] = value; 407ddceee07SGeorge Liu efficiencyRatings.emplace_back(std::move(efficiencyPercent)); 408ddceee07SGeorge Liu asyncResp->res.jsonValue["EfficiencyRatings"] = 409ddceee07SGeorge Liu std::move(efficiencyRatings); 410ddceee07SGeorge Liu } 411ddceee07SGeorge Liu 412ddceee07SGeorge Liu inline void handlePowerSupplyAttributesSubTreeResponse( 413ddceee07SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 414ddceee07SGeorge Liu const boost::system::error_code& ec, 415ddceee07SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) 416ddceee07SGeorge Liu { 417ddceee07SGeorge Liu if (ec) 418ddceee07SGeorge Liu { 419ddceee07SGeorge Liu if (ec.value() != EBADR) 420ddceee07SGeorge Liu { 42162598e31SEd Tanous BMCWEB_LOG_ERROR("DBUS response error for EfficiencyPercent {}", 42262598e31SEd Tanous ec.value()); 423ddceee07SGeorge Liu messages::internalError(asyncResp->res); 424ddceee07SGeorge Liu } 425ddceee07SGeorge Liu return; 426ddceee07SGeorge Liu } 427ddceee07SGeorge Liu 428ddceee07SGeorge Liu if (subtree.empty()) 429ddceee07SGeorge Liu { 43062598e31SEd Tanous BMCWEB_LOG_DEBUG("Can't find Power Supply Attributes!"); 431ddceee07SGeorge Liu return; 432ddceee07SGeorge Liu } 433ddceee07SGeorge Liu 434ddceee07SGeorge Liu if (subtree.size() != 1) 435ddceee07SGeorge Liu { 43662598e31SEd Tanous BMCWEB_LOG_ERROR( 43762598e31SEd Tanous "Unexpected number of paths returned by getSubTree: {}", 43862598e31SEd Tanous subtree.size()); 439ddceee07SGeorge Liu messages::internalError(asyncResp->res); 440ddceee07SGeorge Liu return; 441ddceee07SGeorge Liu } 442ddceee07SGeorge Liu 443ddceee07SGeorge Liu const auto& [path, serviceMap] = *subtree.begin(); 444ddceee07SGeorge Liu const auto& [service, interfaces] = *serviceMap.begin(); 445deae6a78SEd Tanous dbus::utility::getProperty<uint32_t>( 446deae6a78SEd Tanous service, path, "xyz.openbmc_project.Control.PowerSupplyAttributes", 447deae6a78SEd Tanous "DeratingFactor", 448ddceee07SGeorge Liu [asyncResp](const boost::system::error_code& ec1, uint32_t value) { 449ddceee07SGeorge Liu handleGetEfficiencyResponse(asyncResp, ec1, value); 450ddceee07SGeorge Liu }); 451ddceee07SGeorge Liu } 452ddceee07SGeorge Liu 453ddceee07SGeorge Liu inline void 454ddceee07SGeorge Liu getEfficiencyPercent(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 455ddceee07SGeorge Liu { 456ddceee07SGeorge Liu constexpr std::array<std::string_view, 1> efficiencyIntf = { 457ddceee07SGeorge Liu "xyz.openbmc_project.Control.PowerSupplyAttributes"}; 458ddceee07SGeorge Liu 459ddceee07SGeorge Liu dbus::utility::getSubTree( 460ddceee07SGeorge Liu "/xyz/openbmc_project", 0, efficiencyIntf, 461ddceee07SGeorge Liu [asyncResp](const boost::system::error_code& ec, 462ddceee07SGeorge Liu const dbus::utility::MapperGetSubTreeResponse& subtree) { 463ddceee07SGeorge Liu handlePowerSupplyAttributesSubTreeResponse(asyncResp, ec, subtree); 464ddceee07SGeorge Liu }); 465ddceee07SGeorge Liu } 466ddceee07SGeorge Liu 467bd79bce8SPatrick Williams inline void doPowerSupplyGet( 468bd79bce8SPatrick Williams const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 469bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId, 4703e42a329SLakshmi Yadlapati const std::string& powerSupplyPath, const std::string& service) 47100ef5dc6SGeorge Liu { 47200ef5dc6SGeorge Liu asyncResp->res.addHeader( 47300ef5dc6SGeorge Liu boost::beast::http::field::link, 47400ef5dc6SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 4753e42a329SLakshmi Yadlapati asyncResp->res.jsonValue["@odata.type"] = "#PowerSupply.v1_5_0.PowerSupply"; 47600ef5dc6SGeorge Liu asyncResp->res.jsonValue["Name"] = "Power Supply"; 47700ef5dc6SGeorge Liu asyncResp->res.jsonValue["Id"] = powerSupplyId; 47800ef5dc6SGeorge Liu asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( 4793e42a329SLakshmi Yadlapati "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, 4803e42a329SLakshmi Yadlapati powerSupplyId); 48134dfcb94SGeorge Liu 4823e42a329SLakshmi Yadlapati asyncResp->res.jsonValue["Status"]["State"] = resource::State::Enabled; 483539d8c6bSEd Tanous asyncResp->res.jsonValue["Status"]["Health"] = resource::Health::OK; 48434dfcb94SGeorge Liu 4853e42a329SLakshmi Yadlapati getPowerSupplyState(asyncResp, service, powerSupplyPath); 4863e42a329SLakshmi Yadlapati getPowerSupplyHealth(asyncResp, service, powerSupplyPath); 4873e42a329SLakshmi Yadlapati getPowerSupplyAsset(asyncResp, service, powerSupplyPath); 4883e42a329SLakshmi Yadlapati getPowerSupplyFirmwareVersion(asyncResp, service, powerSupplyPath); 4893e42a329SLakshmi Yadlapati getPowerSupplyLocation(asyncResp, service, powerSupplyPath); 490ddceee07SGeorge Liu getEfficiencyPercent(asyncResp); 49100ef5dc6SGeorge Liu } 49200ef5dc6SGeorge Liu 493bd79bce8SPatrick Williams inline void handlePowerSupplyHead( 494bd79bce8SPatrick Williams App& app, const crow::Request& req, 49500ef5dc6SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 496bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId) 49700ef5dc6SGeorge Liu { 49800ef5dc6SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 49900ef5dc6SGeorge Liu { 50000ef5dc6SGeorge Liu return; 50100ef5dc6SGeorge Liu } 50200ef5dc6SGeorge Liu 50300ef5dc6SGeorge Liu // Get the correct Path and Service that match the input parameters 504bd79bce8SPatrick Williams getValidPowerSupplyPath( 5053e42a329SLakshmi Yadlapati asyncResp, chassisId, powerSupplyId, 5063e42a329SLakshmi Yadlapati [asyncResp](const std::string&, const std::string&) { 50700ef5dc6SGeorge Liu asyncResp->res.addHeader( 50800ef5dc6SGeorge Liu boost::beast::http::field::link, 50900ef5dc6SGeorge Liu "</redfish/v1/JsonSchemas/PowerSupply/PowerSupply.json>; rel=describedby"); 51000ef5dc6SGeorge Liu }); 51100ef5dc6SGeorge Liu } 51200ef5dc6SGeorge Liu 513bd79bce8SPatrick Williams inline void handlePowerSupplyGet( 514bd79bce8SPatrick Williams App& app, const crow::Request& req, 51500ef5dc6SGeorge Liu const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 516bd79bce8SPatrick Williams const std::string& chassisId, const std::string& powerSupplyId) 51700ef5dc6SGeorge Liu { 51800ef5dc6SGeorge Liu if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 51900ef5dc6SGeorge Liu { 52000ef5dc6SGeorge Liu return; 52100ef5dc6SGeorge Liu } 5223e42a329SLakshmi Yadlapati getValidPowerSupplyPath( 5233e42a329SLakshmi Yadlapati asyncResp, chassisId, powerSupplyId, 52400ef5dc6SGeorge Liu std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId)); 52500ef5dc6SGeorge Liu } 52600ef5dc6SGeorge Liu 52700ef5dc6SGeorge Liu inline void requestRoutesPowerSupply(App& app) 52800ef5dc6SGeorge Liu { 52900ef5dc6SGeorge Liu BMCWEB_ROUTE( 53000ef5dc6SGeorge Liu app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 53100ef5dc6SGeorge Liu .privileges(redfish::privileges::headPowerSupply) 53200ef5dc6SGeorge Liu .methods(boost::beast::http::verb::head)( 53300ef5dc6SGeorge Liu std::bind_front(handlePowerSupplyHead, std::ref(app))); 53400ef5dc6SGeorge Liu 53500ef5dc6SGeorge Liu BMCWEB_ROUTE( 53600ef5dc6SGeorge Liu app, "/redfish/v1/Chassis/<str>/PowerSubsystem/PowerSupplies/<str>/") 53700ef5dc6SGeorge Liu .privileges(redfish::privileges::getPowerSupply) 53800ef5dc6SGeorge Liu .methods(boost::beast::http::verb::get)( 53900ef5dc6SGeorge Liu std::bind_front(handlePowerSupplyGet, std::ref(app))); 54000ef5dc6SGeorge Liu } 54100ef5dc6SGeorge Liu 542a7210020SGeorge Liu } // namespace redfish 543