diff options
author | Jonathan Doman <jonathan.doman@intel.com> | 2020-12-03 01:50:45 +0300 |
---|---|---|
committer | Ed Tanous <ed@tanous.net> | 2021-05-15 02:05:31 +0300 |
commit | 3cde86f14b7835775d7c37e993fb84a3cd01ef9d (patch) | |
tree | 69300be6945eedead8c254de21f4b5b205f25ab4 | |
parent | 80be2cdb217fd11e60c403a019134ee970ae6453 (diff) | |
download | bmcweb-3cde86f14b7835775d7c37e993fb84a3cd01ef9d.tar.xz |
Handle Processor.AppliedOperatingConfig PATCH
Allow client to PATCH the URI pointing to the active OperatingConfig for
a given processor, in order to dynamically change the processor's
configuration. The OperatingConfig related properties are only available
if a supporting backend daemon is running - currently we have the Intel
cpuinfoapp in the smbios-mdr repo.
This change does basic validation on input data, then sets the D-Bus
property and translates any return errors into Redfish error messages.
Tested:
- PATCH non-existent Processor -> ResourceNotFound
- PATCH with string/int -> PropertyValueTypeError
- PATCH with object w/o @odata.id -> PropertyMissing+Unknown
- PATCH with config from different Processor -> PropertyValueIncorrect
- PATCH with non-existent config -> PropertyValueIncorrect
- PATCH with valid config -> OK, see new config on next GET
- Hack cpuinfoapp backend service to return all possible error codes and
verify that correct Redfish error is returned.
Change-Id: I19d8b461fac25682f1883fe769d840f18f4141a8
Signed-off-by: Jonathan Doman <jonathan.doman@intel.com>
-rw-r--r-- | redfish-core/lib/processor.hpp | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/redfish-core/lib/processor.hpp b/redfish-core/lib/processor.hpp index bd1870711c..49e04e296e 100644 --- a/redfish-core/lib/processor.hpp +++ b/redfish-core/lib/processor.hpp @@ -847,6 +847,140 @@ inline void "xyz.openbmc_project.Inventory.Item.Cpu.OperatingConfig"); } +/** + * Handle the D-Bus response from attempting to set the CPU's AppliedConfig + * property. Main task is to translate error messages into Redfish errors. + * + * @param[in,out] resp HTTP response. + * @param[in] setPropVal Value which we attempted to set. + * @param[in] ec D-Bus response error code. + * @param[in] msg D-Bus response message. + */ +inline void + handleAppliedConfigResponse(const std::shared_ptr<bmcweb::AsyncResp>& resp, + const std::string& setPropVal, + boost::system::error_code ec, + const sdbusplus::message::message& msg) +{ + if (!ec) + { + BMCWEB_LOG_DEBUG << "Set Property succeeded"; + return; + } + + BMCWEB_LOG_DEBUG << "Set Property failed: " << ec; + + const sd_bus_error* dbusError = msg.get_error(); + if (dbusError == nullptr) + { + messages::internalError(resp->res); + return; + } + + // The asio error code doesn't know about our custom errors, so we have to + // parse the error string. Some of these D-Bus -> Redfish translations are a + // stretch, but it's good to try to communicate something vaguely useful. + if (strcmp(dbusError->name, + "xyz.openbmc_project.Common.Error.InvalidArgument") == 0) + { + // Service did not like the object_path we tried to set. + messages::propertyValueIncorrect( + resp->res, "AppliedOperatingConfig/@odata.id", setPropVal); + } + else if (strcmp(dbusError->name, + "xyz.openbmc_project.Common.Error.NotAllowed") == 0) + { + // Service indicates we can never change the config for this processor. + messages::propertyNotWritable(resp->res, "AppliedOperatingConfig"); + } + else if (strcmp(dbusError->name, + "xyz.openbmc_project.Common.Error.Unavailable") == 0) + { + // Service indicates the config cannot be changed right now, but maybe + // in a different system state. + messages::resourceInStandby(resp->res); + } + else if (strcmp(dbusError->name, + "xyz.openbmc_project.Common.Device.Error.WriteFailure") == + 0) + { + // Service tried to change the config, but it failed. + messages::operationFailed(resp->res); + } + else + { + messages::internalError(resp->res); + } +} + +/** + * Handle the PATCH operation of the AppliedOperatingConfig property. Do basic + * validation of the input data, and then set the D-Bus property. + * + * @param[in,out] resp Async HTTP response. + * @param[in] processorId Processor's Id. + * @param[in] appliedConfigUri New property value to apply. + * @param[in] cpuObjectPath Path of CPU object to modify. + * @param[in] serviceMap Service map for CPU object. + */ +inline void patchAppliedOperatingConfig( + const std::shared_ptr<bmcweb::AsyncResp>& resp, + const std::string& processorId, const std::string& appliedConfigUri, + const std::string& cpuObjectPath, const MapperServiceMap& serviceMap) +{ + // Check that the property even exists by checking for the interface + const std::string* controlService = nullptr; + for (const auto& [serviceName, interfaceList] : serviceMap) + { + if (std::find(interfaceList.begin(), interfaceList.end(), + "xyz.openbmc_project.Control.Processor." + "CurrentOperatingConfig") != interfaceList.end()) + { + controlService = &serviceName; + break; + } + } + + if (controlService == nullptr) + { + messages::internalError(resp->res); + return; + } + + // Check that the config URI is a child of the cpu URI being patched. + std::string expectedPrefix("/redfish/v1/Systems/system/Processors/"); + expectedPrefix += processorId; + expectedPrefix += "/OperatingConfigs/"; + if (!boost::starts_with(appliedConfigUri, expectedPrefix) || + expectedPrefix.size() == appliedConfigUri.size()) + { + messages::propertyValueIncorrect( + resp->res, "AppliedOperatingConfig/@odata.id", appliedConfigUri); + return; + } + + // Generate the D-Bus path of the OperatingConfig object, by assuming it's a + // direct child of the CPU object. + // Strip the expectedPrefix from the config URI to get the "filename", and + // append to the CPU's path. + std::string configBaseName = appliedConfigUri.substr(expectedPrefix.size()); + sdbusplus::message::object_path configPath(cpuObjectPath); + configPath /= configBaseName; + + BMCWEB_LOG_INFO << "Setting config to " << configPath.str; + + // Set the property, with handler to check error responses + crow::connections::systemBus->async_method_call( + [resp, appliedConfigUri](boost::system::error_code ec, + sdbusplus::message::message& msg) { + handleAppliedConfigResponse(resp, appliedConfigUri, ec, msg); + }, + *controlService, cpuObjectPath, "org.freedesktop.DBus.Properties", + "Set", "xyz.openbmc_project.Control.Processor.CurrentOperatingConfig", + "AppliedConfig", + std::variant<sdbusplus::message::object_path>(std::move(configPath))); +} + class OperatingConfigCollection : public Node { public: @@ -1087,6 +1221,41 @@ class Processor : public Node getProcessorObject(asyncResp, processorId, getProcessorData); } + + void doPatch(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const crow::Request& req, + const std::vector<std::string>& params) override + { + std::optional<nlohmann::json> appliedConfigJson; + if (!json_util::readJson(req, asyncResp->res, "AppliedOperatingConfig", + appliedConfigJson)) + { + return; + } + + std::string appliedConfigUri; + if (appliedConfigJson) + { + if (!json_util::readJson(*appliedConfigJson, asyncResp->res, + "@odata.id", appliedConfigUri)) + { + return; + } + // Check for 404 and find matching D-Bus object, then run property + // patch handlers if that all succeeds. + getProcessorObject( + asyncResp, params[0], + [appliedConfigUri = std::move(appliedConfigUri)]( + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, + const std::string& processorId, + const std::string& objectPath, + const MapperServiceMap& serviceMap) { + patchAppliedOperatingConfig(asyncResp, processorId, + appliedConfigUri, objectPath, + serviceMap); + }); + } + } }; } // namespace redfish |