Prime system blueprint from wait-vpd-parsers

This commit updates wait-vpd-parsers to prime system blueprint.
As part of PST VPD collection flow, priming inventory objects needs to
be triggered as a part of systemd target, instead of being triggered by
vpd-manager.
This commit only implements only stub APIs under PrimeInventory class.

Change-Id: I144b13192e9ce39461c331c51ed7d4d9e952809c
Signed-off-by: Anupama B R <anupama.b.r1@ibm.com>
diff --git a/wait-vpd-parser/include/prime_inventory.hpp b/wait-vpd-parser/include/prime_inventory.hpp
new file mode 100644
index 0000000..8dab2f8
--- /dev/null
+++ b/wait-vpd-parser/include/prime_inventory.hpp
@@ -0,0 +1,132 @@
+#pragma once
+
+#include "types.hpp"
+
+#include <nlohmann/json.hpp>
+
+#include <string>
+
+/**
+ * @brief Class to prime system blueprint.
+ *
+ * This class will be used for priming the system, by traversing the system
+ * config JSON and primes all the FRU paths which qualifies for priming and
+ * publishes inventory object paths on the DBus.
+ */
+class PrimeInventory
+{
+  public:
+    /**
+     * Deleted methods
+     */
+    PrimeInventory(const PrimeInventory&) = delete;
+    PrimeInventory& operator=(const PrimeInventory&) = delete;
+    PrimeInventory& operator=(PrimeInventory&&) = delete;
+    PrimeInventory(PrimeInventory&&) = delete;
+
+    /**
+     * Contructor
+     *
+     * @throw std::exception
+     */
+    PrimeInventory();
+
+    /**
+     * @brief API to prime system blueprint.
+     *
+     * The API will traverse the system config JSON and will prime all the FRU
+     * paths which qualifies for priming.
+     *
+     */
+    void primeSystemBlueprint() const noexcept;
+
+  private:
+    /**
+     * @brief API to check if priming is required.
+     *
+     * The API will traverse the system config JSON and counts the FRU
+     * paths which qualifies for priming and compares with count of object paths
+     * found under PIM which hosts the "xyz.openbmc_project.Common.Progress"
+     * interface. If the dbus count is equal to or greater than the count from
+     * JSON config consider as priming is not required.
+     *
+     * @return true if priming is required, false otherwise.
+     */
+    bool isPrimingRequired() const noexcept;
+
+    /**
+     * @brief API to prime inventory Objects.
+     *
+     * @param[in] i_vpdFilePath - EEPROM file path.
+     *
+     * @return true if the prime inventory is success, false otherwise.
+     */
+    bool primeInventory(const std::string& i_vpdFilePath) const noexcept;
+
+    /**
+     * @brief API to populate all required interface for a FRU.
+     *
+     * @param[in] i_interfaceJson - JSON containing interfaces to be populated.
+     * @param[in,out] io_interfaceMap - Map to hold populated interfaces.
+     * @param[in] i_parsedVpdMap - Parsed VPD as a map.
+     */
+    void populateInterfaces(
+        const nlohmann::json& i_interfaceJson,
+        vpd::types::InterfaceMap& io_interfaceMap,
+        const vpd::types::VPDMapVariant& i_parsedVpdMap) const noexcept;
+
+    /**
+     * @brief API to check if present property should be handled for given FRU.
+     *
+     * vpd-manager should update present property for a FRU if and only if it's
+     * not synthesized and vpd-manager handles present property for the FRU.
+     * This API assumes "handlePresence" tag is a subset of "synthesized" tag.
+     *
+     * @param[in] i_fru -  JSON block for a single FRU.
+     *
+     * @return true if present property should be handled, false otherwise.
+     */
+    inline bool isPresentPropertyHandlingRequired(
+        const nlohmann::json& i_fru) const noexcept
+    {
+        return !i_fru.value("synthesized", false) &&
+               i_fru.value("handlePresence", true);
+    }
+
+    /**
+     * @brief API to update "Functional" property.
+     *
+     * The API sets the default value for "Functional" property once if the
+     * property is not yet populated over DBus. As the property value is not
+     * controlled by the VPD-Collection process, if it is found already
+     * populated, the functions skips re-populating the property so that already
+     * existing value can be retained.
+     *
+     * @param[in] i_inventoryObjPath - Inventory path as read from config JSON.
+     * @param[in,out] io_interfaces - Map to hold all the interfaces for the
+     * FRU.
+     */
+    void processFunctionalProperty(
+        const std::string& i_inventoryObjPath,
+        vpd::types::InterfaceMap& io_interfaces) const noexcept;
+
+    /**
+     * @brief API to update "enabled" property.
+     *
+     * The API sets the default value for "enabled" property once if the
+     * property is not yet populated over DBus. As the property value is not
+     * controlled by the VPD-Collection process, if it is found already
+     * populated, the functions skips re-populating the property so that already
+     * existing value can be retained.
+     *
+     * @param[in] i_inventoryObjPath - Inventory path as read from config JSON.
+     * @param[in,out] io_interfaces - Map to hold all the interfaces for the
+     * FRU.
+     */
+    void processEnabledProperty(
+        const std::string& i_inventoryObjPath,
+        vpd::types::InterfaceMap& io_interfaces) const noexcept;
+
+    // Parsed JSON file.
+    nlohmann::json m_sysCfgJsonObj{};
+};
diff --git a/wait-vpd-parser/meson.build b/wait-vpd-parser/meson.build
index c9d6a6e..52f5c75 100644
--- a/wait-vpd-parser/meson.build
+++ b/wait-vpd-parser/meson.build
@@ -6,14 +6,26 @@
 endif
 
 sdbusplus = dependency('sdbusplus', fallback: ['sdbusplus', 'sdbusplus_dep'])
