From 00ef5dc6d410ab83302529f23919b3d91a35b5e3 Mon Sep 17 00:00:00 2001 From: George Liu Date: Wed, 5 Oct 2022 16:27:52 +0800 Subject: Implements PowerSupply schema This commit implements the Redfish PowerSupply schema and populates the PowerSupplyCollection members. The PowerSupply is a grandchild of the PowerSubsystem. PowerSupply is part of the new PowerSubsystme/ThermalSubsystem schemas, released in Redfish Version 2020.4. This commit only displays the PowerSupplies in the chassis with common fields like odata.id, odata.type, Id, and Name. Future commits will add PowerSupply properties like FirmwareVersion, LocationIndicatorActive, Status, and Asset information like SerialNumber, PartNumber, Model. This commit looks at the powered_by association from Inventory.Item.Chassis to Inventory.Item.PowerSupply to find a PowerSupply [1]. [1] https://gerrit.openbmc.org/c/openbmc/phosphor-dbus-interfaces/+/58609 Tested: Validator passes 1. curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Chassis/chassis/PowerSubsystem/ PowerSupplies/powersupply0 { "@odata.id": "/redfish/v1/Chassis/chassis/PowerSubsystem/ PowerSupplies/powersupply0", "@odata.type": "#PowerSupply.v1_5_0.PowerSupply", "Id": "powersupply0", "Name": "powersupply0" } 2. Bad power supply name curl -k -H "X-Auth-Token: $token" -X GET https://${bmc}/redfish/v1/Chassis/chassis/PowerSubsystem/ PowerSupplies/ERROR { "error": { "@Message.ExtendedInfo": [ { "@odata.type": "#Message.v1_1_1.Message", "Message": "The requested resource of type PowerSupply named 'ERROR' was not found.", "MessageArgs": [ "PowerSupply", "ERROR" ], "MessageId": "Base.1.13.0.ResourceNotFound", "MessageSeverity": "Critical", "Resolution": "Provide a valid resource identifier and resubmit the request." } ], "code": "Base.1.13.0.ResourceNotFound", "message": "The requested resource of type PowerSupply named 'ERROR' was not found." } } Signed-off-by: George Liu Change-Id: I7b7c0e40c090a3f253f1a778edbe36be9b4317b0 Signed-off-by: Lakshmi Yadlapati --- Redfish.md | 6 ++ redfish-core/include/redfish.hpp | 1 + redfish-core/lib/power_supply.hpp | 170 ++++++++++++++++++++++++++++++++++++-- 3 files changed, 171 insertions(+), 6 deletions(-) diff --git a/Redfish.md b/Redfish.md index 9fec4ed4b6..1cdce980aa 100644 --- a/Redfish.md +++ b/Redfish.md @@ -371,6 +371,12 @@ Fields common to all schemas ##### PowerSupplies - Description +- Members +- Members@odata.count + +#### /redfish/v1/Chassis/{ChassisId}/PowerSubsystem/PowerSupplies/{PowerSupplyId} + +##### PowerSupply ### /redfish/v1/EventService/ diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp index ce09531c42..2bf0f4578e 100644 --- a/redfish-core/include/redfish.hpp +++ b/redfish-core/include/redfish.hpp @@ -91,6 +91,7 @@ class RedfishService #ifdef BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM requestRoutesEnvironmentMetrics(app); requestRoutesPowerSubsystem(app); + requestRoutesPowerSupply(app); requestRoutesPowerSupplyCollection(app); requestRoutesThermalSubsystem(app); #endif diff --git a/redfish-core/lib/power_supply.hpp b/redfish-core/lib/power_supply.hpp index 430a29a632..ebc61c50ab 100644 --- a/redfish-core/lib/power_supply.hpp +++ b/redfish-core/lib/power_supply.hpp @@ -15,13 +15,26 @@ namespace redfish { -inline void updatePowerSupplyList( - const std::shared_ptr& /* asyncResp */, - const std::string& /* chassisId */, - const std::string& /* powerSupplyPath */) +inline void + updatePowerSupplyList(const std::shared_ptr& asyncResp, + const std::string& chassisId, + const std::string& powerSupplyPath) { - // TODO In order for the validator to pass, the Members property will be - // implemented on the next commit + std::string powerSupplyName = + sdbusplus::message::object_path(powerSupplyPath).filename(); + if (powerSupplyName.empty()) + { + return; + } + + nlohmann::json item = nlohmann::json::object(); + item["@odata.id"] = boost::urls::format( + "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, + powerSupplyName); + + nlohmann::json& powerSupplyList = asyncResp->res.jsonValue["Members"]; + powerSupplyList.emplace_back(std::move(item)); + asyncResp->res.jsonValue["Members@odata.count"] = powerSupplyList.size(); } inline void @@ -123,4 +136,149 @@ inline void requestRoutesPowerSupplyCollection(App& app) std::bind_front(handlePowerSupplyCollectionGet, std::ref(app))); } +inline bool checkPowerSupplyId(const std::string& powerSupplyPath, + const std::string& powerSupplyId) +{ + std::string powerSupplyName = + sdbusplus::message::object_path(powerSupplyPath).filename(); + + return !(powerSupplyName.empty() || powerSupplyName != powerSupplyId); +} + +inline void + getValidPowerSupplyPath(const std::shared_ptr& asyncResp, + const std::string& validChassisPath, + const std::string& powerSupplyId, + std::function&& callback) +{ + std::string powerPath = validChassisPath + "/powered_by"; + dbus::utility::getAssociationEndPoints( + powerPath, [asyncResp, powerSupplyId, callback{std::move(callback)}]( + const boost::system::error_code& ec, + const dbus::utility::MapperEndPoints& endpoints) { + if (ec) + { + if (ec.value() != EBADR) + { + BMCWEB_LOG_ERROR + << "DBUS response error for getAssociationEndPoints" + << ec.value(); + messages::internalError(asyncResp->res); + return; + } + messages::resourceNotFound(asyncResp->res, "PowerSupplies", + powerSupplyId); + return; + } + + for (const auto& endpoint : endpoints) + { + if (checkPowerSupplyId(endpoint, powerSupplyId)) + { + callback(); + return; + } + } + + if (!endpoints.empty()) + { + BMCWEB_LOG_WARNING << "Power supply not found: " + << powerSupplyId; + messages::resourceNotFound(asyncResp->res, "PowerSupplies", + powerSupplyId); + return; + } + }); +} + +inline void + doPowerSupplyGet(const std::shared_ptr& asyncResp, + const std::string& chassisId, + const std::string& powerSupplyId, + const std::optional& validChassisPath) +{ + if (!validChassisPath) + { + messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); + return; + } + + // Get the correct Path and Service that match the input parameters + getValidPowerSupplyPath(asyncResp, *validChassisPath, powerSupplyId, + [asyncResp, chassisId, powerSupplyId]() { + asyncResp->res.addHeader( + boost::beast::http::field::link, + "; rel=describedby"); + asyncResp->res.jsonValue["@odata.type"] = + "#PowerSupply.v1_5_0.PowerSupply"; + asyncResp->res.jsonValue["Name"] = "Power Supply"; + asyncResp->res.jsonValue["Id"] = powerSupplyId; + asyncResp->res.jsonValue["@odata.id"] = boost::urls::format( + "/redfish/v1/Chassis/{}/PowerSubsystem/PowerSupplies/{}", chassisId, + powerSupplyId); + }); +} + +inline void + handlePowerSupplyHead(App& app, const crow::Request& req, + const std::shared_ptr& asyncResp, + const std::string& chassisId, + const std::string& powerSupplyId) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + + redfish::chassis_utils::getValidChassisPath( + asyncResp, chassisId, + [asyncResp, chassisId, + powerSupplyId](const std::optional& validChassisPath) { + if (!validChassisPath) + { + messages::resourceNotFound(asyncResp->res, "Chassis", chassisId); + return; + } + + // Get the correct Path and Service that match the input parameters + getValidPowerSupplyPath(asyncResp, *validChassisPath, powerSupplyId, + [asyncResp]() { + asyncResp->res.addHeader( + boost::beast::http::field::link, + "; rel=describedby"); + }); + }); +} + +inline void + handlePowerSupplyGet(App& app, const crow::Request& req, + const std::shared_ptr& asyncResp, + const std::string& chassisId, + const std::string& powerSupplyId) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + + redfish::chassis_utils::getValidChassisPath( + asyncResp, chassisId, + std::bind_front(doPowerSupplyGet, asyncResp, chassisId, powerSupplyId)); +} + +inline void requestRoutesPowerSupply(App& app) +{ + BMCWEB_ROUTE( + app, "/redfish/v1/Chassis//PowerSubsystem/PowerSupplies//") + .privileges(redfish::privileges::headPowerSupply) + .methods(boost::beast::http::verb::head)( + std::bind_front(handlePowerSupplyHead, std::ref(app))); + + BMCWEB_ROUTE( + app, "/redfish/v1/Chassis//PowerSubsystem/PowerSupplies//") + .privileges(redfish::privileges::getPowerSupply) + .methods(boost::beast::http::verb::get)( + std::bind_front(handlePowerSupplyGet, std::ref(app))); +} + } // namespace redfish -- cgit v1.2.3