control: get_managed_objects action
This new action adds all interfaces/properties in its groups into the
Manager's _objects cache, and then calls other actions.
It uses Manager::addObjects() which uses the GetManagedObjects
ObjectManager D-Bus method to obtain all properties provided by the
service, even ones not listed in a group.
This allows an action to run with the latest values in the cache without
having to subscribe to propertiesChanged for them all.
In the below example, the action will call the set_net_increase_target
after it's done populating the cache.
"actions": [
{
"name": "get_managed_objects",
"groups": [
{
"name": "the_temps",
"interface": "xyz.openbmc_project.Sensor.Value",
"property": {
"name": "Value"
}
}
],
"actions": [
{
"name": "set_net_increase_target",
"state": 30,
"delta": 100
}
]
}
]
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: Ic528392139904abd16181d85138395ccfd68a9a6
diff --git a/control/json/actions/get_managed_objects.cpp b/control/json/actions/get_managed_objects.cpp
new file mode 100644
index 0000000..17914ac
--- /dev/null
+++ b/control/json/actions/get_managed_objects.cpp
@@ -0,0 +1,143 @@
+/**
+ * Copyright © 2021 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "get_managed_objects.hpp"
+
+#include "../manager.hpp"
+#include "event.hpp"
+
+#include <iostream>
+
+namespace phosphor::fan::control::json
+{
+
+using json = nlohmann::json;
+
+GetManagedObjects::GetManagedObjects(const json& jsonObj,
+ const std::vector<Group>& groups) :
+ ActionBase(jsonObj, groups)
+{
+ setActions(jsonObj);
+}
+
+void GetManagedObjects::run(Zone& zone)
+{
+ std::set<std::string> services;
+
+ // Call Manager::addObjects to refresh the values of the group members.
+ // If there is an ObjectManager interface that handles them, then
+ // the code can combine all members in the same service down to one call.
+ // If no ObjectManager, then still need addObjects calls for each.
+ for (const auto& group : _groups)
+ {
+ for (const auto& member : group.getMembers())
+ {
+ std::vector<std::string> objMgrPaths;
+
+ const auto& service =
+ zone.getManager()->getService(member, group.getInterface());
+
+ if (!service.empty())
+ {
+ objMgrPaths = zone.getManager()->getPaths(
+ service, "org.freedesktop.DBus.ObjectManager");
+ }
+ else
+ {
+ continue;
+ }
+
+ // Look for the ObjectManager as an ancestor of the path.
+ auto hasObjMgr =
+ std::any_of(objMgrPaths.begin(), objMgrPaths.end(),
+ [member](const auto& path) {
+ return member.find(path) != std::string::npos;
+ });
+
+ if (!hasObjMgr || services.find(service) == services.end())
+ {
+ if (hasObjMgr)
+ {
+ services.insert(service);
+ }
+
+ zone.getManager()->addObjects(member, group.getInterface(),
+ group.getProperty());
+ }
+ }
+ }
+
+ // Perform the actions
+ std::for_each(_actions.begin(), _actions.end(),
+ [](auto& action) { action->run(); });
+}
+
+void GetManagedObjects::setZones(
+ std::vector<std::reference_wrapper<Zone>>& zones)
+{
+ for (auto& zone : zones)
+ {
+ this->addZone(zone);
+ // Add zone to _actions
+ std::for_each(_actions.begin(), _actions.end(),
+ [&zone](std::unique_ptr<ActionBase>& action) {
+ action->addZone(zone);
+ });
+ }
+}
+
+void GetManagedObjects::setActions(const json& jsonObj)
+{
+ if (!jsonObj.contains("actions"))
+ {
+ return;
+ }
+
+ for (const auto& jsonAct : jsonObj["actions"])
+ {
+ if (!jsonAct.contains("name"))
+ {
+ throw ActionParseError{getName(), "Missing required action name"};
+ }
+
+ // Get any configured profile restrictions on the action
+ std::vector<std::string> profiles;
+ if (jsonAct.contains("profiles"))
+ {
+ profiles = jsonAct["profiles"].get<std::vector<std::string>>();
+ }
+
+ // Set the groups configured for each action run when the timer expires
+ std::vector<Group> groups;
+ Event::setGroups(jsonAct, profiles, groups);
+
+ // If no groups on that action, use our own groups instead
+ const std::vector<Group>* groupPtr = &groups;
+ if (groups.empty())
+ {
+ groupPtr = &_groups;
+ }
+
+ // List of zones is set on these actions by overriden setZones()
+ auto actObj = ActionFactory::getAction(
+ jsonAct["name"].get<std::string>(), jsonAct, *groupPtr, {});
+ if (actObj)
+ {
+ _actions.emplace_back(std::move(actObj));
+ }
+ }
+}
+
+} // namespace phosphor::fan::control::json
diff --git a/control/json/actions/get_managed_objects.hpp b/control/json/actions/get_managed_objects.hpp
new file mode 100644
index 0000000..79b0401
--- /dev/null
+++ b/control/json/actions/get_managed_objects.hpp
@@ -0,0 +1,117 @@
+/**
+ * Copyright © 2021 IBM Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#pragma once
+
+#include "../zone.hpp"
+#include "action.hpp"
+#include "group.hpp"
+
+#include <nlohmann/json.hpp>
+
+namespace phosphor::fan::control::json
+{
+
+using json = nlohmann::json;
+
+/**
+ * @class GetManagedObjects
+ *
+ * This action adds the members of its groups to the object cache
+ * by using Manager::addObjects() which calls the GetManagedObjects
+ * D-Bus method to find and add the results. When that is done,
+ * it then runs any actions listed in the JSON.
+ *
+ * This allows an action to run with the latest values in the cache
+ * without having to subscribe to propertiesChanged for them all.
+ *
+ * An example config is:
+ *
+ * "actions": [
+ * {
+ * "name": "get_managed_objects",
+ * "groups": [
+ * {
+ * "name": "the_temps",
+ * "interface": "xyz.openbmc_project.Sensor.Value",
+ * "property": {
+ * "name": "Value"
+ * }
+ * }
+ * ],
+ * "actions": [
+ * {
+ * "name": "set_net_increase_target",
+ * "state": 30,
+ * "delta": 100
+ * }
+ * ]
+ * }
+ * ]
+ **/
+class GetManagedObjects :
+ public ActionBase,
+ public ActionRegister<GetManagedObjects>
+{
+ public:
+ /* Name of this action */
+ static constexpr auto name = "get_managed_objects";
+
+ GetManagedObjects() = delete;
+ GetManagedObjects(const GetManagedObjects&) = delete;
+ GetManagedObjects(GetManagedObjects&&) = delete;
+ GetManagedObjects& operator=(const GetManagedObjects&) = delete;
+ GetManagedObjects& operator=(GetManagedObjects&&) = delete;
+ ~GetManagedObjects() = default;
+
+ /**
+ * @brief Parse the JSON to set the members
+ *
+ * @param[in] jsonObj - JSON configuration of this action
+ * @param[in] groups - Groups of dbus objects the action uses
+ */
+ GetManagedObjects(const json& jsonObj, const std::vector<Group>& groups);
+
+ /**
+ * @brief Run the action.
+ *
+ * @param[in] zone - Zone to run the action on
+ */
+ void run(Zone& zone) override;
+
+ /**
+ * @brief Set the zones on the action and the embedded actions
+ *
+ * @param[in] zones - Zones for the action and timer's actions
+ *
+ * Sets the zones on this action and the timer's actions to run against
+ */
+ void setZones(std::vector<std::reference_wrapper<Zone>>& zones) override;
+
+ private:
+ /**
+ * @brief Parse and set the list of actions
+ *
+ * @param[in] jsonObj - JSON object for the action
+ *
+ * Sets the list of actions that is run when this action runs
+ */
+ void setActions(const json& jsonObj);
+
+ /* List of actions to be called when this action runs */
+ std::vector<std::unique_ptr<ActionBase>> _actions;
+};
+
+} // namespace phosphor::fan::control::json