diff options
author | Chris Cain <cjcain@us.ibm.com> | 2021-05-29 00:57:10 +0300 |
---|---|---|
committer | Chris Cain <cjcain@us.ibm.com> | 2021-07-01 21:58:21 +0300 |
commit | 3a2d042432168ad1b555e4fc9f13c2ae0d35e0c7 (patch) | |
tree | f84c071fc6cb99dcdd10bdfaebb75298879fff1c /redfish-core/lib/systems.hpp | |
parent | 1981771bbd8aac1d689a9c5e258a99e655a76b29 (diff) | |
download | bmcweb-3a2d042432168ad1b555e4fc9f13c2ae0d35e0c7.tar.xz |
Systems: Add PowerMode support
The computer system power mode defines the behavior of a system
based on the performance and power saving requirements.
For example, a system could be set to MaximumPerformance to
run as fast as possible without regard to power consumption.
A system could also be configured to run in PowerSaving mode
which would be running at slower speeds to try to save power.
More information can be found at https://gerrit.openbmc-project.xyz/c/openbmc/docs/+/38786
This commit will allow GET / PATCH operations to the PowerMode property
PowerMode was added in Redfish Release 2021.1:
https://www.dmtf.org/content/redfish-release-20211-now-available
Tested: I manually tested retrieving and setting the PowerMode property
on a Rainier system (with good and bad values):
# curl -k https://$bmc/redfish/v1/Systems/system
{
"@odata.id": "/redfish/v1/Systems/system",
"@odata.type": "#ComputerSystem.v1_15_0.ComputerSystem
...
"PartNumber": "",
"PowerMode": "MaximumPerformance",
"PowerMode@Redfish.AllowableValues": [
"Static",
"MaximumPerformance",
"PowerSaving"
],
"PowerRestorePolicy": "AlwaysOff",
...
# curl -k https://$bmc/xyz/openbmc_project/control/host0/power_mode
{
"data": {
"PowerMode": "xyz.openbmc_project.Control.Power.Mode.PowerMode.MaximumPerformance"
},
"message": "200 OK",
"status": "ok"
}
# curl -k -X PATCH -d '{ "PowerMode":"Static"}' https://$bmc/redfish/v1/Systems/system
curl -k https://$bmc/xyz/openbmc_project/control/host0/power_mode
{
"data": {
"PowerMode": "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"
},
"message": "200 OK",
"status": "ok"
}
Ran Validator on hardware and all tests passed:
Elapsed time: 0:05:07
Counter({'skipOptional': 7128, 'pass': 6020, 'metadataNamespaces': 2217, 'passGet': 315, 'warnDeprecated': 212, 'serviceNamespaces': 79, 'warningPresent': 47, 'warnTrailingSlashLink': 24, 'invalidPropertyValue': 18, 'passAction': 14, 'optionalAction': 11, 'repeat': 3, 'unverifiedComplexAdditional': 1})
Validation has succeeded.
Signed-off-by: Chris Cain <cjcain@us.ibm.com>
Change-Id: I5523a0ebe4a2a77ea4709a14863bff7b55f0303d
Diffstat (limited to 'redfish-core/lib/systems.hpp')
-rw-r--r-- | redfish-core/lib/systems.hpp | 268 |
1 files changed, 266 insertions, 2 deletions
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp index ce7bd5b51e..3e7b4739fa 100644 --- a/redfish-core/lib/systems.hpp +++ b/redfish-core/lib/systems.hpp @@ -1763,6 +1763,263 @@ inline void getProvisioningStatus(std::shared_ptr<bmcweb::AsyncResp> aResp) #endif /** + * @brief Translate the PowerMode to a response message. + * + * @param[in] aResp Shared pointer for generating response message. + * @param[in] modeValue PowerMode value to be translated + * + * @return None. + */ +inline void translatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, + const std::string& modeValue) +{ + std::string modeString; + + if (modeValue == "xyz.openbmc_project.Control.Power.Mode." + "PowerMode.Static") + { + aResp->res.jsonValue["PowerMode"] = "Static"; + } + else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." + "PowerMode.MaximumPerformance") + { + aResp->res.jsonValue["PowerMode"] = "MaximumPerformance"; + } + else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." + "PowerMode.PowerSaving") + { + aResp->res.jsonValue["PowerMode"] = "PowerSaving"; + } + else if (modeValue == "xyz.openbmc_project.Control.Power.Mode." + "PowerMode.OEM") + { + aResp->res.jsonValue["PowerMode"] = "OEM"; + } + else + { + // Any other values would be invalid + BMCWEB_LOG_DEBUG << "PowerMode value was not valid: " << modeValue; + messages::internalError(aResp->res); + } +} + +/** + * @brief Retrieves system power mode + * + * @param[in] aResp Shared pointer for generating response message. + * + * @return None. + */ +inline void getPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp) +{ + BMCWEB_LOG_DEBUG << "Get power mode."; + + // Get Power Mode object path: + crow::connections::systemBus->async_method_call( + [aResp]( + const boost::system::error_code ec, + const std::vector<std::pair< + std::string, + std::vector<std::pair<std::string, std::vector<std::string>>>>>& + subtree) { + if (ec) + { + BMCWEB_LOG_DEBUG + << "DBUS response error on Power.Mode GetSubTree " << ec; + // This is an optional D-Bus object so just return if + // error occurs + return; + } + if (subtree.empty()) + { + // As noted above, this is an optional interface so just return + // if there is no instance found + return; + } + if (subtree.size() > 1) + { + // More then one PowerMode object is not supported and is an + // error + BMCWEB_LOG_DEBUG + << "Found more than 1 system D-Bus Power.Mode objects: " + << subtree.size(); + messages::internalError(aResp->res); + return; + } + if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) + { + BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; + messages::internalError(aResp->res); + return; + } + const std::string& path = subtree[0].first; + const std::string& service = subtree[0].second.begin()->first; + if (service.empty()) + { + BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; + messages::internalError(aResp->res); + return; + } + // Valid Power Mode object found, now read the current value + crow::connections::systemBus->async_method_call( + [aResp](const boost::system::error_code ec, + const std::variant<std::string>& pmode) { + if (ec) + { + BMCWEB_LOG_DEBUG + << "DBUS response error on PowerMode Get: " << ec; + messages::internalError(aResp->res); + return; + } + + const std::string* s = std::get_if<std::string>(&pmode); + if (s == nullptr) + { + BMCWEB_LOG_DEBUG << "Unable to get PowerMode value"; + messages::internalError(aResp->res); + return; + } + + aResp->res.jsonValue["PowerMode@Redfish.AllowableValues"] = + {"Static", "MaximumPerformance", "PowerSaving"}; + + BMCWEB_LOG_DEBUG << "Current power mode: " << *s; + translatePowerMode(aResp, *s); + }, + service, path, "org.freedesktop.DBus.Properties", "Get", + "xyz.openbmc_project.Control.Power.Mode", "PowerMode"); + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), + std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); +} + +/** + * @brief Validate the specified mode is valid and return the PowerMode + * name associated with that string + * + * @param[in] aResp Shared pointer for generating response message. + * @param[in] modeString String representing the desired PowerMode + * + * @return PowerMode value or empty string if mode is not valid + */ +inline std::string + validatePowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, + const std::string& modeString) +{ + std::string mode; + + if (modeString == "Static") + { + mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.Static"; + } + else if (modeString == "MaximumPerformance") + { + mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode." + "MaximumPerformance"; + } + else if (modeString == "PowerSaving") + { + mode = "xyz.openbmc_project.Control.Power.Mode.PowerMode.PowerSaving"; + } + else + { + messages::propertyValueNotInList(aResp->res, modeString, "PowerMode"); + } + return mode; +} + +/** + * @brief Sets system power mode. + * + * @param[in] aResp Shared pointer for generating response message. + * @param[in] pmode System power mode from request. + * + * @return None. + */ +inline void setPowerMode(const std::shared_ptr<bmcweb::AsyncResp>& aResp, + const std::string& pmode) +{ + BMCWEB_LOG_DEBUG << "Set power mode."; + + std::string powerMode = validatePowerMode(aResp, pmode); + if (powerMode.empty()) + { + return; + } + + // Get Power Mode object path: + crow::connections::systemBus->async_method_call( + [aResp, powerMode]( + const boost::system::error_code ec, + const std::vector<std::pair< + std::string, + std::vector<std::pair<std::string, std::vector<std::string>>>>>& + subtree) { + if (ec) + { + BMCWEB_LOG_DEBUG + << "DBUS response error on Power.Mode GetSubTree " << ec; + // This is an optional D-Bus object, but user attempted to patch + messages::internalError(aResp->res); + return; + } + if (subtree.empty()) + { + // This is an optional D-Bus object, but user attempted to patch + messages::resourceNotFound(aResp->res, "ComputerSystem", + "PowerMode"); + return; + } + if (subtree.size() > 1) + { + // More then one PowerMode object is not supported and is an + // error + BMCWEB_LOG_DEBUG + << "Found more than 1 system D-Bus Power.Mode objects: " + << subtree.size(); + messages::internalError(aResp->res); + return; + } + if ((subtree[0].first.empty()) || (subtree[0].second.size() != 1)) + { + BMCWEB_LOG_DEBUG << "Power.Mode mapper error!"; + messages::internalError(aResp->res); + return; + } + const std::string& path = subtree[0].first; + const std::string& service = subtree[0].second.begin()->first; + if (service.empty()) + { + BMCWEB_LOG_DEBUG << "Power.Mode service mapper error!"; + messages::internalError(aResp->res); + return; + } + + BMCWEB_LOG_DEBUG << "Setting power mode(" << powerMode << ") -> " + << path; + + // Set the Power Mode property + crow::connections::systemBus->async_method_call( + [aResp](const boost::system::error_code ec) { + if (ec) + { + messages::internalError(aResp->res); + return; + } + }, + service, path, "org.freedesktop.DBus.Properties", "Set", + "xyz.openbmc_project.Control.Power.Mode", "PowerMode", + std::variant<std::string>(powerMode)); + }, + "xyz.openbmc_project.ObjectMapper", + "/xyz/openbmc_project/object_mapper", + "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", int32_t(0), + std::array<const char*, 1>{"xyz.openbmc_project.Control.Power.Mode"}); +} + +/** * @brief Translates watchdog timeout action DBUS property value to redfish. * * @param[in] dbusAction The watchdog timeout action in D-BUS. @@ -2170,7 +2427,7 @@ inline void requestRoutesSystems(App& app) get)([](const crow::Request&, const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { asyncResp->res.jsonValue["@odata.type"] = - "#ComputerSystem.v1_14_0.ComputerSystem"; + "#ComputerSystem.v1_15_0.ComputerSystem"; asyncResp->res.jsonValue["Name"] = "system"; asyncResp->res.jsonValue["Id"] = "system"; asyncResp->res.jsonValue["SystemType"] = "Physical"; @@ -2282,6 +2539,7 @@ inline void requestRoutesSystems(App& app) getProvisioningStatus(asyncResp); #endif getTrustedModuleRequiredToBoot(asyncResp); + getPowerMode(asyncResp); }); BMCWEB_ROUTE(app, "/redfish/v1/Systems/system/") .privileges({{"ConfigureComponent"}}) @@ -2294,13 +2552,14 @@ inline void requestRoutesSystems(App& app) std::optional<nlohmann::json> wdtTimerProps; std::optional<std::string> assetTag; std::optional<std::string> powerRestorePolicy; + std::optional<std::string> powerMode; if (!json_util::readJson( req, asyncResp->res, "IndicatorLED", indicatorLed, "LocationIndicatorActive", locationIndicatorActive, "Boot", bootProps, "WatchdogTimer", wdtTimerProps, "PowerRestorePolicy", powerRestorePolicy, "AssetTag", - assetTag)) + assetTag, "PowerMode", powerMode)) { return; } @@ -2373,6 +2632,11 @@ inline void requestRoutesSystems(App& app) { setPowerRestorePolicy(asyncResp, *powerRestorePolicy); } + + if (powerMode) + { + setPowerMode(asyncResp, *powerMode); + } }); } |