PID: Add fan profile support
This adds fan profiles to redfish. This uses the
Thermal Mode interface to allow switching between
different fan profiles. Only the selected fan profile
will be seen. When adding a new controller, they will
also be added to the configuration item for that profile.
Patching of the profile to switch between supported
profiles is also supported.
Tested: Could change profiles in redfish.
Python test script:
def testProfile():
a = {
"Oem": {
"OpenBmc": {
"Fan": {
"Profile" : "Acoustic"
}
}
}
}
return a
def dopatch():
resp = requests.patch(address, json=testProfile(), verify=False,
auth=("root", "0penBmc"))
resp.raise_for_status()
Change-Id: Ie2d8582616ed5bde58e3328b21ba8c59437e88ce
Signed-off-by: James Feist <james.feist@linux.intel.com>
diff --git a/include/dbus_utility.hpp b/include/dbus_utility.hpp
index e45bb9a..bb2bd65 100644
--- a/include/dbus_utility.hpp
+++ b/include/dbus_utility.hpp
@@ -36,6 +36,11 @@
std::string,
boost::container::flat_map<std::string, DbusVariantType>>>>;
+using ManagedItem = std::pair<
+ sdbusplus::message::object_path,
+ boost::container::flat_map<
+ std::string, boost::container::flat_map<std::string, DbusVariantType>>>;
+
inline void escapePathForDbus(std::string& path)
{
const std::regex reg("[^A-Za-z0-9_/]");
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index 5f5ef6e..829ce00 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -20,6 +20,7 @@
#include <boost/algorithm/string/replace.hpp>
#include <boost/date_time.hpp>
#include <dbus_utility.hpp>
+#include <memory>
#include <sstream>
#include <utils/systemd_utils.hpp>
#include <variant>
@@ -118,15 +119,20 @@
"xyz.openbmc_project.Configuration.Pid.Zone";
static constexpr const char* stepwiseConfigurationIface =
"xyz.openbmc_project.Configuration.Stepwise";
+static constexpr const char* thermalModeIface =
+ "xyz.openbmc_project.Control.ThermalMode";
static void asyncPopulatePid(const std::string& connection,
const std::string& path,
+ const std::string& currentProfile,
+ const std::vector<std::string>& supportedProfiles,
std::shared_ptr<AsyncResp> asyncResp)
{
crow::connections::systemBus->async_method_call(
- [asyncResp](const boost::system::error_code ec,
- const dbus::utility::ManagedObjectType& managedObj) {
+ [asyncResp, currentProfile, supportedProfiles](
+ const boost::system::error_code ec,
+ const dbus::utility::ManagedObjectType& managedObj) {
if (ec)
{
BMCWEB_LOG_ERROR << ec;
@@ -168,6 +174,13 @@
configRoot["@odata.type"] = "#OemManager.Fan";
configRoot["@odata.context"] =
"/redfish/v1/$metadata#OemManager.Fan";
+ configRoot["Profile@Redfish.AllowableValues"] = supportedProfiles;
+
+ if (!currentProfile.empty())
+ {
+ configRoot["Profile"] = currentProfile;
+ }
+ BMCWEB_LOG_ERROR << "profile = " << currentProfile << " !";
for (const auto& pathPair : managedObj)
{
@@ -186,6 +199,7 @@
messages::internalError(asyncResp->res);
return;
}
+
const std::string* namePtr =
std::get_if<std::string>(&findName->second);
if (namePtr == nullptr)
@@ -194,9 +208,29 @@
messages::internalError(asyncResp->res);
return;
}
-
std::string name = *namePtr;
dbus::utility::escapePathForDbus(name);
+
+ auto findProfiles = intfPair.second.find("Profiles");
+ if (findProfiles != intfPair.second.end())
+ {
+ const std::vector<std::string>* profiles =
+ std::get_if<std::vector<std::string>>(
+ &findProfiles->second);
+ if (profiles == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "Pid Profiles Field illegal";
+ messages::internalError(asyncResp->res);
+ return;
+ }
+ if (std::find(profiles->begin(), profiles->end(),
+ currentProfile) == profiles->end())
+ {
+ BMCWEB_LOG_INFO
+ << name << " not supported in current profile";
+ continue;
+ }
+ }
nlohmann::json* config = nullptr;
const std::string* classPtr = nullptr;
@@ -522,8 +556,9 @@
return true;
}
-static bool findChassis(const dbus::utility::ManagedObjectType& managedObj,
- const std::string& value, std::string& chassis)
+static const dbus::utility::ManagedItem*
+ findChassis(const dbus::utility::ManagedObjectType& managedObj,
+ const std::string& value, std::string& chassis)
{
BMCWEB_LOG_DEBUG << "Find Chassis: " << value << "\n";
@@ -541,11 +576,16 @@
if (it == managedObj.end())
{
- return false;
+ return nullptr;
}
// 5 comes from <chassis-name> being the 5th element
// /xyz/openbmc_project/inventory/system/chassis/<chassis-name>
- return dbus::utility::getNthStringFromPath(it->first.str, 5, chassis);
+ if (dbus::utility::getNthStringFromPath(it->first.str, 5, chassis))
+ {
+ return &(*it);
+ }
+
+ return nullptr;
}
static CreatePIDRet createPidInterface(
@@ -554,7 +594,7 @@
const dbus::utility::ManagedObjectType& managedObj, bool createNewObject,
boost::container::flat_map<std::string, dbus::utility::DbusVariantType>&
output,
- std::string& chassis)
+ std::string& chassis, const std::string& profile)
{
// common deleter
@@ -595,11 +635,13 @@
return CreatePIDRet::del;
}
+ const dbus::utility::ManagedItem* managedItem = nullptr;
if (!createNewObject)
{
// if we aren't creating a new object, we should be able to find it on
// d-bus
- if (!findChassis(managedObj, it.key(), chassis))
+ managedItem = findChassis(managedObj, it.key(), chassis);
+ if (managedItem == nullptr)
{
BMCWEB_LOG_ERROR << "Failed to get chassis from config patch";
messages::invalidObject(response->res, it.key());
@@ -607,6 +649,56 @@
}
}
+ if (profile.size() &&
+ (type == "PidControllers" || type == "FanControllers" ||
+ type == "StepwiseControllers"))
+ {
+ if (managedItem == nullptr)
+ {
+ output["Profiles"] = std::vector<std::string>{profile};
+ }
+ else
+ {
+ std::string interface;
+ if (type == "StepwiseControllers")
+ {
+ interface = stepwiseConfigurationIface;
+ }
+ else
+ {
+ interface = pidConfigurationIface;
+ }
+ auto findConfig = managedItem->second.find(interface);
+ if (findConfig == managedItem->second.end())
+ {
+ BMCWEB_LOG_ERROR
+ << "Failed to find interface in managed object";
+ messages::internalError(response->res);
+ return CreatePIDRet::fail;
+ }
+ auto findProfiles = findConfig->second.find("Profiles");
+ if (findProfiles != findConfig->second.end())
+ {
+ const std::vector<std::string>* curProfiles =
+ std::get_if<std::vector<std::string>>(
+ &(findProfiles->second));
+ if (curProfiles == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "Illegal profiles in managed object";
+ messages::internalError(response->res);
+ return CreatePIDRet::fail;
+ }
+ if (std::find(curProfiles->begin(), curProfiles->end(),
+ profile) == curProfiles->end())
+ {
+ std::vector<std::string> newProfiles = *curProfiles;
+ newProfiles.push_back(profile);
+ output["Profiles"] = newProfiles;
+ }
+ }
+ }
+ }
+
if (type == "PidControllers" || type == "FanControllers")
{
if (createNewObject)
@@ -846,6 +938,510 @@
}
return CreatePIDRet::patch;
}
+struct GetPIDValues : std::enable_shared_from_this<GetPIDValues>
+{
+
+ GetPIDValues(const std::shared_ptr<AsyncResp>& asyncResp) :
+ asyncResp(asyncResp)
+
+ {
+ }
+
+ void run()
+ {
+ std::shared_ptr<GetPIDValues> self = shared_from_this();
+
+ // get all configurations
+ crow::connections::systemBus->async_method_call(
+ [self](const boost::system::error_code ec,
+ const crow::openbmc_mapper::GetSubTreeType& subtree) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << ec;
+ messages::internalError(self->asyncResp->res);
+ return;
+ }
+ self->subtree = subtree;
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
+ std::array<const char*, 4>{
+ pidConfigurationIface, pidZoneConfigurationIface,
+ objectManagerIface, stepwiseConfigurationIface});
+
+ // at the same time get the selected profile
+ crow::connections::systemBus->async_method_call(
+ [self](const boost::system::error_code ec,
+ const crow::openbmc_mapper::GetSubTreeType& subtree) {
+ if (ec || subtree.empty())
+ {
+ return;
+ }
+ if (subtree[0].second.size() != 1)
+ {
+ // invalid mapper response, should never happen
+ BMCWEB_LOG_ERROR << "GetPIDValues: Mapper Error";
+ messages::internalError(self->asyncResp->res);
+ return;
+ }
+
+ const std::string& path = subtree[0].first;
+ const std::string& owner = subtree[0].second[0].first;
+ crow::connections::systemBus->async_method_call(
+ [path, owner, self](
+ const boost::system::error_code ec,
+ const boost::container::flat_map<
+ std::string, std::variant<std::vector<std::string>,
+ std::string>>& resp) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "GetPIDValues: Can't get "
+ "thermalModeIface "
+ << path;
+ messages::internalError(self->asyncResp->res);
+ return;
+ }
+ const std::string* current;
+ const std::vector<std::string>* supported;
+ for (auto& [key, value] : resp)
+ {
+ if (key == "Current")
+ {
+ current = std::get_if<std::string>(&value);
+ if (current == nullptr)
+ {
+ BMCWEB_LOG_ERROR
+ << "GetPIDValues: thermal mode "
+ "iface invalid "
+ << path;
+ messages::internalError(
+ self->asyncResp->res);
+ return;
+ }
+ }
+ if (key == "Supported")
+ {
+ supported =
+ std::get_if<std::vector<std::string>>(
+ &value);
+ if (supported == nullptr)
+ {
+ BMCWEB_LOG_ERROR
+ << "GetPIDValues: thermal mode "
+ "iface invalid"
+ << path;
+ messages::internalError(
+ self->asyncResp->res);
+ return;
+ }
+ }
+ }
+ if (current == nullptr || supported == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "GetPIDValues: thermal mode "
+ "iface invalid "
+ << path;
+ messages::internalError(self->asyncResp->res);
+ return;
+ }
+ self->currentProfile = *current;
+ self->supportedProfiles = *supported;
+ },
+ owner, path, "org.freedesktop.DBus.Properties", "GetAll",
+ thermalModeIface);
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
+ std::array<const char*, 1>{thermalModeIface});
+ }
+
+ ~GetPIDValues()
+ {
+ if (asyncResp->res.result() != boost::beast::http::status::ok)
+ {
+ return;
+ }
+ // create map of <connection, path to objMgr>>
+ boost::container::flat_map<std::string, std::string> objectMgrPaths;
+ boost::container::flat_set<std::string> calledConnections;
+ for (const auto& pathGroup : subtree)
+ {
+ for (const auto& connectionGroup : pathGroup.second)
+ {
+ auto findConnection =
+ calledConnections.find(connectionGroup.first);
+ if (findConnection != calledConnections.end())
+ {
+ break;
+ }
+ for (const std::string& interface : connectionGroup.second)
+ {
+ if (interface == objectManagerIface)
+ {
+ objectMgrPaths[connectionGroup.first] = pathGroup.first;
+ }
+ // this list is alphabetical, so we
+ // should have found the objMgr by now
+ if (interface == pidConfigurationIface ||
+ interface == pidZoneConfigurationIface ||
+ interface == stepwiseConfigurationIface)
+ {
+ auto findObjMgr =
+ objectMgrPaths.find(connectionGroup.first);
+ if (findObjMgr == objectMgrPaths.end())
+ {
+ BMCWEB_LOG_DEBUG << connectionGroup.first
+ << "Has no Object Manager";
+ continue;
+ }
+
+ calledConnections.insert(connectionGroup.first);
+
+ asyncPopulatePid(findObjMgr->first, findObjMgr->second,
+ currentProfile, supportedProfiles,
+ asyncResp);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ std::vector<std::string> supportedProfiles;
+ std::string currentProfile;
+ crow::openbmc_mapper::GetSubTreeType subtree;
+ std::shared_ptr<AsyncResp> asyncResp;
+};
+
+struct SetPIDValues : std::enable_shared_from_this<SetPIDValues>
+{
+
+ SetPIDValues(const std::shared_ptr<AsyncResp>& asyncResp,
+ nlohmann::json& data) :
+ asyncResp(asyncResp)
+ {
+
+ 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(
+ data, asyncResp->res, "PidControllers", pidControllers,
+ "FanControllers", fanControllers, "FanZones", fanZones,
+ "StepwiseControllers", stepwiseControllers, "Profile", profile))
+ {
+ BMCWEB_LOG_ERROR << "Line:" << __LINE__ << ", Illegal Property "
+ << data.dump();
+ return;
+ }
+ configuration.emplace_back("PidControllers", std::move(pidControllers));
+ configuration.emplace_back("FanControllers", std::move(fanControllers));
+ configuration.emplace_back("FanZones", std::move(fanZones));
+ configuration.emplace_back("StepwiseControllers",
+ std::move(stepwiseControllers));
+ }
+ void run()
+ {
+ if (asyncResp->res.result() != boost::beast::http::status::ok)
+ {
+ return;
+ }
+
+ std::shared_ptr<SetPIDValues> self = shared_from_this();
+
+ // todo(james): might make sense to do a mapper call here if this
+ // interface gets more traction
+ crow::connections::systemBus->async_method_call(
+ [self](const boost::system::error_code ec,
+ dbus::utility::ManagedObjectType& managedObj) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Error communicating to Entity Manager";
+ messages::internalError(self->asyncResp->res);
+ return;
+ }
+ self->managedObj = std::move(managedObj);
+ },
+ "xyz.openbmc_project.EntityManager", "/", objectManagerIface,
+ "GetManagedObjects");
+
+ // at the same time get the profile information
+ crow::connections::systemBus->async_method_call(
+ [self](const boost::system::error_code ec,
+ const crow::openbmc_mapper::GetSubTreeType& subtree) {
+ if (ec || subtree.empty())
+ {
+ return;
+ }
+ if (subtree[0].second.empty())
+ {
+ // invalid mapper response, should never happen
+ BMCWEB_LOG_ERROR << "SetPIDValues: Mapper Error";
+ messages::internalError(self->asyncResp->res);
+ return;
+ }
+
+ const std::string& path = subtree[0].first;
+ const std::string& owner = subtree[0].second[0].first;
+ crow::connections::systemBus->async_method_call(
+ [self, path, owner](
+ const boost::system::error_code ec,
+ const boost::container::flat_map<
+ std::string, std::variant<std::vector<std::string>,
+ std::string>>& resp) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "SetPIDValues: Can't get "
+ "thermalModeIface "
+ << path;
+ messages::internalError(self->asyncResp->res);
+ return;
+ }
+ const std::string* current;
+ const std::vector<std::string>* supported;
+ for (auto& [key, value] : resp)
+ {
+ if (key == "Current")
+ {
+ current = std::get_if<std::string>(&value);
+ if (current == nullptr)
+ {
+ BMCWEB_LOG_ERROR
+ << "SetPIDValues: thermal mode "
+ "iface invalid "
+ << path;
+ messages::internalError(
+ self->asyncResp->res);
+ return;
+ }
+ }
+ if (key == "Supported")
+ {
+ supported =
+ std::get_if<std::vector<std::string>>(
+ &value);
+ if (supported == nullptr)
+ {
+ BMCWEB_LOG_ERROR
+ << "SetPIDValues: thermal mode "
+ "iface invalid"
+ << path;
+ messages::internalError(
+ self->asyncResp->res);
+ return;
+ }
+ }
+ }
+ if (current == nullptr || supported == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "SetPIDValues: thermal mode "
+ "iface invalid "
+ << path;
+ messages::internalError(self->asyncResp->res);
+ return;
+ }
+ self->currentProfile = *current;
+ self->supportedProfiles = *supported;
+ self->profileConnection = owner;
+ self->profilePath = path;
+ },
+ owner, path, "org.freedesktop.DBus.Properties", "GetAll",
+ thermalModeIface);
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
+ std::array<const char*, 1>{thermalModeIface});
+ }
+ ~SetPIDValues()
+ {
+ if (asyncResp->res.result() != boost::beast::http::status::ok)
+ {
+ return;
+ }
+
+ std::shared_ptr<AsyncResp> response = asyncResp;
+
+ if (profile)
+ {
+ if (std::find(supportedProfiles.begin(), supportedProfiles.end(),
+ *profile) == supportedProfiles.end())
+ {
+ messages::actionParameterUnknown(response->res, "Profile",
+ *profile);
+ return;
+ }
+ currentProfile = *profile;
+ crow::connections::systemBus->async_method_call(
+ [response](const boost::system::error_code ec) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Error patching profile" << ec;
+ messages::internalError(response->res);
+ }
+ },
+ profileConnection, profilePath,
+ "org.freedesktop.DBus.Properties", "Set", thermalModeIface,
+ "Current", std::variant<std::string>(*profile));
+ }
+
+ for (auto& containerPair : configuration)
+ {
+ auto& container = containerPair.second;
+ if (!container)
+ {
+ continue;
+ }
+ std::string& type = containerPair.first;
+
+ for (nlohmann::json::iterator it = container->begin();
+ it != container->end(); it++)
+ {
+ const auto& name = it.key();
+ auto pathItr =
+ std::find_if(managedObj.begin(), managedObj.end(),
+ [&name](const auto& obj) {
+ return boost::algorithm::ends_with(
+ obj.first.str, "/" + name);
+ });
+ boost::container::flat_map<std::string,
+ dbus::utility::DbusVariantType>
+ output;
+
+ output.reserve(16); // The pid interface length
+
+ // determines if we're patching entity-manager or
+ // creating a new object
+ bool createNewObject = (pathItr == managedObj.end());
+ std::string iface;
+ if (type == "PidControllers" || type == "FanControllers")
+ {
+ iface = pidConfigurationIface;
+ if (!createNewObject &&
+ pathItr->second.find(pidConfigurationIface) ==
+ pathItr->second.end())
+ {
+ createNewObject = true;
+ }
+ }
+ else if (type == "FanZones")
+ {
+ iface = pidZoneConfigurationIface;
+ if (!createNewObject &&
+ pathItr->second.find(pidZoneConfigurationIface) ==
+ pathItr->second.end())
+ {
+
+ createNewObject = true;
+ }
+ }
+ else if (type == "StepwiseControllers")
+ {
+ iface = stepwiseConfigurationIface;
+ if (!createNewObject &&
+ pathItr->second.find(stepwiseConfigurationIface) ==
+ pathItr->second.end())
+ {
+ createNewObject = true;
+ }
+ }
+ BMCWEB_LOG_DEBUG << "Create new = " << createNewObject << "\n";
+ output["Name"] = boost::replace_all_copy(name, "_", " ");
+
+ std::string chassis;
+ CreatePIDRet ret = createPidInterface(
+ response, type, it, pathItr->first.str, managedObj,
+ createNewObject, output, chassis, currentProfile);
+ if (ret == CreatePIDRet::fail)
+ {
+ return;
+ }
+ else if (ret == CreatePIDRet::del)
+ {
+ continue;
+ }
+
+ if (!createNewObject)
+ {
+ for (const auto& property : output)
+ {
+ crow::connections::systemBus->async_method_call(
+ [response,
+ propertyName{std::string(property.first)}](
+ const boost::system::error_code ec) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Error patching "
+ << propertyName << ": "
+ << ec;
+ messages::internalError(response->res);
+ return;
+ }
+ messages::success(response->res);
+ },
+ "xyz.openbmc_project.EntityManager",
+ pathItr->first.str,
+ "org.freedesktop.DBus.Properties", "Set", iface,
+ property.first, property.second);
+ }
+ }
+ else
+ {
+ if (chassis.empty())
+ {
+ BMCWEB_LOG_ERROR << "Failed to get chassis from config";
+ messages::invalidObject(response->res, name);
+ return;
+ }
+
+ bool foundChassis = false;
+ for (const auto& obj : managedObj)
+ {
+ if (boost::algorithm::ends_with(obj.first.str, chassis))
+ {
+ chassis = obj.first.str;
+ foundChassis = true;
+ break;
+ }
+ }
+ if (!foundChassis)
+ {
+ BMCWEB_LOG_ERROR << "Failed to find chassis on dbus";
+ messages::resourceMissingAtURI(
+ response->res, "/redfish/v1/Chassis/" + chassis);
+ return;
+ }
+
+ crow::connections::systemBus->async_method_call(
+ [response](const boost::system::error_code ec) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Error Adding Pid Object "
+ << ec;
+ messages::internalError(response->res);
+ return;
+ }
+ messages::success(response->res);
+ },
+ "xyz.openbmc_project.EntityManager", chassis,
+ "xyz.openbmc_project.AddObject", "AddObject", output);
+ }
+ }
+ }
+ }
+ std::shared_ptr<AsyncResp> asyncResp;
+ std::vector<std::pair<std::string, std::optional<nlohmann::json>>>
+ configuration;
+ std::optional<std::string> profile;
+ dbus::utility::ManagedObjectType managedObj;
+ std::vector<std::string> supportedProfiles;
+ std::string currentProfile;
+ std::string profileConnection;
+ std::string profilePath;
+};
class Manager : public Node
{
@@ -864,73 +1460,6 @@
}
private:
- void getPidValues(std::shared_ptr<AsyncResp> asyncResp)
- {
- crow::connections::systemBus->async_method_call(
- [asyncResp](const boost::system::error_code ec,
- const crow::openbmc_mapper::GetSubTreeType& subtree) {
- if (ec)
- {
- BMCWEB_LOG_ERROR << ec;
- messages::internalError(asyncResp->res);
- return;
- }
-
- // create map of <connection, path to objMgr>>
- boost::container::flat_map<std::string, std::string>
- objectMgrPaths;
- boost::container::flat_set<std::string> calledConnections;
- for (const auto& pathGroup : subtree)
- {
- for (const auto& connectionGroup : pathGroup.second)
- {
- auto findConnection =
- calledConnections.find(connectionGroup.first);
- if (findConnection != calledConnections.end())
- {
- break;
- }
- for (const std::string& interface :
- connectionGroup.second)
- {
- if (interface == objectManagerIface)
- {
- objectMgrPaths[connectionGroup.first] =
- pathGroup.first;
- }
- // this list is alphabetical, so we
- // should have found the objMgr by now
- if (interface == pidConfigurationIface ||
- interface == pidZoneConfigurationIface ||
- interface == stepwiseConfigurationIface)
- {
- auto findObjMgr =
- objectMgrPaths.find(connectionGroup.first);
- if (findObjMgr == objectMgrPaths.end())
- {
- BMCWEB_LOG_DEBUG << connectionGroup.first
- << "Has no Object Manager";
- continue;
- }
-
- calledConnections.insert(connectionGroup.first);
-
- asyncPopulatePid(findObjMgr->first,
- findObjMgr->second, asyncResp);
- break;
- }
- }
- }
- }
- },
- "xyz.openbmc_project.ObjectMapper",
- "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTree", "/", 0,
- std::array<const char*, 4>{
- pidConfigurationIface, pidZoneConfigurationIface,
- objectManagerIface, stepwiseConfigurationIface});
- }
-
void doGet(crow::Response& res, const crow::Request& req,
const std::vector<std::string>& params) override
{
@@ -1035,208 +1564,8 @@
"xyz.openbmc_project.Software.BMC.Updater",
"/xyz/openbmc_project/software",
"org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- getPidValues(asyncResp);
- }
- 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(
- [response,
- data](const boost::system::error_code ec,
- const dbus::utility::ManagedObjectType& managedObj) {
- if (ec)
- {
- BMCWEB_LOG_ERROR << "Error communicating to Entity Manager";
- messages::internalError(response->res);
- return;
- }
-
- // 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<std::string, 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)
- {
- auto& container = *(containerPair.second);
- if (!container)
- {
- continue;
- }
- std::string& type = containerPair.first;
-
- for (nlohmann::json::iterator it = container->begin();
- it != container->end(); it++)
- {
- const auto& name = it.key();
- auto pathItr =
- std::find_if(managedObj.begin(), managedObj.end(),
- [&name](const auto& obj) {
- return boost::algorithm::ends_with(
- obj.first.str, "/" + name);
- });
- boost::container::flat_map<
- std::string, dbus::utility::DbusVariantType>
- output;
-
- output.reserve(16); // The pid interface length
-
- // determines if we're patching entity-manager or
- // creating a new object
- bool createNewObject = (pathItr == managedObj.end());
- std::string iface;
- if (type == "PidControllers" ||
- type == "FanControllers")
- {
- iface = pidConfigurationIface;
- if (!createNewObject &&
- pathItr->second.find(pidConfigurationIface) ==
- pathItr->second.end())
- {
- createNewObject = true;
- }
- }
- else if (type == "FanZones")
- {
- iface = pidZoneConfigurationIface;
- if (!createNewObject &&
- pathItr->second.find(
- pidZoneConfigurationIface) ==
- pathItr->second.end())
- {
-
- createNewObject = true;
- }
- }
- else if (type == "StepwiseControllers")
- {
- iface = stepwiseConfigurationIface;
- if (!createNewObject &&
- pathItr->second.find(
- stepwiseConfigurationIface) ==
- pathItr->second.end())
- {
- createNewObject = true;
- }
- }
- BMCWEB_LOG_DEBUG << "Create new = " << createNewObject
- << "\n";
- output["Name"] =
- boost::replace_all_copy(name, "_", " ");
-
- std::string chassis;
- CreatePIDRet ret = createPidInterface(
- response, type, it, pathItr->first.str, managedObj,
- createNewObject, output, chassis);
- if (ret == CreatePIDRet::fail)
- {
- return;
- }
- else if (ret == CreatePIDRet::del)
- {
- continue;
- }
-
- if (!createNewObject)
- {
- for (const auto& property : output)
- {
- crow::connections::systemBus->async_method_call(
- [response,
- propertyName{std::string(property.first)}](
- const boost::system::error_code ec) {
- if (ec)
- {
- BMCWEB_LOG_ERROR
- << "Error patching "
- << propertyName << ": " << ec;
- messages::internalError(
- response->res);
- return;
- }
- messages::success(response->res);
- },
- "xyz.openbmc_project.EntityManager",
- pathItr->first.str,
- "org.freedesktop.DBus.Properties", "Set",
- iface, property.first, property.second);
- }
- }
- else
- {
- if (chassis.empty())
- {
- BMCWEB_LOG_ERROR
- << "Failed to get chassis from config";
- messages::invalidObject(response->res, name);
- return;
- }
-
- bool foundChassis = false;
- for (const auto& obj : managedObj)
- {
- if (boost::algorithm::ends_with(obj.first.str,
- chassis))
- {
- chassis = obj.first.str;
- foundChassis = true;
- break;
- }
- }
- if (!foundChassis)
- {
- BMCWEB_LOG_ERROR
- << "Failed to find chassis on dbus";
- messages::resourceMissingAtURI(
- response->res,
- "/redfish/v1/Chassis/" + chassis);
- return;
- }
-
- crow::connections::systemBus->async_method_call(
- [response](const boost::system::error_code ec) {
- if (ec)
- {
- BMCWEB_LOG_ERROR
- << "Error Adding Pid Object " << ec;
- messages::internalError(response->res);
- return;
- }
- messages::success(response->res);
- },
- "xyz.openbmc_project.EntityManager", chassis,
- "xyz.openbmc_project.AddObject", "AddObject",
- output);
- }
- }
- }
- },
- "xyz.openbmc_project.EntityManager", "/", objectManagerIface,
- "GetManagedObjects");
+ auto pids = std::make_shared<GetPIDValues>(asyncResp);
+ pids->run();
}
void doPatch(crow::Response& res, const crow::Request& req,
@@ -1273,7 +1602,8 @@
}
if (fan)
{
- setPidValues(response, *fan);
+ auto pid = std::make_shared<SetPIDValues>(response, *fan);
+ pid->run();
}
}
}