control: Load JSON configured groups and events

Load the JSON configured groups and events, removing the remaining
references to the YAML based groups, triggers, and actions types. JSON
configured groups are loaded and provided to each event so that they can
eventually be copied and updated for the specifics of the event.

Change-Id: If713809b2865b5fe84b7bbb5a086cd49ba7fe55c
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json/config_base.hpp b/control/json/config_base.hpp
index 816fcdf..3db6907 100644
--- a/control/json/config_base.hpp
+++ b/control/json/config_base.hpp
@@ -30,6 +30,15 @@
     std::variant<bool, int32_t, int64_t, double, std::string>;
 
 /**
+ * Configuration object key to uniquely map to the configuration object
+ * Pair constructed of:
+ *      std::string = Configuration object's name
+ *      std::vector<std::string> = List of profiles the configuration object
+ *                                 is included in
+ */
+using configKey = std::pair<std::string, std::vector<std::string>>;
+
+/**
  * @class ConfigBase - Base configuration object
  *
  * Base class for fan control's JSON configuration objects.
diff --git a/control/json/event.cpp b/control/json/event.cpp
index d19c9c1..7fec581 100644
--- a/control/json/event.cpp
+++ b/control/json/event.cpp
@@ -16,7 +16,6 @@
 #include "event.hpp"
 
 #include "group.hpp"
-#include "json_parser.hpp"
 
 #include <nlohmann/json.hpp>
 #include <phosphor-logging/log.hpp>
@@ -31,27 +30,18 @@
 using json = nlohmann::json;
 using namespace phosphor::logging;
 
-const std::map<configKey, std::unique_ptr<Group>> Event::_availGrps =
-    getConfig<Group>(true);
-
-Event::Event(sdbusplus::bus::bus& bus, const json& jsonObj) :
-    ConfigBase(jsonObj), _bus(bus)
+Event::Event(const json& jsonObj, sdbusplus::bus::bus& bus,
+             std::map<configKey, std::unique_ptr<Group>>& groups) :
+    ConfigBase(jsonObj),
+    _bus(bus)
 {
-    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);
+            setGroups(jsonObj, groups);
         }
         setTriggers(jsonObj);
         // Event actions are optional
@@ -62,11 +52,12 @@
     }
     else
     {
-        setPrecond(jsonObj);
+        setPrecond(jsonObj, groups);
     }
 }
 
-void Event::setPrecond(const json& jsonObj)
+void Event::setPrecond(const json& jsonObj,
+                       std::map<configKey, std::unique_ptr<Group>>& groups)
 {
     const auto& precond = jsonObj["precondition"];
     if (!precond.contains("name") || !precond.contains("groups") ||
@@ -77,11 +68,12 @@
         throw std::runtime_error(
             "Missing required event precondition attributes");
     }
-    setGroups(precond);
+    setGroups(precond, groups);
     setTriggers(precond);
 }
 
-void Event::setGroups(const json& jsonObj)
+void Event::setGroups(const json& jsonObj,
+                      std::map<configKey, std::unique_ptr<Group>>& groups)
 {
     for (const auto& group : jsonObj["groups"])
     {
@@ -110,8 +102,8 @@
         // Groups with the same profiles as the event can be used
         configKey key =
             std::make_pair(group["name"].get<std::string>(), _profiles);
-        auto grpEntry = _availGrps.find(key);
-        if (grpEntry != _availGrps.end())
+        auto grpEntry = groups.find(key);
+        if (grpEntry != groups.end())
         {
             eGroup grp;
             for (const auto& member : grpEntry->second->getMembers())
@@ -127,8 +119,8 @@
             // Groups with no profiles specified can be used in any event
             key = std::make_pair(group["name"].get<std::string>(),
                                  std::vector<std::string>{});
-            grpEntry = _availGrps.find(key);
-            if (grpEntry != _availGrps.end())
+            grpEntry = groups.find(key);
+            if (grpEntry != groups.end())
             {
                 eGroup grp;
                 for (const auto& member : grpEntry->second->getMembers())
diff --git a/control/json/event.hpp b/control/json/event.hpp
index 05459c7..8c48f35 100644
--- a/control/json/event.hpp
+++ b/control/json/event.hpp
@@ -15,15 +15,16 @@
  */
 #pragma once
 
+#include "action.hpp"
 #include "config_base.hpp"
 #include "group.hpp"
-#include "json_parser.hpp"
-#include "types.hpp"
 
 #include <nlohmann/json.hpp>
 #include <sdbusplus/bus.hpp>
 
+#include <memory>
 #include <optional>
