Monitor : handle inventory service offline

Using nameHasOwner and nameOwnerChanged D-Bus signals, a callback is
activated when inventory is started.

There are two primary modes for operation: Compatible Interfaces, the
inventory-detection callback will fail, however start() will be called a
second time after EntityManager starts and forces a reload of the proper
config for the machine type. Separately, if no EntityManager exists,
then the callback for Inventory-detection will succeed and use the
default configuration file.

To test: stop fan monitor and inventory services. start monitor, wait
10s, start Inventory, after about 15s you should see the online
detection.

Signed-off-by: Mike Capps <mikepcapps@gmail.com>
Change-Id: I289493a0aabb849abee8ce8de047513e94ee2219
diff --git a/monitor/system.cpp b/monitor/system.cpp
index f3863b0..fc38645 100644
--- a/monitor/system.cpp
+++ b/monitor/system.cpp
@@ -22,6 +22,7 @@
 #include "types.hpp"
 #include "utility.hpp"
 #ifdef MONITOR_USE_JSON
+#include "json_config.hpp"
 #include "json_parser.hpp"
 #endif
 
@@ -55,19 +56,54 @@
 
 void System::start()
 {
-    _started = true;
+    namespace match = sdbusplus::bus::match;
+
+    // must be done before service detection
+    _inventoryMatch = std::make_unique<match::match>(
+        _bus, match::rules::nameOwnerChanged(util::INVENTORY_SVC),
+        std::bind(&System::inventoryOnlineCb, this, std::placeholders::_1));
+
+    bool invServiceRunning = util::SDBusPlus::callMethodAndRead<bool>(
+        _bus, "org.freedesktop.DBus", "/org/freedesktop/DBus",
+        "org.freedesktop.DBus", "NameHasOwner", util::INVENTORY_SVC);
+
+    if (invServiceRunning)
+    {
+        _inventoryMatch.reset();
+
+        if (!_loaded)
+        {
+            load();
+        }
+    }
+}
+
+void System::load()
+{
     json jsonObj = json::object();
 #ifdef MONITOR_USE_JSON
-    auto confFile =
-        fan::JsonConfig::getConfFile(_bus, confAppName, confFileName);
-    jsonObj = fan::JsonConfig::load(confFile);
+    try
+    {
+        jsonObj = getJsonObj(_bus);
 #endif
-    // Retrieve and set trust groups within the trust manager
-    setTrustMgr(getTrustGroups(jsonObj));
-    // Retrieve fan definitions and create fan objects to be monitored
-    setFans(getFanDefinitions(jsonObj));
-    setFaultConfig(jsonObj);
-    log<level::INFO>("Configuration loaded");
+        auto trustGrps = getTrustGroups(jsonObj);
+        auto fanDefs = getFanDefinitions(jsonObj);
+        // Retrieve and set trust groups within the trust manager
+        setTrustMgr(getTrustGroups(jsonObj));
+        // Clear/set configured fan definitions
+        _fans.clear();
+        _fanHealth.clear();
+        // Retrieve fan definitions and create fan objects to be monitored
+        setFans(fanDefs);
+        setFaultConfig(jsonObj);
+        log<level::INFO>("Configuration loaded");
+
+        _loaded = true;
+#ifdef MONITOR_USE_JSON
+    }
+    catch (const phosphor::fan::NoConfigFound&)
+    {}
+#endif
 
     if (_powerState->isPowerOn())
     {
@@ -77,16 +113,15 @@
                       });
     }
 
-    if (_sensorMatch.empty())
-    {
-        subscribeSensorsToServices();
-    }
+    subscribeSensorsToServices();
 }
 
 void System::subscribeSensorsToServices()
 {
     namespace match = sdbusplus::bus::match;
 
+    _sensorMatch.clear();
+
     SensorMapType sensorMap;
 
     // build a list of all interfaces, always including the value interface
@@ -152,38 +187,43 @@
     }
 }
 
+void System::inventoryOnlineCb(sdbusplus::message::message& msg)
+{
+    namespace match = sdbusplus::bus::match;
+
+    std::string iface;
+    msg.read(iface);
+
+    if (util::INVENTORY_INTF != iface)
+    {
+        return;
+    }
+
+    std::string oldName;
+    msg.read(oldName);
+
+    std::string newName;
+    msg.read(newName);
+
+    // newName should never be empty since match was reset on the first
+    // nameOwnerChanged signal received from the service.
+    if (!_loaded && !newName.empty())
+    {
+        load();
+    }
+
+    // cancel any further notifications about the service state
+    _inventoryMatch.reset();
+}
+
 void System::sighupHandler(sdeventplus::source::Signal&,
                            const struct signalfd_siginfo*)
 {
     try
     {
-        json jsonObj = json::object();
-#ifdef MONITOR_USE_JSON
-        jsonObj = getJsonObj(_bus);
-#endif
-        auto trustGrps = getTrustGroups(jsonObj);
-        auto fanDefs = getFanDefinitions(jsonObj);
-        // Set configured trust groups
-        setTrustMgr(trustGrps);
-        // Clear/set configured fan definitions
-        _fans.clear();
-        _fanHealth.clear();
-        setFans(fanDefs);
-        setFaultConfig(jsonObj);
-        log<level::INFO>("Configuration reloaded successfully");
-
-        if (_powerState->isPowerOn())
-        {
-            std::for_each(_powerOffRules.begin(), _powerOffRules.end(),
-                          [this](auto& rule) {
-                              rule->check(PowerRuleState::runtime, _fanHealth);
-                          });
-        }
-
-        _sensorMatch.clear();
-        subscribeSensorsToServices();
+        load();
     }
-    catch (const std::runtime_error& re)
+    catch (std::runtime_error& re)
     {
         log<level::ERR>("Error reloading config, no config changes made",
                         entry("LOAD_ERROR=%s", re.what()));
@@ -317,7 +357,7 @@
 
     if (powerStateOn)
     {
-        if (!_started)
+        if (!_loaded)
         {
             log<level::ERR>("No conf file found at power on");
             throw std::runtime_error("No conf file found at power on");