Error code handling in processing specific tags

The change implements error code to handle failure while processing some
of the JSON tags.
Going forward, error code will be used by the caller to identify the
type of failure that occurred while processing the tags  and based
on that appropriate action will be taken.

Change-Id: I95783836d8829f0d50459a26da37a2e4e21638f5
Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
diff --git a/vpd-manager/include/utility/json_utility.hpp b/vpd-manager/include/utility/json_utility.hpp
index 74dfc38..c2bb646 100644
--- a/vpd-manager/include/utility/json_utility.hpp
+++ b/vpd-manager/include/utility/json_utility.hpp
@@ -21,26 +21,28 @@
 {
 
 // forward declaration of API for function map.
-bool processSystemCmdTag(const nlohmann::json& i_parsedConfigJson,
-                         const std::string& i_vpdFilePath,
-                         const std::string& i_baseAction,
-                         const std::string& i_flagToProcess);
+bool processSystemCmdTag(
+    const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
+    const std::string& i_baseAction, const std::string& i_flagToProcess,
+    uint16_t& o_errCode);
 
 // forward declaration of API for function map.
 bool processGpioPresenceTag(
     const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
-    const std::string& i_baseAction, const std::string& i_flagToProcess);
+    const std::string& i_baseAction, const std::string& i_flagToProcess,
+    uint16_t& o_errCode);
 
 // forward declaration of API for function map.
 bool procesSetGpioTag(const nlohmann::json& i_parsedConfigJson,
                       const std::string& i_vpdFilePath,
                       const std::string& i_baseAction,
-                      const std::string& i_flagToProcess);
+                      const std::string& i_flagToProcess, uint16_t& o_errCode);
 
 // Function pointers to process tags from config JSON.
 typedef bool (*functionPtr)(
     const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
-    const std::string& i_baseAction, const std::string& i_flagToProcess);
+    const std::string& i_baseAction, const std::string& i_flagToProcess,
+    uint16_t& o_errCode);
 
 inline std::unordered_map<std::string, functionPtr> funcionMap{
     {"gpioPresence", processGpioPresenceTag},
@@ -238,8 +240,16 @@
         if (itrToFunction != funcionMap.end())
         {
             if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
-                                       "postFailAction", i_flagToProcess))
+                                       "postFailAction", i_flagToProcess,
+                                       o_errCode))
             {
+                if (o_errCode)
+                {
+                    logging::logMessage(
+                        l_tags.key() + " failed for [" + i_vpdFilePath +
+                        "]. Reason " +
+                        vpdSpecificUtility::getErrCodeMsg(o_errCode));
+                }
                 return false;
             }
         }
@@ -259,47 +269,35 @@
  * @param[in] i_baseAction - Base action for which this tag has been called.
  * @param[in] i_flagToProcess - Flag nested under the base action for which this
  * tag has been called.
