control: Correct reloading groups.json thru SIGHUP

When providing a SIGHUP, the groups.json was not getting reloaded due to
being a pure static method. This changes that method to load the
groups.json if not already loaded and requested to load the groups.json
which is the default.

All of available groups are now saved off during a SIGHUP and restored
if the groups.json or events.json fail to be reloaded. If there are no
failures in reloading neither the groups.json nor the events.json, the
newly loaded groups.json is used instead.

Change-Id: I44870e796530fdb325e0821429a203969ae05018
Signed-off-by: Matthew Barth <msbarth@us.ibm.com>
diff --git a/control/json/event.cpp b/control/json/event.cpp
index 6f5ad69..082d0bf 100644
--- a/control/json/event.cpp
+++ b/control/json/event.cpp
@@ -37,6 +37,8 @@
 using json = nlohmann::json;
 using namespace phosphor::logging;
 
+std::map<configKey, std::unique_ptr<Group>> Event::allGroups;
+
 Event::Event(const json& jsonObj, Manager* mgr,
              std::map<configKey, std::unique_ptr<Zone>>& zones) :
     ConfigBase(jsonObj),
@@ -63,10 +65,15 @@
     }
 }
 
-auto& Event::getAvailGroups()
+std::map<configKey, std::unique_ptr<Group>>&
+    Event::getAllGroups(bool loadGroups)
 {
-    static auto groups = Manager::getConfig<Group>(true);
-    return groups;
+    if (allGroups.empty() && loadGroups)
+    {
+        allGroups = Manager::getConfig<Group>(true);
+    }
+
+    return allGroups;
 }
 
 void Event::configGroup(Group& group, const json& jsonObj)
@@ -110,7 +117,7 @@
 {
     if (jsonObj.contains("groups"))
     {
-        auto& availGroups = getAvailGroups();
+        auto& availGroups = getAllGroups();
         for (const auto& jsonGrp : jsonObj["groups"])
         {
             if (!jsonGrp.contains("name"))
diff --git a/control/json/event.hpp b/control/json/event.hpp
index 0e71f79..78bc633 100644
--- a/control/json/event.hpp
+++ b/control/json/event.hpp
@@ -79,6 +79,36 @@
     void enable();
 
     /**
+     * @brief Clear all groups available for events
+     */
+    static void clearAllGroups()
+    {
+        allGroups.clear();
+    }
+
+    /**
+     * @brief Set the groups that are available for events
+     *
+     * @param[in] groups - All groups available for events
+     */
+    static void
+        setAllGroups(std::map<configKey, std::unique_ptr<Group>>&& groups)
+    {
+        allGroups = std::move(groups);
+    }
+
+    /**
+     * @brief Load and/or return all groups available to be configured on events
+     *
+     * @param[in] loadGroups - Whether to load the groups or not
+     *            (default is to load the groups if not already loaded)
+     *
+     * @return Groups available to be configured on events from `groups.json`
+     */
+    static std::map<configKey, std::unique_ptr<Group>>&
+        getAllGroups(bool loadGroups = true);
+
+    /**
      * @brief Parse group parameters and configure a group object
      *
      * @param[in] group - Group object to get configured
@@ -120,12 +150,8 @@
     /* List of trigger enablement functions for this event */
     std::vector<trigger::enableTrigger> _triggers;
 
-    /**
-     * @brief Load the groups available to be configured on events
-     *
-     * @return Groups available to be configured on events from `groups.json`
-     */
-    static auto& getAvailGroups() __attribute__((pure));
+    /* All groups available to be configred on events */
+    static std::map<configKey, std::unique_ptr<Group>> allGroups;
 
     /**
      * @brief Parse and set the event's actions(OPTIONAL)
diff --git a/control/json/manager.cpp b/control/json/manager.cpp
index fb997c5..92ef0d0 100644
--- a/control/json/manager.cpp
+++ b/control/json/manager.cpp
@@ -138,8 +138,22 @@
             }
         }
 
-        // Load any events configured
-        auto events = getConfig<Event>(true, this, zones);
+        // Save all currently available groups, if any, then clear for reloading
+        auto groups = std::move(Event::getAllGroups(false));
+        Event::clearAllGroups();
+
+        std::map<configKey, std::unique_ptr<Event>> events;
+        try
+        {
+            // Load any events configured, including all the groups
+            events = getConfig<Event>(true, this, zones);
+        }
+        catch (const std::runtime_error& re)
+        {
+            // Restore saved set of all available groups for current events
+            Event::setAllGroups(std::move(groups));
+            throw re;
+        }
 
         // Enable zones
         _zones = std::move(zones);