+#include <tuple>
 
 namespace phosphor::fan::control::json
 {
@@ -44,7 +45,7 @@
  * control application source.
  *
  * When no events exist, the configured fans are set to their corresponding
- * zone's full_speed value.
+ * zone's `full_speed` value.
  */
 class Event : public ConfigBase
 {
@@ -61,7 +62,10 @@
     static constexpr auto precondGroups = 1;
     static constexpr auto precondEvents = 2;
     using Precondition =
-        std::tuple<std::string, std::vector<PrecondGroup>, std::vector<Event>>;
+        std::tuple<std::string,
+                   std::vector<std::tuple<std::string, std::string, std::string,
+                                          PropertyVariantType>>,
+                   std::vector<Event>>;
 
   public:
     /* JSON file name for events */
@@ -78,10 +82,12 @@
      * Constructor
      * Parses and populates a configuration event from JSON object data
      *
-     * @param[in] bus - sdbusplus bus object
      * @param[in] jsonObj - JSON object
+     * @param[in] bus - sdbusplus bus object
+     * @param[in] groups - Available groups that can be used
      */
-    Event(sdbusplus::bus::bus& bus, const json& jsonObj);
+    Event(const json& jsonObj, sdbusplus::bus::bus& bus,
+          std::map<configKey, std::unique_ptr<Group>>& groups);
 
     /**
      * @brief Get the precondition
@@ -104,16 +110,6 @@
     }
 
     /**
-     * @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
@@ -124,9 +120,6 @@
     }
 
   private:
-    /* Mapping of available group names & profiles to their group object */
-    static const std::map<configKey, std::unique_ptr<Group>> _availGrps;
-
     /* The sdbusplus bus object */
     sdbusplus::bus::bus& _bus;
 
@@ -136,29 +129,30 @@
     /* List of groups associated with the event */
     std::vector<eGroup> _groups;
 
-    /* List of triggers for this event */
-    std::vector<Trigger> _triggers;
-
     /* List of actions for this event */
-    std::vector<Action> _actions;
+    std::vector<std::unique_ptr<ActionBase>> _actions;
 
     /**
      * @brief Parse and set the event's precondition(OPTIONAL)
      *
      * @param[in] jsonObj - JSON object for the event
+     * @param[in] groups - Available groups that can be used
      *
      * Sets the precondition of the event in order to be enabled
      */
-    void setPrecond(const json& jsonObj);
+    void setPrecond(const json& jsonObj,
+                    std::map<configKey, std::unique_ptr<Group>>& groups);
 
     /**
      * @brief Parse and set the event's groups(OPTIONAL)
      *
      * @param[in] jsonObj - JSON object for the event
+     * @param[in] groups - Available groups that can be used
      *
      * Sets the list of groups associated with the event
      */
-    void setGroups(const json& jsonObj);
+    void setGroups(const json& jsonObj,
+                   std::map<configKey, std::unique_ptr<Group>>& groups);
 
     /**
      * @brief Parse and set the event's triggers
diff --git a/control/json/manager.cpp b/control/json/manager.cpp
index bd5261c..b1b5f91 100644
--- a/control/json/manager.cpp
+++ b/control/json/manager.cpp
@@ -18,6 +18,7 @@
 #include "manager.hpp"
 
 #include "action.hpp"
+#include "event.hpp"
 #include "fan.hpp"
 #include "group.hpp"
 #include "json_config.hpp"
@@ -90,6 +91,12 @@
         }
     }
 
+    // Load the configured groups that are copied into events where they're used
+    auto groups = getConfig<Group>(true, bus);
+
+    // Load any events configured
+    _events = getConfig<Event>(true, bus, bus, groups);
+
     bus.request_name(CONTROL_BUSNAME);
 }
 
diff --git a/control/json/manager.hpp b/control/json/manager.hpp
index 506c8c0..2d75977 100644
--- a/control/json/manager.hpp
+++ b/control/json/manager.hpp
@@ -16,6 +16,8 @@
 #pragma once
 
 #include "action.hpp"
+#include "config_base.hpp"
+#include "event.hpp"
 #include "group.hpp"
 #include "json_config.hpp"
 #include "profile.hpp"
@@ -42,15 +44,6 @@
 /* Application name to be appended to the path for loading a JSON config file */
 constexpr auto confAppName = "control";
 
-/**
- * Configuration object key to uniquely map to the configuration object
- * Pair constructed of:
- *      std::string = Configuration object's name
- *      std::vector<std::string> = List of profiles the configuration object
- *                                 is included in
- */
-using configKey = std::pair<std::string, std::vector<std::string>>;
-
 /* Type of timers supported */
 enum class TimerType
 {
@@ -266,6 +259,9 @@
     /* List of zones configured */
     std::map<configKey, std::unique_ptr<Zone>> _zones;
 
+    /* List of events configured */
+    std::map<configKey, std::unique_ptr<Event>> _events;
+
     /**
      * @brief Parse and set the configured profiles from the profiles JSON file
      *