PEL: Add getLocationCode call to inv callout

Instead of getting the location code, PN, SN, and CCIN all in one
function call, split getting the location code into its own function.
This way, if there is a location code but not the VPD fields, we can
still have the location code in the callout.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I02f1b18319c34fffce79ad31da74e2114ceb5c95
diff --git a/extensions/openpower-pels/data_interface.cpp b/extensions/openpower-pels/data_interface.cpp
index 95de4bb..f84e80f 100644
--- a/extensions/openpower-pels/data_interface.cpp
+++ b/extensions/openpower-pels/data_interface.cpp
@@ -308,7 +308,6 @@
 }
 
 void DataInterface::getHWCalloutFields(const std::string& inventoryPath,
-                                       std::string& locationCode,
                                        std::string& fruPartNumber,
                                        std::string& ccin,
                                        std::string& serialNumber) const
@@ -320,13 +319,7 @@
     // will provide this info.  Any missing interfaces will result
     // in exceptions being thrown.
 
-    auto service = getService(inventoryPath, interface::locCode);
-
-    DBusValue locCode;
-    getProperty(service, inventoryPath, interface::locCode, "LocationCode",
-                locCode);
-
-    locationCode = std::get<std::string>(locCode);
+    auto service = getService(inventoryPath, interface::viniRecordVPD);
 
     auto properties =
         getAllProperties(service, inventoryPath, interface::viniRecordVPD);
@@ -341,5 +334,17 @@
     serialNumber = std::string{value.begin(), value.end()};
 }
 
+std::string
+    DataInterface::getLocationCode(const std::string& inventoryPath) const
+{
+    auto service = getService(inventoryPath, interface::locCode);
+
+    DBusValue locCode;
+    getProperty(service, inventoryPath, interface::locCode, "LocationCode",
+                locCode);
+
+    return std::get<std::string>(locCode);
+}
+
 } // namespace pels
 } // namespace openpower
diff --git a/extensions/openpower-pels/data_interface.hpp b/extensions/openpower-pels/data_interface.hpp
index 6a3e326..d6153b0 100644
--- a/extensions/openpower-pels/data_interface.hpp
+++ b/extensions/openpower-pels/data_interface.hpp
@@ -215,18 +215,26 @@
      *        a callout on an inventory path.
      *
      * @param[in] inventoryPath - The item to get the data for
-     * @param[out] locationCode - Filled in with the  location code
      * @param[out] fruPartNumber - Filled in with the VINI/FN keyword
      * @param[out] ccin - Filled in with the VINI/CC keyword
      * @param[out] serialNumber - Filled in with the VINI/SN keyword
      */
     virtual void getHWCalloutFields(const std::string& inventoryPath,
-                                    std::string& locationCode,
                                     std::string& fruPartNumber,
                                     std::string& ccin,
                                     std::string& serialNumber) const = 0;
 
     /**
+     * @brief Get the location code for an inventory item.
+     *
+     * @param[in] inventoryPath - The item to get the data for
+     *
+     * @return std::string - The location code
+     */
+    virtual std::string
+        getLocationCode(const std::string& inventoryPath) const = 0;
+
+    /**
      * @brief Gets the system type from Entity Manager
      *
      * @param[in] std::string - The system type string
@@ -407,16 +415,27 @@
      *        a callout on an inventory path.
      *
      * @param[in] inventoryPath - The item to get the data for
-     * @param[out] locationCode - Filled in with the  location code
      * @param[out] fruPartNumber - Filled in with the VINI/FN keyword
      * @param[out] ccin - Filled in with the VINI/CC keyword
      * @param[out] serialNumber - Filled in with the VINI/SN keyword
      */
     void getHWCalloutFields(const std::string& inventoryPath,
-                            std::string& locationCode,
                             std::string& fruPartNumber, std::string& ccin,
                             std::string& serialNumber) const override;
 
+    /**
+     * @brief Get the location code for an inventory item.
+     *
+     * Throws an exception if the inventory item doesn't have the
+     * location code interface.
+     *
+     * @param[in] inventoryPath - The item to get the data for
+     *
+     * @return std::string - The location code
+     */
+    std::string
+        getLocationCode(const std::string& inventoryPath) const override;
+
   private:
     /**
      * @brief Reads the BMC firmware version string and puts it into
diff --git a/extensions/openpower-pels/src.cpp b/extensions/openpower-pels/src.cpp
index 0899417..c2edd90 100644
--- a/extensions/openpower-pels/src.cpp
+++ b/extensions/openpower-pels/src.cpp
@@ -529,25 +529,39 @@
     std::string sn;
     std::unique_ptr<src::Callout> callout;
 
-    createCalloutsObject();
-
     try
     {
-        dataIface.getHWCalloutFields(inventoryPath, locCode, fn, ccin, sn);
+        locCode = dataIface.getLocationCode(inventoryPath);
 
-        callout = std::make_unique<src::Callout>(CalloutPriority::high, locCode,
-                                                 fn, ccin, sn);
+        try
+        {
+            dataIface.getHWCalloutFields(inventoryPath, fn, ccin, sn);
+
+            callout = std::make_unique<src::Callout>(CalloutPriority::high,
+                                                     locCode, fn, ccin, sn);
+        }
+        catch (const SdBusError& e)
+        {
+            std::string msg = "No VPD found for " + inventoryPath;
+            log<level::WARNING>(msg.c_str(), entry("ERROR=%s", e.what()));
+
+            // Just create the callout with empty FRU fields
+            callout = std::make_unique<src::Callout>(CalloutPriority::high,
+                                                     locCode, fn, ccin, sn);
+        }
     }
     catch (const SdBusError& e)
     {
-        log<level::INFO>("No VPD found for FRU callout",
-                         entry("PATH=%s", inventoryPath.c_str()));
+        std::string msg = "Could not get location code for " + inventoryPath;
+        log<level::WARNING>(msg.c_str(), entry("ERROR=%s", e.what()));
 
-        // Use the 'NoVPDforFRU' maintenance procedure instead
+        // If this were to happen, people would have to look in the UserData
+        // section that contains CALLOUT_INVENTORY_PATH to see what failed.
         callout = std::make_unique<src::Callout>(CalloutPriority::high,
                                                  "no_vpd_for_fru");
     }
 
+    createCalloutsObject();
     _callouts->addCallout(std::move(callout));
 }