Revamped code for VPD parser
The commit removes all the pre-existing code from the branch
and pushes the revamped code.
Major modification includes:
- Movement from multi exe to single daemon model.
- Multithreaded approach to parse FRU VPD.
- Better error handling.
- Refactored code for performance optimization.
Note: This code supports all the existing functionalities as it is.
Change-Id: I1ddce1f0725ac59020b72709689a1013643bda8b
Signed-off-by: Sunny Srivastava <sunnsr25@in.ibm.com>
diff --git a/vpd-manager/src/parser.cpp b/vpd-manager/src/parser.cpp
new file mode 100644
index 0000000..d6266cb
--- /dev/null
+++ b/vpd-manager/src/parser.cpp
@@ -0,0 +1,342 @@
+#include "parser.hpp"
+
+#include "constants.hpp"
+#include "event_logger.hpp"
+
+#include <utility/dbus_utility.hpp>
+#include <utility/json_utility.hpp>
+#include <utility/vpd_specific_utility.hpp>
+
+#include <fstream>
+
+namespace vpd
+{
+Parser::Parser(const std::string& vpdFilePath, nlohmann::json parsedJson) :
+ m_vpdFilePath(vpdFilePath), m_parsedJson(parsedJson)
+{
+ std::error_code l_errCode;
+
+ // ToDo: Add minimum file size check in all the concert praser classes,
+ // depends on their VPD type.
+ if (!std::filesystem::exists(m_vpdFilePath, l_errCode))
+ {
+ std::string l_message{"Parser object creation failed, file [" +
+ m_vpdFilePath + "] doesn't exists."};
+
+ if (l_errCode)
+ {
+ l_message += " Error message: " + l_errCode.message();
+ }
+
+ throw std::runtime_error(l_message);
+ }
+
+ // Read VPD offset if applicable.
+ if (!m_parsedJson.empty())
+ {
+ m_vpdStartOffset = jsonUtility::getVPDOffset(m_parsedJson, vpdFilePath);
+ }
+}
+
+std::shared_ptr<vpd::ParserInterface> Parser::getVpdParserInstance()
+{
+ // Read the VPD data into a vector.
+ vpdSpecificUtility::getVpdDataInVector(m_vpdFilePath, m_vpdVector,
+ m_vpdStartOffset);
+
+ // This will detect the type of parser required.
+ std::shared_ptr<vpd::ParserInterface> l_parser =
+ ParserFactory::getParser(m_vpdVector, m_vpdFilePath, m_vpdStartOffset);
+
+ return l_parser;
+}
+
+types::VPDMapVariant Parser::parse()
+{
+ std::shared_ptr<vpd::ParserInterface> l_parser = getVpdParserInstance();
+ return l_parser->parse();
+}
+
+int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData)
+{
+ int l_bytesUpdatedOnHardware = constants::FAILURE;
+
+ // A lambda to extract Record : Keyword string from i_paramsToWriteData
+ auto l_keyWordIdentifier =
+ [](const types::WriteVpdParams& i_paramsToWriteData) -> std::string {
+ std::string l_keywordString{};
+ if (const types::IpzData* l_ipzData =
+ std::get_if<types::IpzData>(&i_paramsToWriteData))
+ {
+ l_keywordString =
+ std::get<0>(*l_ipzData) + ":" + std::get<1>(*l_ipzData);
+ }
+ else if (const types::KwData* l_kwData =
+ std::get_if<types::KwData>(&i_paramsToWriteData))
+ {
+ l_keywordString = std::get<0>(*l_kwData);
+ }
+ return l_keywordString;
+ };
+
+ try
+ {
+ // Enable Reboot Guard
+ if (constants::FAILURE == dbusUtility::EnableRebootGuard())
+ {
+ EventLogger::createAsyncPel(
+ types::ErrorType::DbusFailure,
+ types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
+ std::string(
+ "Failed to enable BMC Reboot Guard while updating " +
+ l_keyWordIdentifier(i_paramsToWriteData)),
+ std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+
+ return constants::FAILURE;
+ }
+
+ // Update keyword's value on hardware
+ try
+ {
+ std::shared_ptr<ParserInterface> l_vpdParserInstance =
+ getVpdParserInstance();
+ l_bytesUpdatedOnHardware =
+ l_vpdParserInstance->writeKeywordOnHardware(
+ i_paramsToWriteData);
+ }
+ catch (const std::exception& l_exception)
+ {
+ std::string l_errMsg(
+ "Error while updating keyword's value on hardware path " +
+ m_vpdFilePath + ", error: " + std::string(l_exception.what()));
+
+ // TODO : Log PEL
+
+ throw std::runtime_error(l_errMsg);
+ }
+
+ auto [l_fruPath, l_inventoryObjPath, l_redundantFruPath] =
+ jsonUtility::getAllPathsToUpdateKeyword(m_parsedJson,
+ m_vpdFilePath);
+
+ // If inventory D-bus object path is present, update keyword's value on
+ // DBus
+ if (!l_inventoryObjPath.empty())
+ {
+ types::Record l_recordName;
+ std::string l_interfaceName;
+ std::string l_propertyName;
+ types::DbusVariantType l_keywordValue;
+
+ if (const types::IpzData* l_ipzData =
+ std::get_if<types::IpzData>(&i_paramsToWriteData))
+ {
+ l_recordName = std::get<0>(*l_ipzData);
+ l_interfaceName = constants::ipzVpdInf + l_recordName;
+ l_propertyName = std::get<1>(*l_ipzData);
+
+ try
+ {
+ // Read keyword's value from hardware to write the same on
+ // D-bus.
+ std::shared_ptr<ParserInterface> l_vpdParserInstance =
+ getVpdParserInstance();
+
+ logging::logMessage(
+ "Performing VPD read on " + m_vpdFilePath);
+
+ l_keywordValue =
+ l_vpdParserInstance->readKeywordFromHardware(
+ types::ReadVpdParams(
+ std::make_tuple(l_recordName, l_propertyName)));
+ }
+ catch (const std::exception& l_exception)
+ {
+ // Unable to read keyword's value from hardware.
+ std::string l_errMsg(
+ "Error while reading keyword's value from hadware path " +
+ m_vpdFilePath +
+ ", error: " + std::string(l_exception.what()));
+
+ // TODO: Log PEL
+
+ throw std::runtime_error(l_errMsg);
+ }
+ }
+ else
+ {
+ // Input parameter type provided isn't compatible to perform
+ // update.
+ std::string l_errMsg(
+ "Input parameter type isn't compatible to update keyword's value on DBus for object path: " +
+ l_inventoryObjPath);
+ throw std::runtime_error(l_errMsg);
+ }
+
+ // Get D-bus name for the given keyword
+ l_propertyName =
+ vpdSpecificUtility::getDbusPropNameForGivenKw(l_propertyName);
+
+ // Create D-bus object map
+ types::ObjectMap l_dbusObjMap = {std::make_pair(
+ l_inventoryObjPath,
+ types::InterfaceMap{std::make_pair(
+ l_interfaceName, types::PropertyMap{std::make_pair(
+ l_propertyName, l_keywordValue)})})};
+
+ // Call PIM's Notify method to perform update
+ if (!dbusUtility::callPIM(std::move(l_dbusObjMap)))
+ {
+ // Call to PIM's Notify method failed.
+ std::string l_errMsg("Notify PIM is failed for object path: " +
+ l_inventoryObjPath);
+ throw std::runtime_error(l_errMsg);
+ }
+ }
+
+ // Update keyword's value on redundant hardware if present
+ if (!l_redundantFruPath.empty())
+ {
+ if (updateVpdKeywordOnRedundantPath(l_redundantFruPath,
+ i_paramsToWriteData) < 0)
+ {
+ std::string l_errMsg(
+ "Error while updating keyword's value on redundant path " +
+ l_redundantFruPath);
+ throw std::runtime_error(l_errMsg);
+ }
+ }
+
+ // TODO: Check if revert is required when any of the writes fails.
+ // TODO: Handle error logging
+ }
+ catch (const std::exception& l_ex)
+ {
+ logging::logMessage("Update VPD Keyword failed for : " +
+ l_keyWordIdentifier(i_paramsToWriteData) +
+ " failed due to error: " + l_ex.what());
+
+ // update failed, set return value to failure
+ l_bytesUpdatedOnHardware = constants::FAILURE;
+ }
+
+ // Disable Reboot Guard
+ if (constants::FAILURE == dbusUtility::DisableRebootGuard())
+ {
+ EventLogger::createAsyncPel(
+ types::ErrorType::DbusFailure, types::SeverityType::Critical,
+ __FILE__, __FUNCTION__, 0,
+ std::string("Failed to disable BMC Reboot Guard while updating " +
+ l_keyWordIdentifier(i_paramsToWriteData)),
+ std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+ }
+
+ return l_bytesUpdatedOnHardware;
+}
+
+int Parser::updateVpdKeywordOnRedundantPath(
+ const std::string& i_fruPath,
+ const types::WriteVpdParams& i_paramsToWriteData)
+{
+ try
+ {
+ std::shared_ptr<Parser> l_parserObj =
+ std::make_shared<Parser>(i_fruPath, m_parsedJson);
+
+ std::shared_ptr<ParserInterface> l_vpdParserInstance =
+ l_parserObj->getVpdParserInstance();
+
+ return l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
+ }
+ catch (const std::exception& l_exception)
+ {
+ EventLogger::createSyncPel(
+ types::ErrorType::InvalidVpdMessage,
+ types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
+ "Error while updating keyword's value on redundant path " +
+ i_fruPath + ", error: " + std::string(l_exception.what()),
+ std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+ return -1;
+ }
+}
+
+int Parser::updateVpdKeywordOnHardware(
+ const types::WriteVpdParams& i_paramsToWriteData)
+{
+ int l_bytesUpdatedOnHardware = constants::FAILURE;
+
+ // A lambda to extract Record : Keyword string from i_paramsToWriteData
+ auto l_keyWordIdentifier =
+ [](const types::WriteVpdParams& i_paramsToWriteData) -> std::string {
+ std::string l_keywordString{};
+ if (const types::IpzData* l_ipzData =
+ std::get_if<types::IpzData>(&i_paramsToWriteData))
+ {
+ l_keywordString =
+ std::get<0>(*l_ipzData) + ":" + std::get<1>(*l_ipzData);
+ }
+ else if (const types::KwData* l_kwData =
+ std::get_if<types::KwData>(&i_paramsToWriteData))
+ {
+ l_keywordString = std::get<0>(*l_kwData);
+ }
+ return l_keywordString;
+ };
+
+ try
+ {
+ // Enable Reboot Guard
+ if (constants::FAILURE == dbusUtility::EnableRebootGuard())
+ {
+ EventLogger::createAsyncPel(
+ types::ErrorType::DbusFailure,
+ types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
+ std::string(
+ "Failed to enable BMC Reboot Guard while updating " +
+ l_keyWordIdentifier(i_paramsToWriteData)),
+ std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+
+ return constants::FAILURE;
+ }
+
+ std::shared_ptr<ParserInterface> l_vpdParserInstance =
+ getVpdParserInstance();
+ l_bytesUpdatedOnHardware =
+ l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
+ }
+ catch (const std::exception& l_exception)
+ {
+ types::ErrorType l_errorType;
+
+ if (typeid(l_exception) == typeid(EccException))
+ {
+ l_errorType = types::ErrorType::EccCheckFailed;
+ }
+ else
+ {
+ l_errorType = types::ErrorType::InvalidVpdMessage;
+ }
+
+ EventLogger::createAsyncPel(
+ l_errorType, types::SeverityType::Informational, __FILE__,
+ __FUNCTION__, 0,
+ "Error while updating keyword's value on hardware path [" +
+ m_vpdFilePath + "], error: " + std::string(l_exception.what()),
+ std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+ }
+
+ // Disable Reboot Guard
+ if (constants::FAILURE == dbusUtility::DisableRebootGuard())
+ {
+ EventLogger::createAsyncPel(
+ types::ErrorType::DbusFailure, types::SeverityType::Critical,
+ __FILE__, __FUNCTION__, 0,
+ std::string("Failed to disable BMC Reboot Guard while updating " +
+ l_keyWordIdentifier(i_paramsToWriteData)),
+ std::nullopt, std::nullopt, std::nullopt, std::nullopt);
+ }
+
+ return l_bytesUpdatedOnHardware;
+}
+
+} // namespace vpd