+ * @param[out] o_errCode - To set error code in case of error.
  * @return Execution status.
  */
 inline bool processSystemCmdTag(
     const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
-    const std::string& i_baseAction, const std::string& i_flagToProcess)
+    const std::string& i_baseAction, const std::string& i_flagToProcess,
+    uint16_t& o_errCode)
 {
-    try
+    if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
+        i_baseAction.empty() || i_flagToProcess.empty())
     {
-        if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
-            i_baseAction.empty() || i_flagToProcess.empty())
-        {
-            throw std::runtime_error(
-                std::string(__FUNCTION__) +
-                " Invalid parameter. Abort processing of processSystemCmd.");
-        }
-
-        if (!((i_parsedConfigJson["frus"][i_vpdFilePath].at(
-                   0)[i_baseAction][i_flagToProcess]["systemCmd"])
-                  .contains("cmd")))
-        {
-            throw JsonException(
-                std::string(__FUNCTION__) +
-                " Config JSON missing required information to execute system command for EEPROM " +
-                i_vpdFilePath);
-        }
-
-        const std::string& l_systemCommand =
-            i_parsedConfigJson["frus"][i_vpdFilePath].at(
-                0)[i_baseAction][i_flagToProcess]["systemCmd"]["cmd"];
-
-        commonUtility::executeCmd(l_systemCommand);
-        return true;
-    }
-    catch (const std::exception& l_ex)
-    {
-        EventLogger::createSyncPel(
-            EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
-            __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
-            std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+        o_errCode = error_code::INVALID_INPUT_PARAMETER;
         return false;
     }
+
+    if (!((i_parsedConfigJson["frus"][i_vpdFilePath].at(
+               0)[i_baseAction][i_flagToProcess]["systemCmd"])
+              .contains("cmd")))
+    {
+        o_errCode = error_code::MISSING_FLAG;
+        return false;
+    }
+
+    const std::string& l_systemCommand =
+        i_parsedConfigJson["frus"][i_vpdFilePath].at(
+            0)[i_baseAction][i_flagToProcess]["systemCmd"]["cmd"];
+
+    commonUtility::executeCmd(l_systemCommand);
+    return true;
 }
 
 /**
@@ -313,11 +311,13 @@
  * @param[in] i_baseAction - Base action for which this tag has been called.
  * @param[in] i_flagToProcess - Flag nested under the base action for which this
  * tag has been called.
+ * @param[out] o_errCode - To set error code in case of error
  * @return Execution status.
  */
 inline bool processGpioPresenceTag(
     const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
-    const std::string& i_baseAction, const std::string& i_flagToProcess)
+    const std::string& i_baseAction, const std::string& i_flagToProcess,
+    uint16_t& o_errCode)
 {
     std::string l_presencePinName;
     try
@@ -325,9 +325,8 @@
         if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
             i_baseAction.empty() || i_flagToProcess.empty())
         {
-            throw std::runtime_error(
-                std::string(__FUNCTION__) +
-                "Invalid parameter. Abort processing of processGpioPresence tag");
+            o_errCode = error_code::INVALID_INPUT_PARAMETER;
+            return false;
         }
 
         if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
@@ -337,10 +336,8 @@
                     0)[i_baseAction][i_flagToProcess]["gpioPresence"])
                    .contains("value"))))
         {
-            throw JsonException(
-                std::string(__FUNCTION__) +
-                "Config JSON missing required information to detect presence for EEPROM " +
-                i_vpdFilePath);
+            o_errCode = error_code::JSON_MISSING_GPIO_INFO;
+            return false;
         }
 
         // get the pin name
@@ -356,31 +353,26 @@
 
         if (!l_presenceLine)
         {
+            o_errCode = error_code::DEVICE_PRESENCE_UNKNOWN;
             throw GpioException("Couldn't find the GPIO line.");
         }
 
         l_presenceLine.request({"Read the presence line",
                                 gpiod::line_request::DIRECTION_INPUT, 0});
 
-        return (l_presencePinValue == l_presenceLine.get_value());
-    }
-    catch (const std::exception& l_ex)
-    {
-        // No need to continue in case of JSON failure or Firmware error
-        // as these are errors internal to the code and in that case the FRU
-        // should not be processed. Any other error is considered as external
-        // error in this case and a try to read the EEPROM should be done.
-        if (EventLogger::getErrorType(l_ex) == types::ErrorType::JsonFailure ||
-            EventLogger::getErrorType(l_ex) == types::ErrorType::FirmwareError)
+        if (l_presencePinValue != l_presenceLine.get_value())
         {
-            EventLogger::createSyncPel(
-                EventLogger::getErrorType(l_ex),
-                types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
-                EventLogger::getErrorMsg(l_ex), std::nullopt, std::nullopt,
-                std::nullopt, std::nullopt);
+            // As false is being returned in this case, caller needs to know
+            // that it is not due to some exception. It is because the pin was
+            // read correctly but was not having expected value.
+            o_errCode = error_code::DEVICE_NOT_PRESENT;
             return false;
         }
 
+        return true;
+    }
+    catch (const std::exception& l_ex)
+    {
         std::string l_errMsg = "Exception on GPIO line: ";
         l_errMsg += l_presencePinName;
         l_errMsg += " Reason: ";
@@ -418,11 +410,13 @@
  * @param[in] i_baseAction - Base action for which this tag has been called.
  * @param[in] i_flagToProcess - Flag nested under the base action for which this
  * tag has been called.
+ * @param[out] o_errCode - To set error code in case of error
  * @return Execution status.
  */
 inline bool procesSetGpioTag(
     const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
-    const std::string& i_baseAction, const std::string& i_flagToProcess)
+    const std::string& i_baseAction, const std::string& i_flagToProcess,
+    uint16_t& o_errCode)
 {
     std::string l_pinName;
     try
@@ -430,9 +424,8 @@
         if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
             i_baseAction.empty() || i_flagToProcess.empty())
         {
-            throw std::runtime_error(
-                std::string(__FUNCTION__) +
-                " Invalid parameter. Abort processing of procesSetGpio.");
+            o_errCode = error_code::INVALID_INPUT_PARAMETER;
+            return false;
         }
 
         if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
