worker::CollectionStatus for each inventory FRU

This commit populates CollectionStatus D-bus property under
com.ibm.VPD.Collection D-bus interface for each inventory D-bus object
path which represents a FRU.

The property tells the current status of VPD collection for a given
FRU's D-bus object path.

The property takes the below enum values:

>>>com.ibm.VPD.Collection.Status.Success
-------------------------------------
This value is assigned when VPD collection is successful.

>>>com.ibm.VPD.Collection.Status.Failure
-------------------------------------
VPD collection failure due to VPD exceptions.

>>>com.ibm.VPD.Collection.Status.InProgress
----------------------------------------
This value is assigned when VPD collection starts for the given FRU.

>>>com.ibm.VPD.Collection.Status.NotStarted
----------------------------------------
This default value is assigned when we hit prime inventory path.

Test:
1. VPD parsing failed for /sys/bus/i2c/drivers/at24/0-0051
/eeprom due to error: Unable to determine VPD format

=>CollectionStatus property value for tpm_wilson
s "com.ibm.VPD.Collection.Status.Failure"

2. FRU not found
s "com.ibm.VPD.Collection.Status.Failure"

3. Successful collection of VPD
s "com.ibm.VPD.Collection.Status.Success"

Change-Id: Ia5010a181f720454bb51538d6fcf308daf6b75ca
Signed-off-by: Priyanga Ramasamy <priyanga24@in.ibm.com>
diff --git a/vpd-manager/include/constants.hpp b/vpd-manager/include/constants.hpp
index 7f23070..f7e55d0 100644
--- a/vpd-manager/include/constants.hpp
+++ b/vpd-manager/include/constants.hpp
@@ -197,5 +197,18 @@
 static constexpr auto systemdObjectPath = "/org/freedesktop/systemd1";
 static constexpr auto systemdManagerInterface =
     "org.freedesktop.systemd1.Manager";
+
+static constexpr auto vpdCollectionInterface = "com.ibm.VPD.Collection";
+
+// enumerated values of CollectionStatus D-bus property defined under
+// com.ibm.VPD.Collection interface.
+static constexpr auto vpdCollectionSuccess =
+    "com.ibm.VPD.Collection.Status.Success";
+static constexpr auto vpdCollectionFailure =
+    "com.ibm.VPD.Collection.Status.Failure";
+static constexpr auto vpdCollectionInProgress =
+    "com.ibm.VPD.Collection.Status.InProgress";
+static constexpr auto vpdCollectionNotStarted =
+    "com.ibm.VPD.Collection.Status.NotStarted";
 } // namespace constants
 } // namespace vpd
diff --git a/vpd-manager/include/utility/dbus_utility.hpp b/vpd-manager/include/utility/dbus_utility.hpp
index 27014df..0cb8151 100644
--- a/vpd-manager/include/utility/dbus_utility.hpp
+++ b/vpd-manager/include/utility/dbus_utility.hpp
@@ -563,5 +563,34 @@
     return l_rc;
 }
 
+/**
+ * @brief API to notify FRU VPD Collection status.
+ *
+ * This API uses PIM's Notify method to update the given FRU VPD collection
+ * status on D-bus.
+ *
+ * @param[in] i_inventoryPath - D-bus inventory path
+ * @param[in] i_fruCollectionStatus - FRU VPD collection status.
+ *
+ * @return true if update succeeds, false otherwise.
+ */
+inline bool notifyFRUCollectionStatus(const std::string& i_inventoryPath,
+                                      const std::string& i_fruCollectionStatus)
+{
+    types::ObjectMap l_objectMap;
+    types::InterfaceMap l_interfaceMap;
+    types::PropertyMap l_propertyMap;
+
+    l_propertyMap.emplace("CollectionStatus", i_fruCollectionStatus);
+    l_interfaceMap.emplace(constants::vpdCollectionInterface, l_propertyMap);
+    l_objectMap.emplace(i_inventoryPath, l_interfaceMap);
+
+    if (!dbusUtility::callPIM(std::move(l_objectMap)))
+    {
+        return false;
+    }
+
+    return true;
+}
 } // namespace dbusUtility
 } // namespace vpd
diff --git a/vpd-manager/src/worker.cpp b/vpd-manager/src/worker.cpp
index 82afb3a..262e3dc 100644
--- a/vpd-manager/src/worker.cpp
+++ b/vpd-manager/src/worker.cpp
@@ -870,6 +870,14 @@
         processFunctionalProperty(l_Fru["inventoryPath"], l_interfaces);
         processEnabledProperty(l_Fru["inventoryPath"], l_interfaces);
 
+        // Emplace the default state of FRU VPD collection
+        types::PropertyMap l_fruCollectionProperty = {
+            {"CollectionStatus", constants::vpdCollectionNotStarted}};
+
+        vpdSpecificUtility::insertOrMerge(l_interfaces,
+                                          constants::vpdCollectionInterface,
+                                          std::move(l_fruCollectionProperty));
+
         l_objectInterfaceMap.emplace(std::move(l_fruObjectPath),
                                      std::move(l_interfaces));
     }
@@ -1156,6 +1164,14 @@
             processFunctionalProperty(inventoryPath, interfaces);
             processEnabledProperty(inventoryPath, interfaces);
 
+            // Update collection status as successful
+            types::PropertyMap l_collectionProperty = {
+                {"CollectionStatus", constants::vpdCollectionSuccess}};
+
+            vpdSpecificUtility::insertOrMerge(interfaces,
+                                              constants::vpdCollectionInterface,
+                                              std::move(l_collectionProperty));
+
             objectInterfaceMap.emplace(std::move(fruObjectPath),
                                        std::move(interfaces));
         }
@@ -1430,6 +1446,8 @@
 std::tuple<bool, std::string> Worker::parseAndPublishVPD(
     const std::string& i_vpdFilePath)
 {
+    std::string l_inventoryPath{};
+
     try
     {
         m_semaphore.acquire();
@@ -1439,6 +1457,26 @@
         m_activeCollectionThreadCount++;
         m_mutex.unlock();
 
+        // Set CollectionStatus as InProgress. Since it's an intermediate state
+        // D-bus set-property call is good enough to update the status.
+        try
+        {
+            l_inventoryPath = jsonUtility::getInventoryObjPathFromJson(
+                m_parsedJson, i_vpdFilePath);
+
+            dbusUtility::writeDbusProperty(
+                jsonUtility::getServiceName(m_parsedJson, l_inventoryPath),
+                l_inventoryPath, constants::vpdCollectionInterface,
+                "CollectionStatus",
+                types::DbusVariantType{constants::vpdCollectionInProgress});
+        }
+        catch (const std::exception& l_exception)
+        {
+            logging::logMessage(
+                "Unable to set CollectionStatus as InProgress for " +
+                i_vpdFilePath + ". Error : " + l_exception.what());
+        }
+
         const types::VPDMapVariant& parsedVpdMap = parseVpdFile(i_vpdFilePath);
 
         types::ObjectMap objectInterfaceMap;
@@ -1456,6 +1494,15 @@
     }
     catch (const std::exception& ex)
     {
+        // Notify FRU's VPD CollectionStatus as Failure
+        if (!dbusUtility::notifyFRUCollectionStatus(
+                l_inventoryPath, constants::vpdCollectionFailure))
+        {
+            logging::logMessage(
+                "Call to PIM Notify method failed to update Collection status as Failure for " +
+                i_vpdFilePath);
+        }
+
         // handle all the exceptions internally. Return only true/false
         // based on status of execution.
         if (typeid(ex) == std::type_index(typeid(DataException)))