Update dump inventory and dump object

VPD-Tool currently tries to populate interfaces in case of dump object
and dump inventory without confrming if the object implements that
interface. This can cause Dbus exceptions which can be seen along with
output.

The commit add a pre-check and populates interfaces only which are
applicable. It also adds support for some more interface(s).

Test:

verified both dump object and dump inventory.
Works without giving any exceptions.

root@rain203bmc:~# /tmp/vpd-tool -o -O /system
[
    {
        "/system": {
            "LocationCode": "U9824.42A.13E0C40",
            "Model": "9824-42A",
            "PrettyName": "System",
            "SerialNumber": "13E0C40",
            "SubModel": "S0",
            "TYPE": "FRU",
            "type": "xyz.openbmc_project.Inventory.Item.System"
        }
    }
]
root@rain203bmc:~#
/tmp/vpd-tool -o -O /system/chassis/motherboard/pcieslot10/pcie_card10
[
    {
        "/system/chassis/motherboard/pcieslot10/pcie_card10": {
            "Address": "80",
            "Bus": "29",
            "CC": "6B87",
            "DR": "NVME JBOF  RISER",
            "FN": "03FL195",
            "LocationCode": "U78DB.ND0.WZS0019-P0-C10",
            "PN": "03FL286",
            "PrettyName": "PCIe4 x16 or PCIe5 x8 adapter",
            "SN": "YA30UF13S01P",
            "SlotNumber": "10",
            "TYPE": "FRU",
            "type": "xyz.openbmc_project.Inventory.Item.FabricAdapter"
        }
    }
]

Change-Id: I97ecfbec734c14cddff075f2bbf6469f70f6e25e
Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
diff --git a/vpd-tool/include/tool_constants.hpp b/vpd-tool/include/tool_constants.hpp
index 84b7025..00c64b8 100644
--- a/vpd-tool/include/tool_constants.hpp
+++ b/vpd-tool/include/tool_constants.hpp
@@ -24,7 +24,7 @@
 constexpr auto vpdManagerObjectPath = "/com/ibm/VPD/Manager";
 constexpr auto vpdManagerInfName = "com.ibm.VPD.Manager";
 constexpr auto inventoryItemInf = "xyz.openbmc_project.Inventory.Item";
-constexpr auto kwdVpdInf = "com.ibm.ipzvpd.VINI";
+constexpr auto viniInf = "com.ibm.ipzvpd.VINI";
 constexpr auto locationCodeInf = "com.ibm.ipzvpd.Location";
 constexpr auto assetInf = "xyz.openbmc_project.Inventory.Decorator.Asset";
 constexpr auto objectMapperService = "xyz.openbmc_project.ObjectMapper";
@@ -38,5 +38,11 @@
 constexpr auto dbusObjectPath = "/org/freedesktop/DBus";
 constexpr auto dbusInterface = "org.freedesktop.DBus";
 constexpr auto biosConfigMgrService = "xyz.openbmc_project.BIOSConfigManager";
+constexpr auto networkInf =
+    "xyz.openbmc_project.Inventory.Item.NetworkInterface";
+constexpr auto pcieSlotInf = "xyz.openbmc_project.Inventory.Item.PCIeSlot";
+constexpr auto slotNumInf = "xyz.openbmc_project.Inventory.Decorator.Slot";
+constexpr auto i2cDeviceInf =
+    "xyz.openbmc_project.Inventory.Decorator.I2CDevice";
 } // namespace constants
 } // namespace vpd