@@ -442,10 +435,8 @@
                     0)[i_baseAction][i_flagToProcess]["setGpio"])
                    .contains("value"))))
         {
-            throw JsonException(
-                std::string(__FUNCTION__) +
-                " Config JSON missing required information to set gpio line for EEPROM " +
-                i_vpdFilePath);
+            o_errCode = error_code::JSON_MISSING_GPIO_INFO;
+            return false;
         }
 
         l_pinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
@@ -462,6 +453,7 @@
 
         if (!l_outputLine)
         {
+            o_errCode = error_code::GPIO_LINE_EXCEPTION;
             throw GpioException("Couldn't find GPIO line.");
         }
 
@@ -472,37 +464,25 @@
     }
     catch (const std::exception& l_ex)
     {
-        if (EventLogger::getErrorType(l_ex) != types::ErrorType::GpioError)
-        {
-            EventLogger::createSyncPel(
-                EventLogger::getErrorType(l_ex),
-                types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
-                EventLogger::getErrorMsg(l_ex), std::nullopt, std::nullopt,
-                std::nullopt, std::nullopt);
-        }
-        else
-        {
-            std::string l_errMsg = "Exception on GPIO line: ";
-            l_errMsg += l_pinName;
-            l_errMsg += " Reason: ";
-            l_errMsg += l_ex.what();
-            l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
+        std::string l_errMsg = "Exception on GPIO line: ";
+        l_errMsg += l_pinName;
+        l_errMsg += " Reason: ";
+        l_errMsg += l_ex.what();
+        l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
 
-            uint16_t l_errCode = 0;
+        uint16_t l_errCode = 0;
 
-            // ToDo -- Update Internal RC code
-            EventLogger::createAsyncPelWithInventoryCallout(
-                EventLogger::getErrorType(l_ex),
-                types::SeverityType::Informational,
-                {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
-                                              l_errCode),
-                  types::CalloutPriority::High}},
-                std::source_location::current().file_name(),
-                std::source_location::current().function_name(), 0, l_errMsg,
-                std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+        // ToDo -- Update Internal RC code
+        EventLogger::createAsyncPelWithInventoryCallout(
+            EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
+            {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
+                                          l_errCode),
+              types::CalloutPriority::High}},
+            std::source_location::current().file_name(),
+            std::source_location::current().function_name(), 0, l_errMsg,
+            std::nullopt, std::nullopt, std::nullopt, std::nullopt);
 
-            logging::logMessage(l_errMsg);
-        }
+        logging::logMessage(l_errMsg);
 
         return false;
     }
@@ -535,13 +515,11 @@
             throw std::runtime_error(
                 std::string(__FUNCTION__) + " Invalid parameter");
         }
-
         if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath))
         {
             throw JsonException(std::string(__FUNCTION__) + " File path: " +
                                 i_vpdFilePath + " not found in JSON");
         }
-
         if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains(i_action))
         {
             throw JsonException(
@@ -576,11 +554,19 @@
         auto itrToFunction = funcionMap.find(l_tag.key());
         if (itrToFunction != funcionMap.end())
         {
+            uint16_t o_errCode = 0;
             if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
-                                       i_action, i_flagToProcess))
+                                       i_action, i_flagToProcess, o_errCode))
             {
                 // In case any of the tag fails to execute. Mark action
                 // as failed for that flag.
+                if (o_errCode)
+                {
+                    logging::logMessage(
+                        l_tag.key() + " failed for [" + i_vpdFilePath +
+                        "]. Reason " +
+                        vpdSpecificUtility::getErrCodeMsg(o_errCode));
+                }
                 return false;
             }
         }