control: Create parameter trigger
Create a new event trigger that will run actions when a parameter is
either added, removed, or changed.
When the trigger is enabled it is added to the Manager class since that
is where parameters are stored, and then the Manager watches for
parameter changes and runs actions as needed.
The JSON config would look like:
{
"class": "parameter",
"parameter": "pcie_floor_index"
}
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I8ff281d49ac780e8ff38f3e8ed02ab95395f1fd3
diff --git a/control/Makefile.am b/control/Makefile.am
index 66d7336..71e3282 100644
--- a/control/Makefile.am
+++ b/control/Makefile.am
@@ -76,6 +76,7 @@
json/triggers/timer.cpp \
json/triggers/signal.cpp \
json/triggers/init.cpp \
+ json/triggers/parameter.cpp \
json/actions/default_floor.cpp \
json/actions/request_target_base.cpp \
json/actions/missing_owner_target.cpp \
diff --git a/control/json/manager.cpp b/control/json/manager.cpp
index 5bfa07c..0acf706 100644
--- a/control/json/manager.cpp
+++ b/control/json/manager.cpp
@@ -59,6 +59,7 @@
std::map<std::string, std::map<std::string, PropertyVariantType>>>
Manager::_objects;
std::unordered_map<std::string, PropertyVariantType> Manager::_parameters;
+std::unordered_map<std::string, TriggerActions> Manager::_parameterTriggers;
const std::string Manager::dumpFile = "/tmp/fan_control_dump.json";
@@ -665,7 +666,7 @@
*this))
{
// Perform the actions in the handler package
- auto& actions = std::get<SignalActions>(pkg);
+ auto& actions = std::get<TriggerActions>(pkg);
std::for_each(actions.begin(), actions.end(), [](auto& action) {
if (action.get())
{
@@ -711,4 +712,36 @@
}
}
+void Manager::addParameterTrigger(
+ const std::string& name, std::vector<std::unique_ptr<ActionBase>>& actions)
+{
+ auto it = _parameterTriggers.find(name);
+ if (it != _parameterTriggers.end())
+ {
+ std::for_each(actions.begin(), actions.end(),
+ [&actList = it->second](auto& action) {
+ actList.emplace_back(std::ref(action));
+ });
+ }
+ else
+ {
+ TriggerActions triggerActions;
+ std::for_each(actions.begin(), actions.end(),
+ [&triggerActions](auto& action) {
+ triggerActions.emplace_back(std::ref(action));
+ });
+ _parameterTriggers[name] = std::move(triggerActions);
+ }
+}
+
+void Manager::runParameterActions(const std::string& name)
+{
+ auto it = _parameterTriggers.find(name);
+ if (it != _parameterTriggers.end())
+ {
+ std::for_each(it->second.begin(), it->second.end(),
+ [](auto& action) { action.get()->run(); });
+ }
+}
+
} // namespace phosphor::fan::control::json
diff --git a/control/json/manager.hpp b/control/json/manager.hpp
index a11bc5e..cc68deb 100644
--- a/control/json/manager.hpp
+++ b/control/json/manager.hpp
@@ -86,7 +86,7 @@
constexpr auto Prop = 2;
using SignalObject = std::tuple<std::string, std::string, std::string>;
/* Dbus signal actions */
-using SignalActions =
+using TriggerActions =
std::vector<std::reference_wrapper<std::unique_ptr<ActionBase>>>;
/**
* Signal handler function that handles parsing a signal's message for a
@@ -99,9 +99,9 @@
* Tuple constructed of:
* SignalHandler = Signal handler function
* SignalObject = Dbus signal object
- * SignalActions = List of actions that are run when the signal is received
+ * TriggerActions = List of actions that are run when the signal is received
*/
-using SignalPkg = std::tuple<SignalHandler, SignalObject, SignalActions>;
+using SignalPkg = std::tuple<SignalHandler, SignalObject, TriggerActions>;
/**
* Data associated to a subscribed signal
* Tuple constructed of:
@@ -128,6 +128,12 @@
std::map<Path_v, std::map<Intf_v, std::map<Prop_v, PropertyVariantType>>>;
/**
+ * Actions to run when a parameter trigger runs.
+ */
+using ParamTriggerData = std::vector<
+ std::reference_wrapper<const std::vector<std::unique_ptr<ActionBase>>>>;
+
+/**
* @class Manager - Represents the fan control manager's configuration
*
* A fan control manager configuration is optional, therefore the "manager.json"
@@ -463,7 +469,15 @@
static void setParameter(const std::string& name,
const PropertyVariantType& value)
{
+ auto it = _parameters.find(name);
+ auto changed = (it == _parameters.end()) ||
+ ((it != _parameters.end()) && it->second != value);
_parameters[name] = value;
+
+ if (changed)
+ {
+ runParameterActions(name);
+ }
}
/**
@@ -492,9 +506,32 @@
*/
static void deleteParameter(const std::string& name)
{
- _parameters.erase(name);
+ size_t deleted = _parameters.erase(name);
+
+ if (deleted)
+ {
+ runParameterActions(name);
+ }
}
+ /**
+ * @brief Runs the actions registered to a parameter
+ * trigger with this name.
+ *
+ * @param[in] name - The parameter name
+ */
+ static void runParameterActions(const std::string& name);
+
+ /**
+ * @brief Adds a parameter trigger
+ *
+ * @param[in] name - The parameter name
+ * @param[in] actions - The actions to run on the trigger
+ */
+ static void
+ addParameterTrigger(const std::string& name,
+ std::vector<std::unique_ptr<ActionBase>>& actions);
+
/* The name of the dump file */
static const std::string dumpFile;
@@ -576,6 +613,12 @@
static std::unordered_map<std::string, PropertyVariantType> _parameters;
/**
+ * @brief Map of parameter names to the actions to run when their
+ * values change.
+ */
+ static std::unordered_map<std::string, TriggerActions> _parameterTriggers;
+
+ /**
* @brief Callback for power state changes
*
* @param[in] powerStateOn - Whether the power state is on or not
diff --git a/control/json/triggers/parameter.cpp b/control/json/triggers/parameter.cpp
new file mode 100644
index 0000000..3abe57c
--- /dev/null
+++ b/control/json/triggers/parameter.cpp
@@ -0,0 +1,48 @@
+/**
+ * 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 "parameter.hpp"
+
+#include "../manager.hpp"
+
+#include <fmt/format.h>
+
+namespace phosphor::fan::control::json::trigger::parameter
+{
+
+using json = nlohmann::json;
+
+enableTrigger
+ triggerParameter(const json& jsonObj, const std::string& eventName,
+ std::vector<std::unique_ptr<ActionBase>>& actions)
+{
+ if (!jsonObj.contains("parameter"))
+ {
+ auto msg = fmt::format(
+ "Event '{}' parameter trigger is missing 'parameter'", eventName);
+ log<level::ERR>(msg.c_str());
+ throw std::runtime_error(msg);
+ }
+
+ auto name = jsonObj["parameter"].get<std::string>();
+
+ return [name](const std::string& eventName, Manager* mgr,
+ const std::vector<Group>& groups,
+ std::vector<std::unique_ptr<ActionBase>>& actions) {
+ Manager::addParameterTrigger(name, actions);
+ };
+}
+
+} // namespace phosphor::fan::control::json::trigger::parameter
diff --git a/control/json/triggers/parameter.hpp b/control/json/triggers/parameter.hpp
new file mode 100644
index 0000000..ed7d4fa
--- /dev/null
+++ b/control/json/triggers/parameter.hpp
@@ -0,0 +1,41 @@
+/**
+ * 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 "action.hpp"
+#include "group.hpp"
+#include "trigger_aliases.hpp"
+
+#include <nlohmann/json.hpp>
+
+#include <memory>
+#include <vector>
+
+namespace phosphor::fan::control::json::trigger::parameter
+{
+
+/**
+ * @brief Trigger to process an event after a parameter changes
+ *
+ * @param[in] jsonObj - JSON object for the trigger
+ * @param[in] eventName - Name of event associated to the signal
+ * @param[in] actions - Actions associated with the trigger
+ */
+enableTrigger
+ triggerParameter(const json& jsonObj, const std::string& eventName,
+ std::vector<std::unique_ptr<ActionBase>>& actions);
+
+} // namespace phosphor::fan::control::json::trigger::parameter
diff --git a/control/json/triggers/signal.cpp b/control/json/triggers/signal.cpp
index 491c7a4..19d7f19 100644
--- a/control/json/triggers/signal.cpp
+++ b/control/json/triggers/signal.cpp
@@ -76,8 +76,8 @@
{
// Same SignalObject signal to trigger event actions,
// add actions to be run when signal for SignalObject received
- auto& pkgActions = std::get<SignalActions>(signalPkg);
- auto& actions = std::get<SignalActions>(pkg);
+ auto& pkgActions = std::get<TriggerActions>(signalPkg);
+ auto& actions = std::get<TriggerActions>(pkg);
actions.insert(actions.end(), pkgActions.begin(),
pkgActions.end());
sameSignal = true;
@@ -92,8 +92,8 @@
}
}
-void propertiesChanged(Manager* mgr, const Group& group, SignalActions& actions,
- const json&)
+void propertiesChanged(Manager* mgr, const Group& group,
+ TriggerActions& actions, const json&)
{
// Groups are optional, but a signal triggered event with no groups
// will do nothing since signals require a group
@@ -117,7 +117,7 @@
}
}
-void interfacesAdded(Manager* mgr, const Group& group, SignalActions& actions,
+void interfacesAdded(Manager* mgr, const Group& group, TriggerActions& actions,
const json&)
{
// Groups are optional, but a signal triggered event with no groups
@@ -141,8 +141,8 @@
}
}
-void interfacesRemoved(Manager* mgr, const Group& group, SignalActions& actions,
- const json&)
+void interfacesRemoved(Manager* mgr, const Group& group,
+ TriggerActions& actions, const json&)
{
// Groups are optional, but a signal triggered event with no groups
// will do nothing since signals require a group
@@ -164,7 +164,7 @@
}
}
-void nameOwnerChanged(Manager* mgr, const Group& group, SignalActions& actions,
+void nameOwnerChanged(Manager* mgr, const Group& group, TriggerActions& actions,
const json&)
{
std::vector<std::string> grpServices;
@@ -213,7 +213,7 @@
}
}
-void member(Manager* mgr, const Group& group, SignalActions& actions,
+void member(Manager* mgr, const Group& group, TriggerActions& actions,
const json&)
{
// No SignalObject required to associate to this signal
@@ -265,7 +265,7 @@
jsonObj](const std::string& eventName, Manager* mgr,
const std::vector<Group>& groups,
std::vector<std::unique_ptr<ActionBase>>& actions) {
- SignalActions signalActions;
+ TriggerActions signalActions;
std::for_each(actions.begin(), actions.end(),
[&signalActions](auto& action) {
signalActions.emplace_back(std::ref(action));
diff --git a/control/json/triggers/signal.hpp b/control/json/triggers/signal.hpp
index 675bd21..ad44f95 100644
--- a/control/json/triggers/signal.hpp
+++ b/control/json/triggers/signal.hpp
@@ -50,8 +50,8 @@
* @param[in] group - Group to subscribe signal against
* @param[in] actions - Actions to be run when signal is received
*/
-void propertiesChanged(Manager* mgr, const Group& group, SignalActions& actions,
- const json&);
+void propertiesChanged(Manager* mgr, const Group& group,
+ TriggerActions& actions, const json&);
/**
* @brief Subscribes to an interfacesAdded signal
@@ -60,7 +60,7 @@
* @param[in] group - Group to subscribe signal against
* @param[in] actions - Actions to be run when signal is received
*/
-void interfacesAdded(Manager* mgr, const Group& group, SignalActions& actions,
+void interfacesAdded(Manager* mgr, const Group& group, TriggerActions& actions,
const json&);
/**
@@ -70,8 +70,8 @@
* @param[in] group - Group to subscribe signal against
* @param[in] actions - Actions to be run when signal is received
*/
-void interfacesRemoved(Manager* mgr, const Group& group, SignalActions& actions,
- const json&);
+void interfacesRemoved(Manager* mgr, const Group& group,
+ TriggerActions& actions, const json&);
/**
* @brief Subscribes to a nameOwnerChanged signal
@@ -80,7 +80,7 @@
* @param[in] group - Group to subscribe signal against
* @param[in] actions - Actions to be run when signal is received
*/
-void nameOwnerChanged(Manager* mgr, const Group& group, SignalActions& actions,
+void nameOwnerChanged(Manager* mgr, const Group& group, TriggerActions& actions,
const json&);
/**
@@ -90,12 +90,12 @@
* @param[in] group - Group to subscribe signal against
* @param[in] actions - Actions to be run when signal is received
*/
-void member(Manager* mgr, const Group& group, SignalActions& actions,
+void member(Manager* mgr, const Group& group, TriggerActions& actions,
const json&);
// Match setup function for signals
using SignalMatch =
- std::function<void(Manager*, const Group&, SignalActions&, const json&)>;
+ std::function<void(Manager*, const Group&, TriggerActions&, const json&)>;
/* Supported signals to their corresponding match setup functions */
static const std::unordered_map<std::string, SignalMatch> signals = {
diff --git a/control/json/triggers/trigger.hpp b/control/json/triggers/trigger.hpp
index c8847c4..b462a01 100644
--- a/control/json/triggers/trigger.hpp
+++ b/control/json/triggers/trigger.hpp
@@ -16,6 +16,7 @@
#pragma once
#include "init.hpp"
+#include "parameter.hpp"
#include "signal.hpp"
#include "timer.hpp"
#include "trigger_aliases.hpp"
@@ -31,6 +32,7 @@
{"signal", signal::triggerSignal},
{"init", init::triggerInit},
{"poweron", init::triggerInit},
- {"poweroff", init::triggerInit}};
+ {"poweroff", init::triggerInit},
+ {"parameter", parameter::triggerParameter}};
} // namespace phosphor::fan::control::json::trigger