control: Add event configuration class framework
The event class will contain the configuration for each event that
results in altering how fan control functions. Events continue to be
optional, where no events configured result in no fan speed changes.
Events are made up of groups of sensors, triggers from those sensors,
and actions to be run when a trigger occurs. Events may also have a
precondition that must exist before the event is loaded into fan
control. The triggers, actions, and preconditions configured must be
available within the fan control application.
Tested:
Event JSON configuration able to be loaded
Event objects created, each with the name configured
Required event base attributes exist otherwise throw exception
Change-Id: I8a3d116522c78fafa3b3e9a37a63bb8262802a98
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json/Makefile.am b/control/json/Makefile.am
index 5f480f5..bc1db07 100644
--- a/control/json/Makefile.am
+++ b/control/json/Makefile.am
@@ -16,4 +16,5 @@
profile.cpp \
fan.cpp \
zone.cpp \
- group.cpp
+ group.cpp \
+ event.cpp
diff --git a/control/json/event.cpp b/control/json/event.cpp
new file mode 100644
index 0000000..e7a7bfb
--- /dev/null
+++ b/control/json/event.cpp
@@ -0,0 +1,112 @@
+/**
+ * Copyright © 2020 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 "event.hpp"
+
+#include <nlohmann/json.hpp>
+#include <phosphor-logging/log.hpp>
+#include <sdbusplus/bus.hpp>
+
+namespace phosphor::fan::control::json
+{
+
+using json = nlohmann::json;
+using namespace phosphor::logging;
+
+Event::Event(sdbusplus::bus::bus& bus, const json& jsonObj) :
+ ConfigBase(jsonObj)
+{
+ if (jsonObj.contains("profiles"))
+ {
+ for (const auto& profile : jsonObj["profiles"])
+ {
+ _profiles.emplace_back(profile.get<std::string>());
+ }
+ }
+
+ // Event could have a precondition
+ if (!jsonObj.contains("precondition"))
+ {
+ // Event groups are optional
+ if (jsonObj.contains("groups"))
+ {
+ setGroups(jsonObj);
+ }
+ setTriggers(jsonObj);
+ // Event actions are optional
+ if (jsonObj.contains("actions"))
+ {
+ setActions(jsonObj);
+ }
+ }
+ else
+ {
+ setPrecond(jsonObj);
+ }
+}
+
+void Event::setPrecond(const json& jsonObj)
+{
+ const auto& precond = jsonObj["precondition"];
+ if (!precond.contains("name") || !precond.contains("groups") ||
+ !precond.contains("triggers") || !precond.contains("events"))
+ {
+ log<level::ERR>("Missing required event precondition attributes",
+ entry("JSON=%s", precond.dump().c_str()));
+ throw std::runtime_error(
+ "Missing required event precondition attributes");
+ }
+ setGroups(precond);
+ setTriggers(precond);
+}
+
+void Event::setGroups(const json& jsonObj)
+{
+ for (const auto& group : jsonObj["groups"])
+ {
+ if (!group.contains("name") || !group.contains("interface") ||
+ !group.contains("property"))
+ {
+ log<level::ERR>("Missing required event group attributes",
+ entry("JSON=%s", group.dump().c_str()));
+ throw std::runtime_error("Missing required event group attributes");
+ }
+ }
+}
+
+void Event::setTriggers(const json& jsonObj)
+{
+ if (!jsonObj.contains("triggers"))
+ {
+ log<level::ERR>("Missing required event triggers list",
+ entry("JSON=%s", jsonObj.dump().c_str()));
+ throw std::runtime_error("Missing required event triggers list");
+ }
+}
+
+void Event::setActions(const json& jsonObj)
+{
+ for (const auto& action : jsonObj["actions"])
+ {
+ if (!action.contains("name"))
+ {
+ log<level::ERR>("Missing required event action name",
+ entry("JSON=%s", action.dump().c_str()));
+ throw std::runtime_error("Missing required event action name");
+ }
+ }
+}
+
+} // namespace phosphor::fan::control::json
diff --git a/control/json/event.hpp b/control/json/event.hpp
new file mode 100644
index 0000000..5230fbb
--- /dev/null
+++ b/control/json/event.hpp
@@ -0,0 +1,163 @@
+/**
+ * Copyright © 2020 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 "config_base.hpp"
+#include "types.hpp"
+
+#include <nlohmann/json.hpp>
+#include <sdbusplus/bus.hpp>
+
+namespace phosphor::fan::control::json
+{
+
+using json = nlohmann::json;
+
+/**
+ * @class Event - Represents a configured fan control event
+ *
+ * Fan control events are optional, therefore the "events.json" file is
+ * also optional. An event object can be used to enable a specific change to
+ * how fan control should function. These events contain the configured
+ * attributes that result in how fans are controlled within a system. Events
+ * are made up of groups of sensors, triggers from those sensors, and actions
+ * to be run when a trigger occurs. Events may also have a precondition that
+ * must exist before the event is loaded into fan control. The triggers,
+ * actions, and preconditions configured must be available within the fan
+ * control application source.
+ *
+ * When no events exist, the configured fans are set to their corresponding
+ * zone's full_speed value.
+ */
+class Event : public ConfigBase
+{
+ static constexpr auto precondName = 0;
+ static constexpr auto precondGroups = 1;
+ static constexpr auto precondEvents = 2;
+ using Precondition =
+ std::tuple<std::string, std::vector<PrecondGroup>, std::vector<Event>>;
+
+ public:
+ /* JSON file name for events */
+ static constexpr auto confFileName = "events.json";
+
+ Event() = delete;
+ Event(const Event&) = delete;
+ Event(Event&&) = delete;
+ Event& operator=(const Event&) = delete;
+ Event& operator=(Event&&) = delete;
+ ~Event() = default;
+
+ /**
+ * Constructor
+ * Parses and populates a configuration event from JSON object data
+ *
+ * @param[in] bus - sdbusplus bus object
+ * @param[in] jsonObj - JSON object
+ */
+ Event(sdbusplus::bus::bus& bus, const json& jsonObj);
+
+ /**
+ * @brief Get the precondition
+ *
+ * @return The precondition details of the event
+ */
+ inline const auto& getPrecond() const
+ {
+ return _precond;
+ }
+
+ /**
+ * @brief Get the groups
+ *
+ * @return List of groups associated with the event
+ */
+ inline const auto& getGroups() const
+ {
+ return _groups;
+ }
+
+ /**
+ * @brief Get the triggers
+ *
+ * @return List of triggers for this event
+ */
+ inline const auto& getTriggers() const
+ {
+ return _triggers;
+ }
+
+ /**
+ * @brief Get the actions
+ *
+ * @return List of actions to perform for the event
+ */
+ inline const auto& getActions() const
+ {
+ return _actions;
+ }
+
+ private:
+ /* A precondition the event has in order to be enabled */
+ Precondition _precond;
+
+ /* List of groups associated with the event */
+ std::vector<Group> _groups;
+
+ /* List of triggers for this event */
+ std::vector<Trigger> _triggers;
+
+ /* List of actions for this event */
+ std::vector<Action> _actions;
+
+ /**
+ * @brief Parse and set the event's precondition(OPTIONAL)
+ *
+ * @param[in] jsonObj - JSON object for the event
+ *
+ * Sets the precondition of the event in order to be enabled
+ */
+ void setPrecond(const json& jsonObj);
+
+ /**
+ * @brief Parse and set the event's groups(OPTIONAL)
+ *
+ * @param[in] jsonObj - JSON object for the event
+ *
+ * Sets the list of groups associated with the event
+ */
+ void setGroups(const json& jsonObj);
+
+ /**
+ * @brief Parse and set the event's triggers
+ *
+ * @param[in] jsonObj - JSON object for the event
+ *
+ * Sets the list of triggers for the event
+ */
+ void setTriggers(const json& jsonObj);
+
+ /**
+ * @brief Parse and set the event's actions(OPTIONAL)
+ *
+ * @param[in] jsonObj - JSON object for the event
+ *
+ * Sets the list of actions to perform for the event
+ */
+ void setActions(const json& jsonObj);
+};
+
+} // namespace phosphor::fan::control::json
diff --git a/control/json_parser.cpp b/control/json_parser.cpp
index b16bfc1..66c59e3 100644
--- a/control/json_parser.cpp
+++ b/control/json_parser.cpp
@@ -15,6 +15,7 @@
*/
#include "json_parser.hpp"
+#include "json/event.hpp"
#include "json/fan.hpp"
#include "json/group.hpp"
#include "json/manager.hpp"
@@ -37,8 +38,13 @@
auto fans = getConfig<json::Fan>(bus);
// Zones within the system
auto zones = getConfig<json::Zone>(bus);
- // Groups to include in events
- auto groups = getConfig<json::Group>(bus);
+ // Fan control events are optional
+ auto events = getConfig<json::Event>(bus, true);
+ if (!events.empty())
+ {
+ // Groups to include in events
+ auto groups = getConfig<json::Group>(bus);
+ }
// TODO Create zone groups after loading all JSON config files