vpd-tool dumpObject: show Decorator.Asset properties (#599)

This commit adds properties under Decorator.Asset interface such as
"Model","SerialNumber", etc. to the vpd-tool --dumpObject JSON.
Properties under Decorator.Asset interface are derived from VINI
keywords.
If a FRU doesn't have properties under VINI interface on PIM,
we need to get the properties from Decorator.Asset interface.

This commit also adds "TYPE" property of a FRU in --dumpObject JSON.

Change-Id: Ib72738143f34a4206da15e159f450715f15b066e
Signed-off-by: Souvik Roy <souvik.roy10@ibm.com>
diff --git a/vpd-tool/include/tool_types.hpp b/vpd-tool/include/tool_types.hpp
index 1e9ff7d..86e942c 100644
--- a/vpd-tool/include/tool_types.hpp
+++ b/vpd-tool/include/tool_types.hpp
@@ -67,6 +67,9 @@
 // A table column name-size pair
 using TableColumnNameSizePair = std::pair<std::string, std::size_t>;
 
+/* Map<Property, Value>*/
+using PropertyMap = std::map<std::string, DbusVariantType>;
+
 enum UserOption
 {
     Exit,
diff --git a/vpd-tool/include/tool_utils.hpp b/vpd-tool/include/tool_utils.hpp
index 4d650c1..fece0ec 100644
--- a/vpd-tool/include/tool_utils.hpp
+++ b/vpd-tool/include/tool_utils.hpp
@@ -73,6 +73,55 @@
 }
 
 /**
+ * @brief An API to get property map for an interface.
+ *
+ * This API returns a map of property and its value with respect to a particular
+ * interface.
+ *
+ * Note: It will be caller's responsibility to check for empty map returned and
+ * generate appropriate error.
+ *
+ * @param[in] i_service - Service name.
+ * @param[in] i_objectPath - object path.
+ * @param[in] i_interface - Interface, for the properties to be listed.
+ *
+ * @return - A map of property and value of an interface, if success.
+ *           if failed, empty map.
+ */
+inline types::PropertyMap getPropertyMap(
+    const std::string& i_service, const std::string& i_objectPath,
+    const std::string& i_interface) noexcept
+{
+    types::PropertyMap l_propertyValueMap;
+    if (i_service.empty() || i_objectPath.empty() || i_interface.empty())
+    {
+        // TODO: Enable logging when verbose is enabled.
+        // std::cout << "Invalid parameters to get property map" << std::endl;
+        return l_propertyValueMap;
+    }
+
+    try
+    {
+        auto l_bus = sdbusplus::bus::new_default();
+        auto l_method =
+            l_bus.new_method_call(i_service.c_str(), i_objectPath.c_str(),
+                                  "org.freedesktop.DBus.Properties", "GetAll");
+        l_method.append(i_interface);
+        auto l_result = l_bus.call(l_method);
+        l_result.read(l_propertyValueMap);
+    }
+    catch (const sdbusplus::exception::SdBusError& l_ex)
+    {
+        // TODO: Enable logging when verbose is enabled.
+        // std::cerr << "Failed to get property map for service: [" << i_service
+        //           << "], object path: [" << i_objectPath
+        //           << "] Error : " << l_ex.what() << std::endl;
+    }
+
+    return l_propertyValueMap;
+}
+
+/**
  * @brief An API to print json data on stdout.
  *
  * @param[in] i_jsonData - JSON object.
diff --git a/vpd-tool/src/vpd_tool.cpp b/vpd-tool/src/vpd_tool.cpp
index f6e4cd9..7d229d7 100644
--- a/vpd-tool/src/vpd_tool.cpp
+++ b/vpd-tool/src/vpd_tool.cpp
@@ -150,15 +150,6 @@
                            l_locationCodeInJson.cend());
     }
 
-    const auto l_subModelInJson = getInventoryPropertyJson<std::string>(
-        i_objectPath, constants::assetInf, "SubModel");
-
-    if (!l_subModelInJson.empty() &&
-        !l_subModelInJson.value("SubModel", "").empty())
-    {
-        l_fruObject.insert(l_subModelInJson.cbegin(), l_subModelInJson.cend());
-    }
-
     // Get the properties under VINI interface.
 
     nlohmann::json l_viniPropertiesInJson = nlohmann::json::object({});
@@ -183,6 +174,24 @@
         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 (const auto l_propertyValueStr =
+                    std::get_if<std::string>(&l_aProperty.second))
+            {
+                l_fruObject.emplace(l_aProperty.first, *l_propertyValueStr);
+            }
+        }
+    }
 
     const auto l_typePropertyJson = getFruTypeProperty(i_objectPath);
     if (!l_typePropertyJson.empty())
@@ -191,6 +200,9 @@
                            l_typePropertyJson.cend());
     }
 
+    // insert FRU "TYPE"
+    l_fruObject.emplace("TYPE", "FRU");
+
     return l_fruJson;
 }