diff options
| author | James Feist <james.feist@linux.intel.com> | 2018-12-12 14:08:25 -0800 |
|---|---|---|
| committer | Ed Tanous <ed.tanous@intel.com> | 2019-01-14 23:48:04 +0000 |
| commit | 5f2caaef9fec67f3b4da92b7eddcf125b6987f46 (patch) | |
| tree | 6cf0201b53374f04fe7263f7313be4622d8cb78a | |
| parent | b7a08d042222796f8803311c05e5029b10144d6a (diff) | |
| download | bmcweb-5f2caaef9fec67f3b4da92b7eddcf125b6987f46.tar.gz bmcweb-5f2caaef9fec67f3b4da92b7eddcf125b6987f46.zip | |
redfish: oem: add stepwise configuration SET
Add ability to set stepwise controllers through redfish.
Also convert all pid control to use readJson.
Tested-by: Set different values using python requests api
Change-Id: Ifa31db7dce3338ec033426641a0185dd3d56b4bc
Signed-off-by: James Feist <james.feist@linux.intel.com>
| -rw-r--r-- | redfish-core/lib/managers.hpp | 544 |
1 files changed, 324 insertions, 220 deletions
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp index 99a3e8b..f009f2a 100644 --- a/redfish-core/lib/managers.hpp +++ b/redfish-core/lib/managers.hpp @@ -473,15 +473,79 @@ enum class CreatePIDRet patch }; +static bool getZonesFromJsonReq(const std::shared_ptr<AsyncResp>& response, + std::vector<nlohmann::json>& config, + std::vector<std::string>& zones) +{ + + for (auto& odata : config) + { + std::string path; + if (!redfish::json_util::readJson(odata, response->res, "@odata.id", + path)) + { + return false; + } + std::string input; + if (!dbus::utility::getNthStringFromPath(path, 4, input)) + { + BMCWEB_LOG_ERROR << "Got invalid path " << path; + BMCWEB_LOG_ERROR << "Illegal Type Zones"; + messages::propertyValueFormatError(response->res, odata.dump(), + "Zones"); + return false; + } + boost::replace_all(input, "_", " "); + zones.emplace_back(std::move(input)); + } + return true; +} + static CreatePIDRet createPidInterface( const std::shared_ptr<AsyncResp>& response, const std::string& type, - const nlohmann::json& record, const std::string& path, + nlohmann::json&& record, const std::string& path, const dbus::utility::ManagedObjectType& managedObj, bool createNewObject, boost::container::flat_map<std::string, dbus::utility::DbusVariantType>& output, std::string& chassis) { + // common deleter + if (record == nullptr) + { + std::string iface; + if (type == "PidControllers" || type == "FanControllers") + { + iface = pidConfigurationIface; + } + else if (type == "FanZones") + { + iface = pidZoneConfigurationIface; + } + else if (type == "StepwiseControllers") + { + iface = stepwiseConfigurationIface; + } + else + { + BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " + << type; + messages::propertyUnknown(response->res, type); + return CreatePIDRet::fail; + } + // delete interface + crow::connections::systemBus->async_method_call( + [response, path](const boost::system::error_code ec) { + if (ec) + { + BMCWEB_LOG_ERROR << "Error patching " << path << ": " << ec; + messages::internalError(response->res); + } + }, + "xyz.openbmc_project.EntityManager", path, iface, "Delete"); + return CreatePIDRet::del; + } + if (type == "PidControllers" || type == "FanControllers") { if (createNewObject) @@ -490,102 +554,66 @@ static CreatePIDRet createPidInterface( : std::string("fan"); output["Type"] = std::string("Pid"); } - else if (record == nullptr) + + std::optional<std::vector<nlohmann::json>> zones; + std::optional<std::vector<std::string>> inputs; + std::optional<std::vector<std::string>> outputs; + std::map<std::string, std::optional<double>> doubles; + if (!redfish::json_util::readJson( + record, response->res, "Inputs", inputs, "Outputs", outputs, + "Zones", zones, "FFGainCoefficient", + doubles["FFGainCoefficient"], "FFOffCoefficient", + doubles["FFOffCoefficient"], "ICoefficient", + doubles["ICoefficient"], "ILimitMax", doubles["ILimitMax"], + "ILimitMin", doubles["ILimitMin"], "OutLimitMax", + doubles["OutLimitMax"], "OutLimitMin", doubles["OutLimitMin"], + "PCoefficient", doubles["PCoefficient"], "SetPoint", + doubles["SetPoint"], "SlewNeg", doubles["SlewNeg"], "SlewPos", + doubles["SlewPos"])) { - // delete interface - crow::connections::systemBus->async_method_call( - [response, - path{std::string(path)}](const boost::system::error_code ec) { - if (ec) - { - BMCWEB_LOG_ERROR << "Error patching " << path << ": " - << ec; - messages::internalError(response->res); - } - }, - "xyz.openbmc_project.EntityManager", path, - pidConfigurationIface, "Delete"); - return CreatePIDRet::del; + BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " + << record.dump(); + return CreatePIDRet::fail; } - - for (auto& field : record.items()) + if (zones) { - if (field.key() == "Zones") + std::vector<std::string> zonesStr; + if (!getZonesFromJsonReq(response, *zones, zonesStr)) { - if (!field.value().is_array()) - { - BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); - messages::propertyValueFormatError( - response->res, field.value(), field.key()); - return CreatePIDRet::fail; - } - std::vector<std::string> inputs; - for (const auto& odata : field.value().items()) - { - for (const auto& value : odata.value().items()) - { - const std::string* path = - value.value().get_ptr<const std::string*>(); - if (path == nullptr) - { - BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); - messages::propertyValueFormatError( - response->res, field.value().dump(), - field.key()); - return CreatePIDRet::fail; - } - std::string input; - if (!dbus::utility::getNthStringFromPath(*path, 4, - input)) - { - BMCWEB_LOG_ERROR << "Got invalid path " << *path; - messages::propertyValueFormatError( - response->res, field.value().dump(), - field.key()); - return CreatePIDRet::fail; - } - boost::replace_all(input, "_", " "); - inputs.emplace_back(std::move(input)); - } - } - output["Zones"] = std::move(inputs); + BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones"; + return CreatePIDRet::fail; } - else if (field.key() == "Inputs" || field.key() == "Outputs") + output["Zones"] = std::move(zonesStr); + } + if (inputs || outputs) + { + std::array<std::optional<std::vector<std::string>>*, 2> containers = + {&inputs, &outputs}; + size_t index = 0; + for (const auto& containerPtr : containers) { - if (!field.value().is_array()) + std::optional<std::vector<std::string>>& container = + *containerPtr; + if (!container) { - BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); - messages::propertyValueFormatError( - response->res, field.value().dump(), field.key()); - return CreatePIDRet::fail; + index++; + continue; } - std::vector<std::string> inputs; - for (const auto& value : field.value().items()) - { - const std::string* sensor = - value.value().get_ptr<const std::string*>(); - if (sensor == nullptr) - { - BMCWEB_LOG_ERROR << "Illegal Type " - << field.value().dump(); - messages::propertyValueFormatError( - response->res, field.value().dump(), field.key()); - return CreatePIDRet::fail; - } + for (std::string& value : *container) + { - std::string input = - boost::replace_all_copy(*sensor, "_", " "); - inputs.push_back(std::move(input)); // try to find the sensor in the // configuration if (chassis.empty()) { + std::string escaped = + boost::replace_all_copy(value, " ", "_"); std::find_if( managedObj.begin(), managedObj.end(), - [&chassis, sensor](const auto& obj) { + [&chassis, &escaped](const auto& obj) { if (boost::algorithm::ends_with(obj.first.str, - *sensor)) + escaped)) { return dbus::utility::getNthStringFromPath( obj.first.str, 5, chassis); @@ -593,116 +621,167 @@ static CreatePIDRet createPidInterface( return false; }); } + boost::replace_all(value, "_", " "); + } + std::string key; + if (index == 0) + { + key = "Inputs"; + } + else + { + key = "Outputs"; } - output[field.key()] = inputs; + output[key] = *container; + index++; } + } - // doubles - else if (field.key() == "FFGainCoefficient" || - field.key() == "FFOffCoefficient" || - field.key() == "ICoefficient" || - field.key() == "ILimitMax" || field.key() == "ILimitMin" || - field.key() == "OutLimitMax" || - field.key() == "OutLimitMin" || - field.key() == "PCoefficient" || - field.key() == "SetPoint" || field.key() == "SlewNeg" || - field.key() == "SlewPos") + // doubles + for (const auto& pairs : doubles) + { + if (!pairs.second) { - const double* ptr = field.value().get_ptr<const double*>(); - if (ptr == nullptr) - { - BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); - messages::propertyValueFormatError( - response->res, field.value().dump(), field.key()); - return CreatePIDRet::fail; - } - output[field.key()] = *ptr; + continue; + } + BMCWEB_LOG_DEBUG << pairs.first << " = " << *pairs.second; + output[pairs.first] = *(pairs.second); + } + } + + else if (type == "FanZones") + { + output["Type"] = std::string("Pid.Zone"); + + std::optional<nlohmann::json> chassisContainer; + std::optional<double> failSafePercent; + std::optional<double> minThermalRpm; + if (!redfish::json_util::readJson(record, response->res, "Chassis", + chassisContainer, "FailSafePercent", + failSafePercent, "MinThermalRpm", + minThermalRpm)) + { + BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " + << record.dump(); + return CreatePIDRet::fail; + } + + if (chassisContainer) + { + + std::string chassisId; + if (!redfish::json_util::readJson(*chassisContainer, response->res, + "@odata.id", chassisId)) + { + BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " + << chassisContainer->dump(); + return CreatePIDRet::fail; } - else + // /refish/v1/chassis/chassis_name/ + if (!dbus::utility::getNthStringFromPath(chassisId, 3, chassis)) { - BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); - messages::propertyUnknown(response->res, field.key()); + BMCWEB_LOG_ERROR << "Got invalid path " << chassisId; + messages::invalidObject(response->res, chassisId); return CreatePIDRet::fail; } } + if (minThermalRpm) + { + output["MinThermalRpm"] = *minThermalRpm; + } + if (failSafePercent) + { + output["FailSafePercent"] = *failSafePercent; + } } - else if (type == "FanZones") + else if (type == "StepwiseControllers") { - if (!createNewObject && record == nullptr) + output["Type"] = std::string("Stepwise"); + + std::optional<std::vector<nlohmann::json>> zones; + std::optional<std::vector<nlohmann::json>> steps; + std::optional<std::vector<std::string>> inputs; + std::optional<double> positiveHysteresis; + std::optional<double> negativeHysteresis; + if (!redfish::json_util::readJson( + record, response->res, "Zones", zones, "Steps", steps, "Inputs", + inputs, "PositiveHysteresis", positiveHysteresis, + "NegativeHysteresis", negativeHysteresis)) { - // delete interface - crow::connections::systemBus->async_method_call( - [response, - path{std::string(path)}](const boost::system::error_code ec) { - if (ec) - { - BMCWEB_LOG_ERROR << "Error patching " << path << ": " - << ec; - messages::internalError(response->res); - } - }, - "xyz.openbmc_project.EntityManager", path, - pidZoneConfigurationIface, "Delete"); - return CreatePIDRet::del; + BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property " + << record.dump(); + return CreatePIDRet::fail; } - output["Type"] = std::string("Pid.Zone"); - for (auto& field : record.items()) + if (zones) { - if (field.key() == "Chassis") + std::vector<std::string> zoneStrs; + if (!getZonesFromJsonReq(response, *zones, zoneStrs)) { - const std::string* chassisId = nullptr; - for (const auto& id : field.value().items()) - { - if (id.key() != "@odata.id") - { - BMCWEB_LOG_ERROR << "Illegal Type " << id.key(); - messages::propertyUnknown(response->res, field.key()); - return CreatePIDRet::fail; - } - chassisId = id.value().get_ptr<const std::string*>(); - if (chassisId == nullptr) - { - messages::createFailedMissingReqProperties( - response->res, field.key()); - return CreatePIDRet::fail; - } - } + BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Zones"; + return CreatePIDRet::fail; + } + output["Zones"] = std::move(zoneStrs); + } + if (steps) + { + std::vector<double> readings; + std::vector<double> outputs; + for (auto& step : *steps) + { + double target; + double output; - // /refish/v1/chassis/chassis_name/ - if (!dbus::utility::getNthStringFromPath(*chassisId, 3, - chassis)) + if (!redfish::json_util::readJson(step, response->res, "Target", + target, "Output", output)) { - BMCWEB_LOG_ERROR << "Got invalid path " << *chassisId; - messages::invalidObject(response->res, *chassisId); + BMCWEB_LOG_ERROR << "Line:" << __LINE__ + << ", Illegal Property " << record.dump(); return CreatePIDRet::fail; } + readings.emplace_back(target); + outputs.emplace_back(output); } - else if (field.key() == "FailSafePercent" || - field.key() == "MinThermalRpm") + output["Reading"] = std::move(readings); + output["Output"] = std::move(outputs); + } + if (inputs) + { + for (std::string& value : *inputs) { - const double* ptr = field.value().get_ptr<const double*>(); - if (ptr == nullptr) + if (chassis.empty()) { - BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); - messages::propertyValueFormatError( - response->res, field.value().dump(), field.key()); - return CreatePIDRet::fail; + std::string escaped = + boost::replace_all_copy(value, " ", "_"); + std::find_if( + managedObj.begin(), managedObj.end(), + [&chassis, &escaped](const auto& obj) { + if (boost::algorithm::ends_with(obj.first.str, + escaped)) + { + return dbus::utility::getNthStringFromPath( + obj.first.str, 5, chassis); + } + return false; + }); } - output[field.key()] = *ptr; - } - else - { - BMCWEB_LOG_ERROR << "Illegal Type " << field.key(); - messages::propertyUnknown(response->res, field.key()); - return CreatePIDRet::fail; + boost::replace_all(value, "_", " "); } + output["Inputs"] = std::move(*inputs); + } + if (negativeHysteresis) + { + output["NegativeHysteresis"] = *negativeHysteresis; + } + if (positiveHysteresis) + { + output["PositiveHysteresis"] = *positiveHysteresis; } } else { - BMCWEB_LOG_ERROR << "Illegal Type " << type; + BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Type " << type; messages::propertyUnknown(response->res, type); return CreatePIDRet::fail; } @@ -852,8 +931,9 @@ class Manager : public Node { for (auto& interface : objpath.second) { - // If interface is xyz.openbmc_project.Software.Version, - // this is what we're looking for. + // If interface is + // xyz.openbmc_project.Software.Version, this is + // what we're looking for. if (interface.first == "xyz.openbmc_project.Software.Version") { @@ -883,9 +963,9 @@ class Manager : public Node "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); getPidValues(asyncResp); } - void setPidValues(std::shared_ptr<AsyncResp> response, - const nlohmann::json& data) + void setPidValues(std::shared_ptr<AsyncResp> response, nlohmann::json& data) { + // todo(james): might make sense to do a mapper call here if this // interface gets more traction crow::connections::systemBus->async_method_call( @@ -898,18 +978,46 @@ class Manager : public Node messages::internalError(response->res); return; } - for (const auto& type : data.items()) + + // todo(james) mutable doesn't work with asio bindings + nlohmann::json jsonData = data; + + std::optional<nlohmann::json> pidControllers; + std::optional<nlohmann::json> fanControllers; + std::optional<nlohmann::json> fanZones; + std::optional<nlohmann::json> stepwiseControllers; + if (!redfish::json_util::readJson( + jsonData, response->res, "PidControllers", + pidControllers, "FanControllers", fanControllers, + "FanZones", fanZones, "StepwiseControllers", + stepwiseControllers)) + { + BMCWEB_LOG_ERROR << "Line:" << __LINE__ + << ", Illegal Property " + << jsonData.dump(); + return; + } + std::array< + std::pair<const char*, std::optional<nlohmann::json>*>, 4> + sections = { + std::make_pair("PidControllers", &pidControllers), + std::make_pair("FanControllers", &fanControllers), + std::make_pair("FanZones", &fanZones), + std::make_pair("StepwiseControllers", + &stepwiseControllers)}; + + for (auto& containerPair : sections) { - if (!type.value().is_object()) + auto& container = *(containerPair.second); + if (!container) { - BMCWEB_LOG_ERROR << "Illegal Type " << type.key(); - messages::propertyValueFormatError( - response->res, type.value(), type.key()); - return; + continue; } - for (const auto& record : type.value().items()) + const char* type = containerPair.first; + + for (auto& record : container->items()) { - const std::string& name = record.key(); + const auto& name = record.key(); auto pathItr = std::find_if(managedObj.begin(), managedObj.end(), [&name](const auto& obj) { @@ -925,9 +1033,11 @@ class Manager : public Node // determines if we're patching entity-manager or // creating a new object bool createNewObject = (pathItr == managedObj.end()); - if (type.key() == "PidControllers" || - type.key() == "FanControllers") + std::string iface; + if (type == "PidControllers" || + type == "FanControllers") { + iface = pidConfigurationIface; if (!createNewObject && pathItr->second.find(pidConfigurationIface) == pathItr->second.end()) @@ -935,19 +1045,35 @@ class Manager : public Node createNewObject = true; } } - else if (!createNewObject && - pathItr->second.find( - pidZoneConfigurationIface) == - pathItr->second.end()) + else if (type == "FanZones") + { + iface = pidZoneConfigurationIface; + if (!createNewObject && + pathItr->second.find( + pidZoneConfigurationIface) == + pathItr->second.end()) + { + + createNewObject = true; + } + } + else if (type == "StepwiseControllers") { - createNewObject = true; + iface = stepwiseConfigurationIface; + if (!createNewObject && + pathItr->second.find( + stepwiseConfigurationIface) == + pathItr->second.end()) + { + createNewObject = true; + } } output["Name"] = boost::replace_all_copy(name, "_", " "); std::string chassis; CreatePIDRet ret = createPidInterface( - response, type.key(), record.value(), + response, type, std::move(record.value()), pathItr->first.str, managedObj, createNewObject, output, chassis); if (ret == CreatePIDRet::fail) @@ -963,10 +1089,6 @@ class Manager : public Node { for (const auto& property : output) { - const char* iface = - type.key() == "FanZones" - ? pidZoneConfigurationIface - : pidConfigurationIface; crow::connections::systemBus->async_method_call( [response, propertyName{std::string(property.first)}]( @@ -983,8 +1105,7 @@ class Manager : public Node "xyz.openbmc_project.EntityManager", pathItr->first.str, "org.freedesktop.DBus.Properties", "Set", - std::string(iface), property.first, - property.second); + iface, property.first, property.second); } } else @@ -1054,47 +1175,30 @@ class Manager : public Node { for (const auto& oemLevel : oem->items()) { - if (oemLevel.key() == "OpenBmc") + std::optional<nlohmann::json> openbmc; + if (!redfish::json_util::readJson(*oem, res, "OpenBmc", + openbmc)) { - if (!oemLevel.value().is_object()) + BMCWEB_LOG_ERROR << "Line:" << __LINE__ + << ", Illegal Property " << oem->dump(); + return; + } + if (openbmc) + { + std::optional<nlohmann::json> fan; + if (!redfish::json_util::readJson(*openbmc, res, "Fan", + fan)) { - BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key(); - messages::propertyValueFormatError( - response->res, "Oem", "OemManager.OpenBmc"); + BMCWEB_LOG_ERROR << "Line:" << __LINE__ + << ", Illegal Property " + << openbmc->dump(); return; } - for (const auto& typeLevel : oemLevel.value().items()) + if (fan) { - - if (typeLevel.key() == "Fan") - { - if (!typeLevel.value().is_object()) - { - BMCWEB_LOG_ERROR << "Bad Patch " - << typeLevel.key(); - messages::propertyValueFormatError( - response->res, typeLevel.value().dump(), - typeLevel.key()); - return; - } - setPidValues(response, - std::move(typeLevel.value())); - } - else - { - BMCWEB_LOG_ERROR << "Bad Patch " << typeLevel.key(); - messages::propertyUnknown(response->res, - typeLevel.key()); - return; - } + setPidValues(response, *fan); } } - else - { - BMCWEB_LOG_ERROR << "Bad Patch " << oemLevel.key(); - messages::propertyUnknown(response->res, oemLevel.key()); - return; - } } } } |