diff --git a/vpd-tool/include/vpd_tool.hpp b/vpd-tool/include/vpd_tool.hpp
index 67a52fc..0004949 100644
--- a/vpd-tool/include/vpd_tool.hpp
+++ b/vpd-tool/include/vpd_tool.hpp
@@ -43,6 +43,38 @@
     nlohmann::json getFruProperties(const std::string& i_objectPath) const;
 
     /**
+     * @brief API to populate FRU JSON.
+     *
+     * The API will create FRUs JSON, which will have property value pairs for
+     * all the interfaces required for that particular FRU.
+     *
+     * @param[in] i_inventoryObjPath - FRU inventory path.
+     * @param[in, out] io_fruJsonObject - JSON object.
+     * @param[in] i_interfaceList - list of interfaces implemented by the FRU on
+     * Dbus.
+     */
+    void populateFruJson(const std::string& i_inventoryObjPath,
+                         nlohmann::json& io_fruJsonObject,
+                         const std::vector<std::string>& i_interfaceList) const;
+
+    /**
+     * @brief API to populate JSON for an interface.
+     *
+     * The API will create interface JSON, which will have property value pairs
+     * for all the properties required under that interface.
+     *
+     * @param[in] i_inventoryObjPath - FRU inventory path.
+     * @param[in] i_infName - interface whose JSON need to be populated.
+     * @param[in] i_propList - List of properties needed in the JSON.
+     * @param[in, out] io_fruJsonObject - JSON object.
+     */
+    template <typename PropertyType>
+    void populateInterfaceJson(const std::string& i_inventoryObjPath,
+                               const std::string& i_infName,
+                               const std::vector<std::string>& i_propList,
+                               nlohmann::json& io_fruJsonObject) const;
+
+    /**
      * @brief Get any inventory property in JSON.
      *
      * API to get any property of a FRU in JSON format. Given an object path,
diff --git a/vpd-tool/src/vpd_tool.cpp b/vpd-tool/src/vpd_tool.cpp
index f66450c..e9f15eb 100644
--- a/vpd-tool/src/vpd_tool.cpp
+++ b/vpd-tool/src/vpd_tool.cpp
@@ -119,6 +119,123 @@
     return l_rc;
 }
 
+template <typename PropertyType>
+void VpdTool::populateInterfaceJson(const std::string& i_inventoryObjPath,
+                                    const std::string& i_infName,
+                                    const std::vector<std::string>& i_propList,
+                                    nlohmann::json& io_fruJsonObject) const
+{
+    nlohmann::json l_interfaceJsonObj = nlohmann::json::object({});
+
+    auto l_readProperties = [i_inventoryObjPath, &l_interfaceJsonObj, i_infName,
+                             this](const std::string& i_property) {
+        const nlohmann::json l_propertyJsonObj =
+            getInventoryPropertyJson<PropertyType>(i_inventoryObjPath,
+                                                   i_infName, i_property);
+        l_interfaceJsonObj.insert(l_propertyJsonObj.cbegin(),
+                                  l_propertyJsonObj.cend());
+    };
+
+    std::for_each(i_propList.cbegin(), i_propList.cend(), l_readProperties);
+
+    if (!l_interfaceJsonObj.empty())
+    {
+        io_fruJsonObject.insert(l_interfaceJsonObj.cbegin(),
+                                l_interfaceJsonObj.cend());
+    }
+}
+
+void VpdTool::populateFruJson(
+    const std::string& i_inventoryObjPath, nlohmann::json& io_fruJsonObject,
+    const std::vector<std::string>& i_interfaceList) const
+{
+    for (const auto& l_interface : i_interfaceList)
+    {
+        if (l_interface == constants::inventoryItemInf)
+        {
+            const std::vector<std::string> l_properties = {"PrettyName"};
+            populateInterfaceJson<std::string>(i_inventoryObjPath,
+                                               constants::inventoryItemInf,
+                                               l_properties, io_fruJsonObject);
+            continue;
+        }
+
+        if (l_interface == constants::locationCodeInf)
+        {
+            const std::vector<std::string> l_properties = {"LocationCode"};
+            populateInterfaceJson<std::string>(i_inventoryObjPath,
+                                               constants::locationCodeInf,
+                                               l_properties, io_fruJsonObject);
+            continue;
+        }
+
+        if (l_interface == constants::viniInf)
+        {
+            const std::vector<std::string> l_properties = {"SN", "PN", "CC",
+                                                           "FN", "DR"};
+            populateInterfaceJson<vpd::types::BinaryVector>(
+                i_inventoryObjPath, constants::viniInf, l_properties,
+                io_fruJsonObject);
+            continue;
+        }
+
+        if (l_interface == constants::assetInf)
+        {
+            if (std::find(i_interfaceList.begin(), i_interfaceList.end(),
+                          constants::viniInf) != i_interfaceList.end())
+            {
+                // The value will be filled from VINI interface. Don't
+                // process asset interface.
+                continue;
+            }
+
+            const std::vector<std::string> l_properties = {
+                "Model", "SerialNumber", "SubModel"};
+
+            populateInterfaceJson<std::string>(i_inventoryObjPath,
+                                               constants::assetInf,
+                                               l_properties, io_fruJsonObject);
+            continue;
+        }
+
+        if (l_interface == constants::networkInf)
+        {
+            const std::vector<std::string> l_properties = {"MACAddress"};
+            populateInterfaceJson<std::string>(i_inventoryObjPath,
+                                               constants::networkInf,
+                                               l_properties, io_fruJsonObject);
+            continue;
+        }
+
+        if (l_interface == constants::pcieSlotInf)
+        {
+            const std::vector<std::string> l_properties = {"SlotType"};
+            populateInterfaceJson<std::string>(i_inventoryObjPath,
+                                               constants::pcieSlotInf,
+                                               l_properties, io_fruJsonObject);
+            continue;
+        }
+
+        if (l_interface == constants::slotNumInf)
+        {
+            const std::vector<std::string> l_properties = {"SlotNumber"};
+            populateInterfaceJson<uint32_t>(i_inventoryObjPath,
+                                            constants::slotNumInf, l_properties,
+                                            io_fruJsonObject);
+            continue;
+        }
+
+        if (l_interface == constants::i2cDeviceInf)
+        {
+            const std::vector<std::string> l_properties = {"Address", "Bus"};
+            populateInterfaceJson<uint32_t>(i_inventoryObjPath,
+                                            constants::i2cDeviceInf,
+                                            l_properties, io_fruJsonObject);
+            continue;
+        }
+    }
+}
+
 nlohmann::json VpdTool::getFruProperties(const std::string& i_objectPath) const
 {
     // check if FRU is present in the system
@@ -139,63 +256,16 @@
 
     auto& l_fruObject = l_fruJson[l_displayObjectPath];
 
-    const auto l_prettyNameInJson = getInventoryPropertyJson<std::string>(
-        i_objectPath, constants::inventoryItemInf, "PrettyName");
-    if (!l_prettyNameInJson.empty())
+    types::MapperGetObject l_mapperResp = utils::GetServiceInterfacesForObject(
+        i_objectPath, std::vector<std::string>{});
+
+    for (const auto& [l_service, l_interfaceList] : l_mapperResp)
     {
-        l_fruObject.insert(l_prettyNameInJson.cbegin(),
-                           l_prettyNameInJson.cend());
-    }
-
-    const auto l_locationCodeInJson = getInventoryPropertyJson<std::string>(
-        i_objectPath, constants::locationCodeInf, "LocationCode");
-    if (!l_locationCodeInJson.empty())
-    {
-        l_fruObject.insert(l_locationCodeInJson.cbegin(),
-                           l_locationCodeInJson.cend());
-    }
-
-    // Get the properties under VINI interface.
-
-    nlohmann::json l_viniPropertiesInJson = nlohmann::json::object({});
-
-    auto l_readViniKeyWord = [i_objectPath, &l_viniPropertiesInJson,
-                              this](const std::string& i_keyWord) {
-        const nlohmann::json l_keyWordJson =
-            getInventoryPropertyJson<vpd::types::BinaryVector>(
-                i_objectPath, constants::kwdVpdInf, i_keyWord);
-        l_viniPropertiesInJson.insert(l_keyWordJson.cbegin(),
-                                      l_keyWordJson.cend());
-    };
-
-    const std::vector<std::string> l_viniKeywords = {"SN", "PN", "CC", "FN",
-                                                     "DR"};
-
-    std::for_each(l_viniKeywords.cbegin(), l_viniKeywords.cend(),
-                  l_readViniKeyWord);
-
-    if (!l_viniPropertiesInJson.empty())
-    {
-        l_fruObject.insert(l_viniPropertiesInJson.cbegin(),
-                           l_viniPropertiesInJson.cend());
-    }
-    // if a FRU doesn't have VINI properties, we need to get the properties from
-    // Decorator.Asset interface
-    else
-    {
-        // Get properties under Decorator.Asset interface
-        const auto l_decoratorAssetPropertiesMap =
-            utils::getPropertyMap(constants::inventoryManagerService,
-                                  i_objectPath, constants::assetInf);
-
-        for (const auto& l_aProperty : l_decoratorAssetPropertiesMap)
+        if (l_service != constants::inventoryManagerService)
         {
-            if (const auto l_propertyValueStr =
-                    std::get_if<std::string>(&l_aProperty.second))
-            {
-                l_fruObject.emplace(l_aProperty.first, *l_propertyValueStr);
-            }
+            continue;
         }
+        populateFruJson(i_objectPath, l_fruObject, l_interfaceList);
     }
 
     const auto l_typePropertyJson = getFruTypeProperty(i_objectPath);
@@ -244,6 +314,11 @@
 
                 l_resultInJson.emplace(i_propertyName, l_keywordStrValue);
             }
+            else if constexpr (std::is_same<PropertyType, uint32_t>::value)
+            {
+                l_resultInJson.emplace(i_propertyName,
+                                       std::to_string(*l_value));
+            }
         }
         else
         {