Refactor wait-vpd-status from script to executable
This commit implements wait-vpd-status.sh logic as an application
written in C++. Moving the logic to C++ allows better error handling and
more flexibility with respect to future requirements.
Test:
```
1. Ensure vpd-manager CollectionStatus property is in "Completed" state.
2. Run wait-vpd-parser executable
3. Observe executable waits for 2s, then reads vpd-manager
CollectionStatus property and outputs a trace saying VPD collection
is completed, and then exits with return code 0
4. Using busctl change vpd-manager CollectionStatus property to
"InProgress"
5. Run wait-vpd-parser executable
6. Observe executable waits for 2s, and reads vpd-manager
CollectionStatus property for a total of 100 retries. After 100
retries, it outputs a trace saying timeout and exits with return code 1
7. Using busctl change vpd-manager CollectionStatus property to
"InProgress"
8. Run wait-vpd-parser executable
9. Observe executable waits for 2s, and reads vpd-manager with retry
count starting from 100 and counting down.
10. Now change CollectionStatus property to "Completed"
11. Observe executable reads vpd-manager CollectionStatus property and
outputs a trace saying VPD collection is completed, and then exits
with return code 0.
```
Change-Id: Ifa96a1262b73f4eacc6e13d4e05c710d6e693035
Signed-off-by: Souvik Roy <souvikroyofficial10@gmail.com>
diff --git a/meson.build b/meson.build
index e7983ea..3b99744 100644
--- a/meson.build
+++ b/meson.build
@@ -63,6 +63,7 @@
if get_option('ibm_system').allowed()
subdir('vpd-tool')
+ subdir('wait-vpd-parser')
scripts = ['scripts/wait-vpd-status.sh']
install_data(
diff --git a/wait-vpd-parser/meson.build b/wait-vpd-parser/meson.build
new file mode 100644
index 0000000..c9d6a6e
--- /dev/null
+++ b/wait-vpd-parser/meson.build
@@ -0,0 +1,19 @@
+compiler = meson.get_compiler('cpp')
+if compiler.has_header('CLI/CLI.hpp')
+ CLI_dep = declare_dependency()
+else
+ CLI_dep = dependency('CLI11')
+endif
+
+sdbusplus = dependency('sdbusplus', fallback: ['sdbusplus', 'sdbusplus_dep'])
+dependency_list = [CLI_dep, sdbusplus]
+
+sources = ['src/wait_vpd_parser.cpp', '../vpd-manager/src/logger.cpp']
+
+wait_vpd_parser_exe = executable(
+ 'wait-vpd-parser',
+ sources,
+ include_directories: ['../', '../vpd-manager/include'],
+ dependencies: dependency_list,
+ install: true,
+)
diff --git a/wait-vpd-parser/src/wait_vpd_parser.cpp b/wait-vpd-parser/src/wait_vpd_parser.cpp
new file mode 100644
index 0000000..56128f3
--- /dev/null
+++ b/wait-vpd-parser/src/wait_vpd_parser.cpp
@@ -0,0 +1,91 @@
+#include "config.h"
+
+#include "constants.hpp"
+#include "logger.hpp"
+#include "utility/dbus_utility.hpp"
+
+#include <CLI/CLI.hpp>
+
+#include <chrono>
+#include <thread>
+
+/**
+ * @brief API to check for VPD collection status
+ *
+ * This API checks for VPD manager collection status by reading the
+ * "CollectionStatus" property exposed by vpd-manager on Dbus. The read logic
+ * uses a retry loop with a specific number of retries with specific sleep time
+ * between each retry.
+ *
+ * @param[in] i_retryLimit - Maximum number of retries
+ * @param[in] i_sleepDurationInSeconds - Sleep time in seconds between each
+ * retry
+ *
+ * @return If "CollectionStatus" property is "Completed", returns 0, otherwise
+ * returns 1.
+ */
+int checkVpdCollectionStatus(const unsigned i_retryLimit,
+ const unsigned i_sleepDurationInSeconds) noexcept
+{
+ auto l_logger = vpd::Logger::getLoggerInstance();
+
+ try
+ {
+ l_logger->logMessage(
+ "Checking every " + std::to_string(i_sleepDurationInSeconds) +
+ "s for VPD collection status ....");
+
+ for (unsigned l_retries = i_retryLimit;
+ l_retries != vpd::constants::VALUE_0; --l_retries)
+ {
+ // check at specified time interval
+ std::this_thread::sleep_for(
+ std::chrono::seconds(i_sleepDurationInSeconds));
+
+ // TODO: revisit this once "CollectionStatus" property is moved to
+ // xyz interface
+ const auto l_propValue = vpd::dbusUtility::readDbusProperty(
+ IFACE, OBJPATH, IFACE, "CollectionStatus");
+
+ if (auto l_val = std::get_if<std::string>(&l_propValue))
+ {
+ if (*l_val == "Completed")
+ {
+ l_logger->logMessage("VPD collection is completed");
+ return vpd::constants::VALUE_0;
+ }
+ }
+
+ l_logger->logMessage(
+ "Waiting for VPD status update. Retries remaining: " +
+ std::to_string(l_retries));
+ }
+
+ l_logger->logMessage(
+ "Exit wait for VPD services to finish with timeout");
+ }
+ catch (const std::exception& l_ex)
+ {
+ l_logger->logMessage("Error while checking VPD collection status: " +
+ std::string(l_ex.what()));
+ }
+
+ return vpd::constants::VALUE_1;
+}
+
+int main(int argc, char** argv)
+{
+ CLI::App l_app{"Wait VPD parser app"};
+
+ // 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");
+
+ CLI11_PARSE(l_app, argc, argv);
+
+ return checkVpdCollectionStatus(l_retryLimit, l_sleepDurationInSeconds);
+}