-dependency_list = [CLI_dep, sdbusplus]
 
-sources = ['src/wait_vpd_parser.cpp', '../vpd-manager/src/logger.cpp']
+libgpiodcxx = dependency(
+    'libgpiodcxx',
+    default_options: ['bindings=cxx'],
+    version: '<1.7.0',
+)
+
+dependency_list = [CLI_dep, sdbusplus, libgpiodcxx]
+
+sources = [
+    'src/wait_vpd_parser.cpp',
+    '../vpd-manager/src/logger.cpp',
+    'src/prime_inventory.cpp',
+    '../vpd-manager/src/event_logger.cpp',
+]
 
 wait_vpd_parser_exe = executable(
     'wait-vpd-parser',
     sources,
-    include_directories: ['../', '../vpd-manager/include'],
+    include_directories: ['include/', '../', '../vpd-manager/include'],
     dependencies: dependency_list,
     install: true,
 )
diff --git a/wait-vpd-parser/src/prime_inventory.cpp b/wait-vpd-parser/src/prime_inventory.cpp
new file mode 100644
index 0000000..84688d0
--- /dev/null
+++ b/wait-vpd-parser/src/prime_inventory.cpp
@@ -0,0 +1,98 @@
+#include "prime_inventory.hpp"
+
+#include "event_logger.hpp"
+#include "exceptions.hpp"
+#include "utility/dbus_utility.hpp"
+#include "utility/json_utility.hpp"
+#include "utility/vpd_specific_utility.hpp"
+
+#include <string>
+
+PrimeInventory::PrimeInventory()
+{
+    try
+    {
+        uint16_t l_errCode = 0;
+        m_sysCfgJsonObj =
+            vpd::jsonUtility::getParsedJson(INVENTORY_JSON_SYM_LINK, l_errCode);
+
+        if (l_errCode)
+        {
+            throw std::runtime_error(
+                "JSON parsing failed for file [ " +
+                std::string(INVENTORY_JSON_SYM_LINK) + " ], error : " +
+                vpd::vpdSpecificUtility::getErrCodeMsg(l_errCode));
+        }
+
+        // check for mandatory fields at this point itself.
+        if (!m_sysCfgJsonObj.contains("frus"))
+        {
+            throw std::runtime_error(
+                "Mandatory tag(s) missing from JSON file [" +
+                std::string(INVENTORY_JSON_SYM_LINK) + "]");
+        }
+    }
+    catch (const std::exception& l_ex)
+    {
+        vpd::EventLogger::createSyncPel(
+            vpd::types::ErrorType::JsonFailure,
+            vpd::types::SeverityType::Critical, __FILE__, __FUNCTION__, 0,
+            "Prime inventory failed, reason: " + std::string(l_ex.what()),
+            std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+
+        throw;
+    }
+}
+
+bool PrimeInventory::isPrimingRequired() const noexcept
+{
+    // ToDo: Check if priming is required.
+    return true;
+}
+
+void PrimeInventory::primeSystemBlueprint() const noexcept
+{
+    try
+    {
+        /*ToDo:
+      * Check if priming is required.
+      * Traverse the system config JSON &
+      prime all the FRU paths which qualifies for priming.
+      */
+    }
+    catch (const std::exception& l_ex)
+    {
+        // ToDo: log an error
+    }
+}
+
+bool PrimeInventory::primeInventory(
+    [[maybe_unused]] const std::string& i_vpdFilePath) const noexcept
+{
+    // ToDo: Travers system config JSON & prime inventory objects found under
+    // the EEPROM.
+    return true;
+}
+
+void PrimeInventory::populateInterfaces(
+    [[maybe_unused]] const nlohmann::json& i_interfaceJson,
+    [[maybe_unused]] vpd::types::InterfaceMap& io_interfaceMap,
+    [[maybe_unused]] const vpd::types::VPDMapVariant& i_parsedVpdMap)
+    const noexcept
+{
+    // ToDo: Populate interfaces needs to be published on Dbus.
+}
+
+void PrimeInventory::processFunctionalProperty(
+    [[maybe_unused]] const std::string& i_inventoryObjPath,
+    [[maybe_unused]] vpd::types::InterfaceMap& io_interfaces) const noexcept
+{
+    // ToDo: Populate interface to publish Functional property on Dbus.
+}
+
+void PrimeInventory::processEnabledProperty(
+    [[maybe_unused]] const std::string& i_inventoryObjPath,
+    [[maybe_unused]] vpd::types::InterfaceMap& io_interfaces) const noexcept
+{
+    // ToDo: Populate interface to publish Enabled property on Dbus.
+}
diff --git a/wait-vpd-parser/src/wait_vpd_parser.cpp b/wait-vpd-parser/src/wait_vpd_parser.cpp
index 44f1da3..352f5cd 100644
--- a/wait-vpd-parser/src/wait_vpd_parser.cpp
+++ b/wait-vpd-parser/src/wait_vpd_parser.cpp
@@ -2,6 +2,7 @@
 
 #include "constants.hpp"
 #include "logger.hpp"
+#include "prime_inventory.hpp"
 #include "utility/dbus_utility.hpp"
 
 #include <CLI/CLI.hpp>
@@ -104,20 +105,34 @@
 
 int main(int argc, char** argv)
 {
-    CLI::App l_app{"Wait VPD parser app"};
+    try
+    {
+        CLI::App l_app{"Wait VPD parser app"};
 
-    // default retry limit and sleep duration values
-    unsigned l_retryLimit{100};
-    unsigned l_sleepDurationInSeconds{2};
+        // default retry limit and sleep duration values
+        unsigned l_retryLimit{100};
+        unsigned l_sleepDurationInSeconds{2};
 
-    l_app.add_option("--retryLimit, -r", l_retryLimit, "Retry limit");
-    l_app.add_option("--sleepDurationInSeconds, -s", l_sleepDurationInSeconds,
-                     "Sleep duration in seconds between each retry");
+        l_app.add_option("--retryLimit, -r", l_retryLimit, "Retry limit");
+        l_app.add_option("--sleepDurationInSeconds, -s",
+                         l_sleepDurationInSeconds,
+                         "Sleep duration in seconds between each retry");
 
-    CLI11_PARSE(l_app, argc, argv);
+        CLI11_PARSE(l_app, argc, argv);
 
-    return collectAllFruVpd()
-               ? checkVpdCollectionStatus(l_retryLimit,
-                                          l_sleepDurationInSeconds)
-               : vpd::constants::VALUE_1;
+        PrimeInventory l_primeObj;
+        l_primeObj.primeSystemBlueprint();
+
+        return collectAllFruVpd()
+                   ? checkVpdCollectionStatus(l_retryLimit,
+                                              l_sleepDurationInSeconds)
+                   : vpd::constants::VALUE_1;
+    }
+    catch (const std::exception& l_ex)
+    {
+        const auto l_logger = vpd::Logger::getLoggerInstance();
+        l_logger->logMessage("Exiting from wait-vpd-parser, reason: " +
+                             std::string(l_ex.what()));
+        return vpd::constants::VALUE_1;
+    }
 }