#pragma once #include "error_codes.hpp" #include "event_logger.hpp" #include "exceptions.hpp" #include "logger.hpp" #include "types.hpp" #include #include #include #include #include #include #include namespace vpd { namespace jsonUtility { // forward declaration of API for function map. bool processSystemCmdTag( const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, const std::string& i_baseAction, const std::string& i_flagToProcess, uint16_t& o_errCode); // forward declaration of API for function map. bool processGpioPresenceTag( const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, const std::string& i_baseAction, const std::string& i_flagToProcess, uint16_t& o_errCode); // forward declaration of API for function map. bool procesSetGpioTag(const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, const std::string& i_baseAction, const std::string& i_flagToProcess, uint16_t& o_errCode); // Function pointers to process tags from config JSON. typedef bool (*functionPtr)( const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, const std::string& i_baseAction, const std::string& i_flagToProcess, uint16_t& o_errCode); inline std::unordered_map funcionMap{ {"gpioPresence", processGpioPresenceTag}, {"setGpio", procesSetGpioTag}, {"systemCmd", processSystemCmdTag}}; /** * @brief API to read VPD offset from JSON file. * * @param[in] i_sysCfgJsonObj - Parsed system config JSON object. * @param[in] i_vpdFilePath - VPD file path. * @param[in] o_errCode - To set error code in case of error. * @return VPD offset if found in JSON, 0 otherwise. */ inline size_t getVPDOffset(const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdFilePath, uint16_t& o_errCode) { if (i_vpdFilePath.empty() || (i_sysCfgJsonObj.empty()) || (!i_sysCfgJsonObj.contains("frus"))) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return 0; } if (i_sysCfgJsonObj["frus"].contains(i_vpdFilePath)) { return i_sysCfgJsonObj["frus"][i_vpdFilePath].at(0).value("offset", 0); } const nlohmann::json& l_fruList = i_sysCfgJsonObj["frus"].get_ref(); for (const auto& l_fru : l_fruList.items()) { const auto l_fruPath = l_fru.key(); // check if given path is redundant FRU path if (i_vpdFilePath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value( "redundantEeprom", "")) { // Return the offset of redundant EEPROM taken from JSON. return i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("offset", 0); } } return 0; } /** * @brief API to parse respective JSON. * * @param[in] pathToJson - Path to JSON. * @param[out] o_errCode - To set error code in case of error. * @return on success parsed JSON. On failure empty JSON object. * * Note: Caller has to handle it in case an empty JSON object is received. */ inline nlohmann::json getParsedJson(const std::string& pathToJson, uint16_t& o_errCode) noexcept { if (pathToJson.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return nlohmann::json{}; } if (!std::filesystem::exists(pathToJson)) { o_errCode = error_code::FILE_NOT_FOUND; return nlohmann::json{}; } if (std::filesystem::is_empty(pathToJson)) { o_errCode = error_code::EMPTY_FILE; return nlohmann::json{}; } std::ifstream l_jsonFile(pathToJson); if (!l_jsonFile) { o_errCode = error_code::FILE_ACCESS_ERROR; return nlohmann::json{}; } try { return nlohmann::json::parse(l_jsonFile); } catch (const std::exception& l_ex) { o_errCode = error_code::JSON_PARSE_ERROR; return nlohmann::json{}; } } /** * @brief Get inventory object path from system config JSON. * * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path, * this API returns D-bus inventory path if present in JSON. * * @param[in] i_sysCfgJsonObj - System config JSON object * @param[in] i_vpdPath - Path to where VPD is stored. * @param[in] o_errCode - To set error code in case of error. * * @return On success a valid path is returned, on failure an empty string is * returned. * * Note: Caller has to handle it in case an empty string is received. */ inline std::string getInventoryObjPathFromJson( const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath, uint16_t& o_errCode) noexcept { if (i_vpdPath.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return std::string{}; } if (!i_sysCfgJsonObj.contains("frus")) { o_errCode = error_code::INVALID_JSON; return std::string{}; } // check if given path is FRU path if (i_sysCfgJsonObj["frus"].contains(i_vpdPath)) { return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value( "inventoryPath", ""); } const nlohmann::json& l_fruList = i_sysCfgJsonObj["frus"].get_ref(); for (const auto& l_fru : l_fruList.items()) { const auto l_fruPath = l_fru.key(); const auto l_invObjPath = i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath", ""); // check if given path is redundant FRU path or inventory path if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value( "redundantEeprom", "") || (i_vpdPath == l_invObjPath)) { return l_invObjPath; } } return std::string{}; } /** * @brief Process "PostFailAction" defined in config JSON. * * In case there is some error in the processing of "preAction" execution and a * set of procedure needs to be done as a part of post fail action. This base * action can be defined in the config JSON for that FRU and it will be handled * under this API. * * @param[in] i_parsedConfigJson - config JSON * @param[in] i_vpdFilePath - EEPROM file path * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed * @param[out] o_errCode - To set error code in case of error * under PostFailAction tag of config JSON. * @return - success or failure */ inline bool executePostFailAction( const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, const std::string& i_flagToProcess, uint16_t& o_errCode) { if (i_parsedConfigJson.empty() || i_vpdFilePath.empty() || i_flagToProcess.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return false; } if (!i_parsedConfigJson.contains("frus")) { o_errCode = error_code::INVALID_JSON; return false; } if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath)) { o_errCode = error_code::FRU_PATH_NOT_FOUND; return false; } if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains( "postFailAction")) { o_errCode = error_code::MISSING_ACTION_TAG; return false; } if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))["postFailAction"] .contains(i_flagToProcess)) { o_errCode = error_code::MISSING_FLAG; return false; } for (const auto& l_tags : (i_parsedConfigJson["frus"][i_vpdFilePath].at( 0))["postFailAction"][i_flagToProcess] .items()) { auto itrToFunction = funcionMap.find(l_tags.key()); if (itrToFunction != funcionMap.end()) { if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath, "postFailAction", i_flagToProcess, o_errCode)) { if (o_errCode) { logging::logMessage( l_tags.key() + " failed for [" + i_vpdFilePath + "]. Reason " + vpdSpecificUtility::getErrCodeMsg(o_errCode)); } return false; } } } return true; } /** * @brief Process "systemCmd" tag for a given FRU. * * The API will process "systemCmd" tag if it is defined in the config * JSON for the given FRU. * * @param[in] i_parsedConfigJson - config JSON * @param[in] i_vpdFilePath - EEPROM file path * @param[in] i_baseAction - Base action for which this tag has been called. * @param[in] i_flagToProcess - Flag nested under the base action for which this * tag has been called. * @param[out] o_errCode - To set error code in case of error. * @return Execution status. */ inline bool processSystemCmdTag( const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, const std::string& i_baseAction, const std::string& i_flagToProcess, uint16_t& o_errCode) { if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() || i_baseAction.empty() || i_flagToProcess.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return false; } try { if (!((i_parsedConfigJson["frus"][i_vpdFilePath].at( 0)[i_baseAction][i_flagToProcess]["systemCmd"]) .contains("cmd"))) { o_errCode = error_code::MISSING_FLAG; return false; } const std::string& l_systemCommand = i_parsedConfigJson["frus"][i_vpdFilePath].at( 0)[i_baseAction][i_flagToProcess]["systemCmd"]["cmd"]; commonUtility::executeCmd(l_systemCommand); } catch (const std::exception& l_ex) { o_errCode = error_code::ERROR_PROCESSING_SYSTEM_CMD; return false; } return true; } /** * @brief Checks for presence of a given FRU using GPIO line. * * This API returns the presence information of the FRU corresponding to the * given VPD file path by setting the presence pin. * * @param[in] i_parsedConfigJson - config JSON * @param[in] i_vpdFilePath - EEPROM file path * @param[in] i_baseAction - Base action for which this tag has been called. * @param[in] i_flagToProcess - Flag nested under the base action for which this * tag has been called. * @param[out] o_errCode - To set error code in case of error * @return Execution status. */ inline bool processGpioPresenceTag( const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, const std::string& i_baseAction, const std::string& i_flagToProcess, uint16_t& o_errCode) { std::string l_presencePinName; try { if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() || i_baseAction.empty() || i_flagToProcess.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return false; } if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at( 0)[i_baseAction][i_flagToProcess]["gpioPresence"]) .contains("pin")) && ((i_parsedConfigJson["frus"][i_vpdFilePath].at( 0)[i_baseAction][i_flagToProcess]["gpioPresence"]) .contains("value")))) { o_errCode = error_code::JSON_MISSING_GPIO_INFO; return false; } // get the pin name l_presencePinName = i_parsedConfigJson["frus"][i_vpdFilePath].at( 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["pin"]; // get the pin value uint8_t l_presencePinValue = i_parsedConfigJson["frus"][i_vpdFilePath].at( 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["value"]; gpiod::line l_presenceLine = gpiod::find_line(l_presencePinName); if (!l_presenceLine) { o_errCode = error_code::DEVICE_PRESENCE_UNKNOWN; throw GpioException("Couldn't find the GPIO line."); } l_presenceLine.request({"Read the presence line", gpiod::line_request::DIRECTION_INPUT, 0}); if (l_presencePinValue != l_presenceLine.get_value()) { // As false is being returned in this case, caller needs to know // that it is not due to some exception. It is because the pin was // read correctly but was not having expected value. o_errCode = error_code::DEVICE_NOT_PRESENT; return false; } return true; } catch (const std::exception& l_ex) { std::string l_errMsg = "Exception on GPIO line: "; l_errMsg += l_presencePinName; l_errMsg += " Reason: "; l_errMsg += l_ex.what(); l_errMsg += " File: " + i_vpdFilePath + " Pel Logged"; uint16_t l_errCode = 0; // ToDo -- Update Internal Rc code. EventLogger::createAsyncPelWithInventoryCallout( EventLogger::getErrorType(l_ex), types::SeverityType::Informational, {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath, l_errCode), types::CalloutPriority::High}}, std::source_location::current().file_name(), std::source_location::current().function_name(), 0, l_errMsg, std::nullopt, std::nullopt, std::nullopt, std::nullopt); logging::logMessage(l_errMsg); // Except when GPIO pin value is false, we go and try collecting the // FRU VPD as we couldn't able to read GPIO pin value due to some // error/exception. So returning true in error scenario. return true; } } /** * @brief Process "setGpio" tag for a given FRU. * * This API enables the GPIO line. * * @param[in] i_parsedConfigJson - config JSON * @param[in] i_vpdFilePath - EEPROM file path * @param[in] i_baseAction - Base action for which this tag has been called. * @param[in] i_flagToProcess - Flag nested under the base action for which this * tag has been called. * @param[out] o_errCode - To set error code in case of error * @return Execution status. */ inline bool procesSetGpioTag( const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, const std::string& i_baseAction, const std::string& i_flagToProcess, uint16_t& o_errCode) { std::string l_pinName; try { if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() || i_baseAction.empty() || i_flagToProcess.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return false; } if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at( 0)[i_baseAction][i_flagToProcess]["setGpio"]) .contains("pin")) && ((i_parsedConfigJson["frus"][i_vpdFilePath].at( 0)[i_baseAction][i_flagToProcess]["setGpio"]) .contains("value")))) { o_errCode = error_code::JSON_MISSING_GPIO_INFO; return false; } l_pinName = i_parsedConfigJson["frus"][i_vpdFilePath].at( 0)[i_baseAction][i_flagToProcess]["setGpio"]["pin"]; // Get the value to set uint8_t l_pinValue = i_parsedConfigJson["frus"][i_vpdFilePath].at( 0)[i_baseAction][i_flagToProcess]["setGpio"]["value"]; logging::logMessage( "Setting GPIO: " + l_pinName + " to " + std::to_string(l_pinValue)); gpiod::line l_outputLine = gpiod::find_line(l_pinName); if (!l_outputLine) { o_errCode = error_code::GPIO_LINE_EXCEPTION; throw GpioException("Couldn't find GPIO line."); } l_outputLine.request( {"FRU Action", ::gpiod::line_request::DIRECTION_OUTPUT, 0}, l_pinValue); return true; } catch (const std::exception& l_ex) { std::string l_errMsg = "Exception on GPIO line: "; l_errMsg += l_pinName; l_errMsg += " Reason: "; l_errMsg += l_ex.what(); l_errMsg += " File: " + i_vpdFilePath + " Pel Logged"; uint16_t l_errCode = 0; // ToDo -- Update Internal RC code EventLogger::createAsyncPelWithInventoryCallout( EventLogger::getErrorType(l_ex), types::SeverityType::Informational, {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath, l_errCode), types::CalloutPriority::High}}, std::source_location::current().file_name(), std::source_location::current().function_name(), 0, l_errMsg, std::nullopt, std::nullopt, std::nullopt, std::nullopt); logging::logMessage(l_errMsg); return false; } } /** * @brief Process any action, if defined in config JSON. * * If any FRU(s) requires any special handling, then this base action can be * defined for that FRU in the config JSON, processing of which will be handled * in this API. * Examples of action - preAction, PostAction etc. * * @param[in] i_parsedConfigJson - config JSON * @param[in] i_action - Base action to be performed. * @param[in] i_vpdFilePath - EEPROM file path * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed * under PreAction tag of config JSON. * @param[out] o_errCode - To set error code in case of error. * @return - success or failure */ inline bool executeBaseAction( const nlohmann::json& i_parsedConfigJson, const std::string& i_action, const std::string& i_vpdFilePath, const std::string& i_flagToProcess, uint16_t& o_errCode) { if (i_flagToProcess.empty() || i_action.empty() || i_vpdFilePath.empty() || !i_parsedConfigJson.contains("frus")) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return false; } if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath)) { o_errCode = error_code::FILE_NOT_FOUND; return false; } if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains(i_action)) { o_errCode = error_code::MISSING_ACTION_TAG; return false; } if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))[i_action].contains( i_flagToProcess)) { o_errCode = error_code::MISSING_FLAG; return false; } const nlohmann::json& l_tagsJson = (i_parsedConfigJson["frus"][i_vpdFilePath].at( 0))[i_action][i_flagToProcess]; for (const auto& l_tag : l_tagsJson.items()) { auto itrToFunction = funcionMap.find(l_tag.key()); if (itrToFunction != funcionMap.end()) { if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath, i_action, i_flagToProcess, o_errCode)) { // In case any of the tag fails to execute. Mark action // as failed for that flag. if (o_errCode) { logging::logMessage( l_tag.key() + " failed for [" + i_vpdFilePath + "]. Reason " + vpdSpecificUtility::getErrCodeMsg(o_errCode)); } return false; } } } return true; } /** * @brief Get redundant FRU path from system config JSON * * Given either D-bus inventory path/FRU path/redundant FRU path, this * API returns the redundant FRU path taken from "redundantEeprom" tag from * system config JSON. * * @param[in] i_sysCfgJsonObj - System config JSON object. * @param[in] i_vpdPath - Path to where VPD is stored. * @param[out] o_errCode - To set error code in case of error. * * @return On success return valid path, on failure return empty string. */ inline std::string getRedundantEepromPathFromJson( const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath, uint16_t& o_errCode) { if (i_vpdPath.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return std::string{}; } if (!i_sysCfgJsonObj.contains("frus")) { o_errCode = error_code::INVALID_JSON; return std::string{}; } // check if given path is FRU path if (i_sysCfgJsonObj["frus"].contains(i_vpdPath)) { return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value( "redundantEeprom", ""); } const nlohmann::json& l_fruList = i_sysCfgJsonObj["frus"].get_ref(); for (const auto& l_fru : l_fruList.items()) { const std::string& l_fruPath = l_fru.key(); const std::string& l_redundantFruPath = i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("redundantEeprom", ""); // check if given path is inventory path or redundant FRU path if ((i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath", "") == i_vpdPath) || (l_redundantFruPath == i_vpdPath)) { return l_redundantFruPath; } } return std::string(); } /** * @brief Get FRU EEPROM path from system config JSON * * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path, * this API returns FRU EEPROM path if present in JSON. * * @param[in] i_sysCfgJsonObj - System config JSON object * @param[in] i_vpdPath - Path to where VPD is stored. * @param[out] o_errCode - To set error code in case of error. * * @return On success return valid path, on failure return empty string. */ inline std::string getFruPathFromJson(const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath, uint16_t& o_errCode) { if (i_vpdPath.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return std::string{}; } if (!i_sysCfgJsonObj.contains("frus")) { o_errCode = error_code::INVALID_JSON; return std::string{}; } // check if given path is FRU path if (i_sysCfgJsonObj["frus"].contains(i_vpdPath)) { return i_vpdPath; } const nlohmann::json& l_fruList = i_sysCfgJsonObj["frus"].get_ref(); for (const auto& l_fru : l_fruList.items()) { const auto l_fruPath = l_fru.key(); // check if given path is redundant FRU path or inventory path if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value( "redundantEeprom", "") || (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value( "inventoryPath", ""))) { return l_fruPath; } } return std::string(); } /** * @brief An API to check backup and restore VPD is required. * * The API checks if there is provision for backup and restore mentioned in the * system config JSON, by looking "backupRestoreConfigPath" tag. * Checks if the path mentioned is a hardware path, by checking if the file path * exists and size of contents in the path. * * @param[in] i_sysCfgJsonObj - System config JSON object. * @param[out] o_errCode - To set error code in case of error. * * @return true if backup and restore is required, false otherwise. */ inline bool isBackupAndRestoreRequired(const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode) { if (i_sysCfgJsonObj.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return false; } const std::string& l_backupAndRestoreCfgFilePath = i_sysCfgJsonObj.value("backupRestoreConfigPath", ""); if (!l_backupAndRestoreCfgFilePath.empty() && std::filesystem::exists(l_backupAndRestoreCfgFilePath) && !std::filesystem::is_empty(l_backupAndRestoreCfgFilePath)) { return true; } return false; } /** @brief API to check if an action is required for given EEPROM path. * * System config JSON can contain pre-action, post-action etc. like actions * defined for an EEPROM path. The API will check if any such action is defined * for the EEPROM. * * @param[in] i_sysCfgJsonObj - System config JSON object. * @param[in] i_vpdFruPath - EEPROM path. * @param[in] i_action - Action to be checked. * @param[in] i_flowFlag - Denotes the flow w.r.t which the action should be * triggered. * @param[out] o_errCode - To set error code in case of error. * @return - True if action is defined for the flow, false otherwise. */ inline bool isActionRequired(const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdFruPath, const std::string& i_action, const std::string& i_flowFlag, uint16_t& o_errCode) { if (i_vpdFruPath.empty() || i_action.empty() || i_flowFlag.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return false; } if (!i_sysCfgJsonObj.contains("frus")) { o_errCode = error_code::INVALID_JSON; return false; } if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath)) { o_errCode = error_code::FRU_PATH_NOT_FOUND; return false; } if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)).contains(i_action)) { if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))[i_action].contains( i_flowFlag)) { return true; } } return false; } /** * @brief An API to return list of FRUs that needs GPIO polling. * * An API that checks for the FRUs that requires GPIO polling and returns * a list of FRUs that needs polling. Returns an empty list if there are * no FRUs that requires polling. * * @param[in] i_sysCfgJsonObj - System config JSON object. * @param[out] o_errCode - To set error codes in case of error. * * @return On success list of FRUs parameters that needs polling. On failure, * empty list. */ inline std::vector getListOfGpioPollingFrus( const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode) { std::vector l_gpioPollingRequiredFrusList; if (i_sysCfgJsonObj.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return l_gpioPollingRequiredFrusList; } if (!i_sysCfgJsonObj.contains("frus")) { o_errCode = error_code::INVALID_JSON; return l_gpioPollingRequiredFrusList; } for (const auto& l_fru : i_sysCfgJsonObj["frus"].items()) { const auto l_fruPath = l_fru.key(); bool l_isHotPluggableFru = isActionRequired(i_sysCfgJsonObj, l_fruPath, "pollingRequired", "hotPlugging", o_errCode); if (o_errCode) { logging::logMessage( "Error while checking if action required for FRU [" + std::string(l_fruPath) + "], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode)); return l_gpioPollingRequiredFrusList; } if (l_isHotPluggableFru) { if (i_sysCfgJsonObj["frus"][l_fruPath] .at(0)["pollingRequired"]["hotPlugging"] .contains("gpioPresence")) { l_gpioPollingRequiredFrusList.push_back(l_fruPath); } } } return l_gpioPollingRequiredFrusList; } /** * @brief Get all related path(s) to update keyword value. * * Given FRU EEPROM path/Inventory path needs keyword's value update, this API * returns tuple of FRU EEPROM path, inventory path and redundant EEPROM path if * exists in the system config JSON. * * Note: If the inventory object path or redundant EEPROM path(s) are not found * in the system config JSON, corresponding fields will have empty value in the * returning tuple. * * @param[in] i_sysCfgJsonObj - System config JSON object. * @param[in,out] io_vpdPath - Inventory object path or FRU EEPROM path. * @param[out] o_errCode - To set error code in case of error. * * @return On success returns tuple of EEPROM path, inventory path & redundant * path, on failure returns tuple with given input path alone. */ inline std::tuple getAllPathsToUpdateKeyword(const nlohmann::json& i_sysCfgJsonObj, std::string io_vpdPath, uint16_t& o_errCode) { types::Path l_inventoryObjPath; types::Path l_redundantFruPath; o_errCode = 0; if (i_sysCfgJsonObj.empty() || io_vpdPath.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath); } // Get hardware path from system config JSON. const types::Path l_fruPath = jsonUtility::getFruPathFromJson(i_sysCfgJsonObj, io_vpdPath, o_errCode); if (!l_fruPath.empty()) { io_vpdPath = l_fruPath; // Get inventory object path from system config JSON l_inventoryObjPath = jsonUtility::getInventoryObjPathFromJson( i_sysCfgJsonObj, l_fruPath, o_errCode); if (l_inventoryObjPath.empty()) { if (o_errCode) { logging::logMessage( "Failed to get inventory path from JSON for [" + io_vpdPath + "], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode)); } else { o_errCode = error_code::FRU_PATH_NOT_FOUND; } return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath); } // Get redundant hardware path if present in system config JSON l_redundantFruPath = jsonUtility::getRedundantEepromPathFromJson( i_sysCfgJsonObj, l_fruPath, o_errCode); if (l_redundantFruPath.empty()) { if (o_errCode) { logging::logMessage( "Failed to get redundant EEPROM path for FRU [" + l_fruPath + "], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode)); o_errCode = error_code::ERROR_GETTING_REDUNDANT_PATH; } else { o_errCode = error_code::REDUNDANT_PATH_NOT_FOUND; } return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath); } } else if (o_errCode) { logging::logMessage( "Failed to get FRU path from JSON for [" + io_vpdPath + "], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode)); } else { o_errCode = error_code::NO_EEPROM_PATH; } return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath); } /** * @brief An API to get DBus service name. * * Given DBus inventory path, this API returns DBus service name if present in * the JSON. * * @param[in] i_sysCfgJsonObj - System config JSON object. * @param[in] l_inventoryPath - DBus inventory path. * @param[out] o_errCode - To set error code in case of error. * * @return On success returns the service name present in the system config * JSON, otherwise empty string. * * Note: Caller has to handle in case of empty string received. */ inline std::string getServiceName(const nlohmann::json& i_sysCfgJsonObj, const std::string& l_inventoryPath, uint16_t& o_errCode) { if (l_inventoryPath.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return std::string{}; } if (!i_sysCfgJsonObj.contains("frus")) { o_errCode = error_code::INVALID_JSON; return std::string{}; } const nlohmann::json& l_listOfFrus = i_sysCfgJsonObj["frus"].get_ref(); for (const auto& l_frus : l_listOfFrus.items()) { for (const auto& l_inventoryItem : l_frus.value()) { if (l_inventoryPath.compare(l_inventoryItem["inventoryPath"]) == constants::STR_CMP_SUCCESS) { if (l_inventoryItem.contains("serviceName")) { return l_inventoryItem.value("serviceName", ""); } o_errCode = error_code::JSON_MISSING_SERVICE_NAME; return std::string{}; } } } o_errCode = error_code::FRU_PATH_NOT_FOUND; return std::string{}; } /** * @brief An API to check if a FRU is tagged as "powerOffOnly" * * Given the system config JSON and VPD FRU path, this API checks if the FRU * VPD can be collected at Chassis Power Off state only. * * @param[in] i_sysCfgJsonObj - System config JSON object. * @param[in] i_vpdFruPath - EEPROM path. * @param[out] o_errCode - To set error code for the error. * @return - True if FRU VPD can be collected at Chassis Power Off state only. * False otherwise */ inline bool isFruPowerOffOnly(const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdFruPath, uint16_t& o_errCode) { if (i_vpdFruPath.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return false; } if (!i_sysCfgJsonObj.contains("frus")) { o_errCode = error_code::INVALID_JSON; return false; } if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath)) { o_errCode = error_code::FRU_PATH_NOT_FOUND; return false; } return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)) .contains("powerOffOnly") && (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["powerOffOnly"])); } /** * @brief API which tells if the FRU is replaceable at runtime * * @param[in] i_sysCfgJsonObj - System config JSON object. * @param[in] i_vpdFruPath - EEPROM path. * @param[out] o_errCode - to set error code in case of error. * * @return true if FRU is replaceable at runtime. false otherwise. */ inline bool isFruReplaceableAtRuntime(const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdFruPath, uint16_t& o_errCode) { if (i_vpdFruPath.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return false; } if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus"))) { o_errCode = error_code::INVALID_JSON; return false; } if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath)) { o_errCode = error_code::FRU_PATH_NOT_FOUND; return false; } return ( (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)) .contains("replaceableAtRuntime") && (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtRuntime"])); return false; } /** * @brief API which tells if the FRU is replaceable at standby * * @param[in] i_sysCfgJsonObj - System config JSON object. * @param[in] i_vpdFruPath - EEPROM path. * @param[out] o_errCode - set error code in case of error. * * @return true if FRU is replaceable at standby. false otherwise. */ inline bool isFruReplaceableAtStandby(const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdFruPath, uint16_t& o_errCode) { if (i_vpdFruPath.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return false; } if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus"))) { o_errCode = error_code::INVALID_JSON; return false; } if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath)) { o_errCode = error_code::FRU_PATH_NOT_FOUND; return false; } return ( (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)) .contains("replaceableAtStandby") && (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtStandby"])); return false; } /** * @brief API to get list of FRUs replaceable at standby from JSON. * * The API will return a vector of FRUs inventory path which are replaceable at * standby. * * @param[in] i_sysCfgJsonObj - System config JSON object. * @param[out] o_errCode - To set error code in case of error. * * @return - On success, list of FRUs replaceable at standby. On failure, empty * vector. */ inline std::vector getListOfFrusReplaceableAtStandby( const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode) { std::vector l_frusReplaceableAtStandby; if (!i_sysCfgJsonObj.contains("frus")) { o_errCode = error_code::INVALID_JSON; return l_frusReplaceableAtStandby; } const nlohmann::json& l_fruList = i_sysCfgJsonObj["frus"].get_ref(); for (const auto& l_fru : l_fruList.items()) { if (i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value( "replaceableAtStandby", false)) { const std::string& l_inventoryObjectPath = i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value( "inventoryPath", ""); if (!l_inventoryObjectPath.empty()) { l_frusReplaceableAtStandby.emplace_back(l_inventoryObjectPath); } } } return l_frusReplaceableAtStandby; } /** * @brief API to select powerVS JSON based on system IM. * * The API selects respective JSON based on system IM, parse it and return the * JSON object. Empty JSON will be returned in case of any error. Caller needs * to handle empty value. * * @param[in] i_imValue - IM value of the system. * @param[out] o_errCode - to set error code in case of error. * @return Parsed JSON object, empty JSON otherwise. */ inline nlohmann::json getPowerVsJson(const types::BinaryVector& i_imValue, uint16_t& o_errCode) { if (i_imValue.empty() || i_imValue.size() < 4) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return nlohmann::json{}; } o_errCode = 0; if ((i_imValue.at(0) == constants::HEX_VALUE_50) && (i_imValue.at(1) == constants::HEX_VALUE_00) && (i_imValue.at(2) == constants::HEX_VALUE_30)) { nlohmann::json l_parsedJson = jsonUtility::getParsedJson( constants::power_vs_50003_json, o_errCode); if (o_errCode) { logging::logMessage( "Failed to parse JSON file [ " + std::string(constants::power_vs_50003_json) + " ], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode)); } return l_parsedJson; } else if (i_imValue.at(0) == constants::HEX_VALUE_50 && (i_imValue.at(1) == constants::HEX_VALUE_00) && (i_imValue.at(2) == constants::HEX_VALUE_10)) { nlohmann::json l_parsedJson = jsonUtility::getParsedJson( constants::power_vs_50001_json, o_errCode); if (o_errCode) { logging::logMessage( "Failed to parse JSON file [ " + std::string(constants::power_vs_50001_json) + " ], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode)); } return l_parsedJson; } return nlohmann::json{}; } /** * @brief API to get list of FRUs for which "monitorPresence" is true. * * @param[in] i_sysCfgJsonObj - System config JSON object. * @param[out] o_errCode - To set error code in case of error. * * @return On success, returns list of FRUs for which "monitorPresence" is true, * empty list on error. */ inline std::vector getFrusWithPresenceMonitoring( const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode) { std::vector l_frusWithPresenceMonitoring; if (!i_sysCfgJsonObj.contains("frus")) { o_errCode = error_code::INVALID_JSON; return l_frusWithPresenceMonitoring; } const nlohmann::json& l_listOfFrus = i_sysCfgJsonObj["frus"].get_ref(); for (const auto& l_aFru : l_listOfFrus) { if (l_aFru.at(0).value("monitorPresence", false)) { l_frusWithPresenceMonitoring.emplace_back( l_aFru.at(0).value("inventoryPath", "")); } } return l_frusWithPresenceMonitoring; } /** * @brief API which tells if the FRU's presence is handled * * For a given FRU, this API checks if it's presence is handled by vpd-manager * by checking the "handlePresence" tag. * * @param[in] i_sysCfgJsonObj - System config JSON object. * @param[in] i_vpdFruPath - EEPROM path. * @param[out] o_errCode - To set error code in case of failure. * * @return true if FRU presence is handled, false otherwise. */ inline bool isFruPresenceHandled(const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdFruPath, uint16_t& o_errCode) { if (i_vpdFruPath.empty()) { o_errCode = error_code::INVALID_INPUT_PARAMETER; return false; } if (!i_sysCfgJsonObj.contains("frus")) { o_errCode = error_code::INVALID_JSON; return false; } if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath)) { o_errCode = error_code::FRU_PATH_NOT_FOUND; return false; } return i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0).value( "handlePresence", true); } } // namespace jsonUtility } // namespace vpd