Fill in the function for resolving errors

The function will look for the error log entries that have the matching
callout string via the association interface. It will then loop over
those entries matching the callout and look for the entries that match
the message for the fault/error we are looking to resolve. If/when a
match is found, the Resolved property for the logging entry will be set
to true.

Resolves: openbmc/openbmc#2676

Change-Id: Ic24841bca0b9fff7d70cc6343862f96f451ec468
Signed-off-by: Brandon Wyman <bjwyman@gmail.com>
diff --git a/power-supply/power_supply.cpp b/power-supply/power_supply.cpp
index af611f0..d7a018f 100644
--- a/power-supply/power_supply.cpp
+++ b/power-supply/power_supply.cpp
@@ -27,6 +27,12 @@
 using namespace sdbusplus::org::open_power::Witherspoon::Fault::Error;
 using namespace sdbusplus::xyz::openbmc_project::Common::Device::Error;
 
+constexpr auto ASSOCIATION_IFACE = "org.openbmc.Association";
+constexpr auto ENDPOINTS_PROPERTY = "endpoints";
+constexpr auto LOGGING_IFACE = "xyz.openbmc_project.Logging.Entry";
+constexpr auto MESSAGE_PROPERTY = "Message";
+constexpr auto RESOLVED_PROPERTY = "Resolved";
+
 namespace witherspoon
 {
 namespace power
@@ -543,8 +549,61 @@
 void PowerSupply::resolveError(const std::string& callout,
                                const std::string& message)
 {
-    // to be filled in.
-    return;
+    using EndpointList = std::vector<std::string>;
+
+    try
+    {
+        auto path = callout + "/fault";
+        // Get the service name from the mapper for the fault callout
+        auto service = util::getService(path,
+                                        ASSOCIATION_IFACE,
+                                        bus);
+
+        // Use getProperty utility function to get log entries (endpoints)
+        EndpointList logEntries;
+        util::getProperty(ASSOCIATION_IFACE, ENDPOINTS_PROPERTY, path, service,
+                          bus, logEntries);
+
+        // It is possible that all such entries for this callout have since
+        // been deleted.
+        if (logEntries.empty())
+        {
+            return;
+        }
+
+        auto logEntryService = util::getService(logEntries[0], LOGGING_IFACE,
+                                                bus);
+        if (logEntryService.empty())
+        {
+            return;
+        }
+
+        // go through each log entry that matches this callout path
+        std::string logMessage;
+        for (const auto& logEntry : logEntries)
+        {
+            // Check to see if this logEntry has a message that matches.
+            util::getProperty(LOGGING_IFACE, MESSAGE_PROPERTY, logEntry,
+                              logEntryService, bus, logMessage);
+
+            if (message == logMessage)
+            {
+                // Log entry matches call out and message, set Resolved to true
+                bool resolved = true;
+                util::setProperty(LOGGING_IFACE, RESOLVED_PROPERTY, logEntry,
+                                  logEntryService, bus, resolved);
+            }
+
+        }
+
+    }
+    catch (std::exception& e)
+    {
+        log<level::INFO>("Failed to resolve error",
+                         entry("CALLOUT=%s", callout.c_str()),
+                         entry("MESSAGE=%s", message.c_str()));
+    }
+
 }
 
 }