diff --git a/redfish-core/lib/power.hpp b/redfish-core/lib/power.hpp index eaea5aba54..ac7503d44d 100644 --- a/redfish-core/lib/power.hpp +++ b/redfish-core/lib/power.hpp @@ -40,6 +40,109 @@ class Power : public Node private: std::vector typeList = {"/xyz/openbmc_project/sensors/voltage", "/xyz/openbmc_project/sensors/power"}; + void setPowerCapOverride( + std::shared_ptr asyncResp, + std::vector& powerControlCollections) + { + auto getChassisPath = + [asyncResp, powerControlCollections]( + const std::optional& chassisPath) mutable { + if (!chassisPath) + { + BMCWEB_LOG_ERROR << "Don't find valid chassis path "; + messages::resourceNotFound(asyncResp->res, "Chassis", + asyncResp->chassisId); + return; + } + + if (powerControlCollections.size() != 1) + { + BMCWEB_LOG_ERROR + << "Don't support multiple hosts at present "; + messages::resourceNotFound(asyncResp->res, "Power", + "PowerControl"); + return; + } + + auto& item = powerControlCollections[0]; + + std::optional powerLimit; + if (!json_util::readJson(item, asyncResp->res, "PowerLimit", + powerLimit)) + { + return; + } + if (!powerLimit) + { + return; + } + std::optional value; + if (!json_util::readJson(*powerLimit, asyncResp->res, + "LimitInWatts", value)) + { + return; + } + if (!value) + { + return; + } + auto valueHandler = [value, asyncResp]( + const boost::system::error_code ec, + const SensorVariant& powerCapEnable) { + if (ec) + { + messages::internalError(asyncResp->res); + BMCWEB_LOG_ERROR + << "powerCapEnable Get handler: Dbus error " << ec; + return; + } + // Check PowerCapEnable + const bool* b = + sdbusplus::message::variant_ns::get_if( + &powerCapEnable); + if (b == nullptr) + { + messages::internalError(asyncResp->res); + BMCWEB_LOG_ERROR + << "Fail to get PowerCapEnable status "; + return; + } + if (!(*b)) + { + messages::actionNotSupported( + asyncResp->res, + "Setting LimitInWatts when PowerLimit " + "feature is disabled"); + BMCWEB_LOG_ERROR << "PowerLimit feature is disabled "; + return; + } + + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec) { + if (ec) + { + BMCWEB_LOG_DEBUG + << "Power Limit Set: Dbus error: " << ec; + messages::internalError(asyncResp->res); + return; + } + asyncResp->res.result( + boost::beast::http::status::no_content); + }, + "xyz.openbmc_project.Settings", + "/xyz/openbmc_project/control/host0/power_cap", + "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.Control.Power.Cap", "PowerCap", + sdbusplus::message::variant(*value)); + }; + crow::connections::systemBus->async_method_call( + std::move(valueHandler), "xyz.openbmc_project.Settings", + "/xyz/openbmc_project/control/host0/power_cap", + "org.freedesktop.DBus.Properties", "Get", + "xyz.openbmc_project.Control.Power.Cap", "PowerCapEnable"); + }; + getValidChassisPath(asyncResp, std::move(getChassisPath)); + } void doGet(crow::Response& res, const crow::Request& req, const std::vector& params) override { @@ -227,7 +330,38 @@ class Power : public Node void doPatch(crow::Response& res, const crow::Request& req, const std::vector& params) override { - setSensorOverride(res, req, params, typeList, "Power"); + if (params.size() != 1) + { + messages::internalError(res); + res.end(); + return; + } + + const std::string& chassisName = params[0]; + auto asyncResp = std::make_shared(res, chassisName, + typeList, "Power"); + + std::optional> voltageCollections; + std::optional> powerCtlCollections; + + if (!json_util::readJson(req, asyncResp->res, "PowerControl", + powerCtlCollections, "Voltages", + voltageCollections)) + { + return; + } + + if (powerCtlCollections) + { + setPowerCapOverride(asyncResp, *powerCtlCollections); + } + if (voltageCollections) + { + std::unordered_map> + allCollections; + allCollections.emplace("Voltages", *std::move(voltageCollections)); + setSensorOverride(asyncResp, allCollections, chassisName, typeList); + } } }; diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp index c900863f13..12657835d8 100644 --- a/redfish-core/lib/sensors.hpp +++ b/redfish-core/lib/sensors.hpp @@ -261,6 +261,62 @@ void reduceSensorList( } } +/** + * @brief Retrieves valid chassis path + * @param asyncResp Pointer to object holding response data + * @param callback Callback for next step to get valid chassis path + */ +template +void getValidChassisPath(std::shared_ptr asyncResp, + Callback&& callback) +{ + BMCWEB_LOG_DEBUG << "checkChassisId enter"; + const std::array interfaces = { + "xyz.openbmc_project.Inventory.Item.Board", + "xyz.openbmc_project.Inventory.Item.Chassis"}; + + auto respHandler = + [callback{std::move(callback)}, + asyncResp](const boost::system::error_code ec, + const std::vector& chassisPaths) mutable { + BMCWEB_LOG_DEBUG << "getValidChassisPath respHandler enter"; + if (ec) + { + BMCWEB_LOG_ERROR + << "getValidChassisPath respHandler DBUS error: " << ec; + messages::internalError(asyncResp->res); + return; + } + + std::optional chassisPath; + std::string chassisName; + for (const std::string& chassis : chassisPaths) + { + std::size_t lastPos = chassis.rfind("/"); + if (lastPos == std::string::npos) + { + BMCWEB_LOG_ERROR << "Failed to find '/' in " << chassis; + continue; + } + chassisName = chassis.substr(lastPos + 1); + if (chassisName == asyncResp->chassisId) + { + chassisPath = chassis; + break; + } + } + callback(chassisPath); + }; + + // Get the Chassis Collection + crow::connections::systemBus->async_method_call( + respHandler, "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", + "/xyz/openbmc_project/inventory", 0, interfaces); + BMCWEB_LOG_DEBUG << "checkChassisId exit"; +} + /** * @brief Retrieves requested chassis sensors and redundancy data from DBus . * @param SensorsAsyncResp Pointer to object holding response data @@ -2329,72 +2385,18 @@ bool findSensorNameUsingSensorPath( * @brief Entry point for overriding sensor values of given sensor * * @param res response object - * @param req request object - * @param params parameter passed for CRUD + * @param allCollections Collections extract from sensors' request patch info * @param typeList TypeList of sensors for the resource queried * @param chassisSubNode Chassis Node for which the query has to happen */ -void setSensorOverride(crow::Response& res, const crow::Request& req, - const std::vector& params, - const std::vector typeList, - const std::string& chassisSubNode) +void setSensorOverride( + std::shared_ptr sensorAsyncResp, + std::unordered_map>& + allCollections, + const std::string& chassisName, const std::vector typeList) { - - // TODO: Need to figure out dynamic way to restrict patch (Set Sensor - // override) based on another d-bus announcement to be more generic. - if (params.size() != 1) - { - messages::internalError(res); - res.end(); - return; - } - - std::unordered_map> allCollections; - std::optional> temperatureCollections; - std::optional> fanCollections; - std::vector voltageCollections; - BMCWEB_LOG_INFO << "setSensorOverride for subNode" << chassisSubNode - << "\n"; - - if (chassisSubNode == "Thermal") - { - if (!json_util::readJson(req, res, "Temperatures", - temperatureCollections, "Fans", - fanCollections)) - { - return; - } - if (!temperatureCollections && !fanCollections) - { - messages::resourceNotFound(res, "Thermal", - "Temperatures / Voltages"); - res.end(); - return; - } - if (temperatureCollections) - { - allCollections.emplace("Temperatures", - *std::move(temperatureCollections)); - } - if (fanCollections) - { - allCollections.emplace("Fans", *std::move(fanCollections)); - } - } - else if (chassisSubNode == "Power") - { - if (!json_util::readJson(req, res, "Voltages", voltageCollections)) - { - return; - } - allCollections.emplace("Voltages", std::move(voltageCollections)); - } - else - { - res.result(boost::beast::http::status::not_found); - res.end(); - return; - } + BMCWEB_LOG_INFO << "setSensorOverride for subNode" + << sensorAsyncResp->chassisSubNode << "\n"; const char* propertyValueName; std::unordered_map> overrideMap; @@ -2416,8 +2418,8 @@ void setSensorOverride(crow::Response& res, const crow::Request& req, } for (auto& item : collectionItems.second) { - if (!json_util::readJson(item, res, "MemberId", memberId, - propertyValueName, value)) + if (!json_util::readJson(item, sensorAsyncResp->res, "MemberId", + memberId, propertyValueName, value)) { return; } @@ -2425,9 +2427,7 @@ void setSensorOverride(crow::Response& res, const crow::Request& req, std::make_pair(value, collectionItems.first)); } } - const std::string& chassisName = params[0]; - auto sensorAsyncResp = std::make_shared( - res, chassisName, typeList, chassisSubNode); + auto getChassisSensorListCb = [sensorAsyncResp, overrideMap](const std::shared_ptr< boost::container::flat_set< diff --git a/redfish-core/lib/thermal.hpp b/redfish-core/lib/thermal.hpp index e39aa3e224..3ab9e441ad 100644 --- a/redfish-core/lib/thermal.hpp +++ b/redfish-core/lib/thermal.hpp @@ -60,7 +60,45 @@ class Thermal : public Node void doPatch(crow::Response& res, const crow::Request& req, const std::vector& params) override { - setSensorOverride(res, req, params, typeList, "Thermal"); + if (params.size() != 1) + { + res.end(); + messages::internalError(res); + return; + } + + const std::string& chassisName = params[0]; + std::optional> temperatureCollections; + std::optional> fanCollections; + std::unordered_map> + allCollections; + + auto asyncResp = std::make_shared( + res, chassisName, typeList, "Thermal"); + + if (!json_util::readJson(req, asyncResp->res, "Temperatures", + temperatureCollections, "Fans", + fanCollections)) + { + return; + } + if (!temperatureCollections && !fanCollections) + { + messages::resourceNotFound(asyncResp->res, "Thermal", + "Temperatures / Voltages"); + return; + } + if (temperatureCollections) + { + allCollections.emplace("Temperatures", + *std::move(temperatureCollections)); + } + if (fanCollections) + { + allCollections.emplace("Fans", *std::move(fanCollections)); + } + + setSensorOverride(asyncResp, allCollections, chassisName, typeList); } };