1 #pragma once 2 3 #include "error_codes.hpp" 4 #include "event_logger.hpp" 5 #include "exceptions.hpp" 6 #include "logger.hpp" 7 #include "types.hpp" 8 9 #include <gpiod.hpp> 10 #include <nlohmann/json.hpp> 11 #include <utility/common_utility.hpp> 12 #include <utility/vpd_specific_utility.hpp> 13 14 #include <fstream> 15 #include <type_traits> 16 #include <unordered_map> 17 18 namespace vpd 19 { 20 namespace jsonUtility 21 { 22 23 // forward declaration of API for function map. 24 bool processSystemCmdTag( 25 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, 26 const std::string& i_baseAction, const std::string& i_flagToProcess, 27 uint16_t& o_errCode); 28 29 // forward declaration of API for function map. 30 bool processGpioPresenceTag( 31 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, 32 const std::string& i_baseAction, const std::string& i_flagToProcess, 33 uint16_t& o_errCode); 34 35 // forward declaration of API for function map. 36 bool procesSetGpioTag(const nlohmann::json& i_parsedConfigJson, 37 const std::string& i_vpdFilePath, 38 const std::string& i_baseAction, 39 const std::string& i_flagToProcess, uint16_t& o_errCode); 40 41 // Function pointers to process tags from config JSON. 42 typedef bool (*functionPtr)( 43 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, 44 const std::string& i_baseAction, const std::string& i_flagToProcess, 45 uint16_t& o_errCode); 46 47 inline std::unordered_map<std::string, functionPtr> funcionMap{ 48 {"gpioPresence", processGpioPresenceTag}, 49 {"setGpio", procesSetGpioTag}, 50 {"systemCmd", processSystemCmdTag}}; 51 52 /** 53 * @brief API to read VPD offset from JSON file. 54 * 55 * @param[in] i_sysCfgJsonObj - Parsed system config JSON object. 56 * @param[in] i_vpdFilePath - VPD file path. 57 * @param[in] o_errCode - To set error code in case of error. 58 * @return VPD offset if found in JSON, 0 otherwise. 59 */ 60 inline size_t getVPDOffset(const nlohmann::json& i_sysCfgJsonObj, 61 const std::string& i_vpdFilePath, 62 uint16_t& o_errCode) 63 { 64 if (i_vpdFilePath.empty() || (i_sysCfgJsonObj.empty()) || 65 (!i_sysCfgJsonObj.contains("frus"))) 66 { 67 o_errCode = error_code::INVALID_INPUT_PARAMETER; 68 return 0; 69 } 70 71 if (i_sysCfgJsonObj["frus"].contains(i_vpdFilePath)) 72 { 73 return i_sysCfgJsonObj["frus"][i_vpdFilePath].at(0).value("offset", 0); 74 } 75 76 const nlohmann::json& l_fruList = 77 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>(); 78 79 for (const auto& l_fru : l_fruList.items()) 80 { 81 const auto l_fruPath = l_fru.key(); 82 83 // check if given path is redundant FRU path 84 if (i_vpdFilePath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value( 85 "redundantEeprom", "")) 86 { 87 // Return the offset of redundant EEPROM taken from JSON. 88 return i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("offset", 0); 89 } 90 } 91 92 return 0; 93 } 94 95 /** 96 * @brief API to parse respective JSON. 97 * 98 * @param[in] pathToJson - Path to JSON. 99 * @param[out] o_errCode - To set error code in case of error. 100 * @return on success parsed JSON. On failure empty JSON object. 101 * 102 * Note: Caller has to handle it in case an empty JSON object is received. 103 */ 104 inline nlohmann::json getParsedJson(const std::string& pathToJson, 105 uint16_t& o_errCode) noexcept 106 { 107 if (pathToJson.empty()) 108 { 109 o_errCode = error_code::INVALID_INPUT_PARAMETER; 110 return nlohmann::json{}; 111 } 112 113 if (!std::filesystem::exists(pathToJson)) 114 { 115 o_errCode = error_code::FILE_NOT_FOUND; 116 return nlohmann::json{}; 117 } 118 119 if (std::filesystem::is_empty(pathToJson)) 120 { 121 o_errCode = error_code::EMPTY_FILE; 122 return nlohmann::json{}; 123 } 124 125 std::ifstream l_jsonFile(pathToJson); 126 if (!l_jsonFile) 127 { 128 o_errCode = error_code::FILE_ACCESS_ERROR; 129 return nlohmann::json{}; 130 } 131 132 try 133 { 134 return nlohmann::json::parse(l_jsonFile); 135 } 136 catch (const std::exception& l_ex) 137 { 138 o_errCode = error_code::JSON_PARSE_ERROR; 139 return nlohmann::json{}; 140 } 141 } 142 143 /** 144 * @brief Get inventory object path from system config JSON. 145 * 146 * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path, 147 * this API returns D-bus inventory path if present in JSON. 148 * 149 * @param[in] i_sysCfgJsonObj - System config JSON object 150 * @param[in] i_vpdPath - Path to where VPD is stored. 151 * @param[in] o_errCode - To set error code in case of error. 152 * 153 * @return On success a valid path is returned, on failure an empty string is 154 * returned. 155 * 156 * Note: Caller has to handle it in case an empty string is received. 157 */ 158 inline std::string getInventoryObjPathFromJson( 159 const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath, 160 uint16_t& o_errCode) noexcept 161 { 162 if (i_vpdPath.empty()) 163 { 164 o_errCode = error_code::INVALID_INPUT_PARAMETER; 165 return std::string{}; 166 } 167 168 if (!i_sysCfgJsonObj.contains("frus")) 169 { 170 o_errCode = error_code::INVALID_JSON; 171 return std::string{}; 172 } 173 174 // check if given path is FRU path 175 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath)) 176 { 177 return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value( 178 "inventoryPath", ""); 179 } 180 181 const nlohmann::json& l_fruList = 182 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>(); 183 184 for (const auto& l_fru : l_fruList.items()) 185 { 186 const auto l_fruPath = l_fru.key(); 187 const auto l_invObjPath = 188 i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath", ""); 189 190 // check if given path is redundant FRU path or inventory path 191 if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value( 192 "redundantEeprom", "") || 193 (i_vpdPath == l_invObjPath)) 194 { 195 return l_invObjPath; 196 } 197 } 198 199 return std::string{}; 200 } 201 202 /** 203 * @brief Process "PostFailAction" defined in config JSON. 204 * 205 * In case there is some error in the processing of "preAction" execution and a 206 * set of procedure needs to be done as a part of post fail action. This base 207 * action can be defined in the config JSON for that FRU and it will be handled 208 * under this API. 209 * 210 * @param[in] i_parsedConfigJson - config JSON 211 * @param[in] i_vpdFilePath - EEPROM file path 212 * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed 213 * @param[out] o_errCode - To set error code in case of error 214 * under PostFailAction tag of config JSON. 215 * @return - success or failure 216 */ 217 inline bool executePostFailAction( 218 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, 219 const std::string& i_flagToProcess, uint16_t& o_errCode) 220 { 221 if (i_parsedConfigJson.empty() || i_vpdFilePath.empty() || 222 i_flagToProcess.empty()) 223 { 224 o_errCode = error_code::INVALID_INPUT_PARAMETER; 225 return false; 226 } 227 228 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))["postFailAction"] 229 .contains(i_flagToProcess)) 230 { 231 o_errCode = error_code::MISSING_FLAG; 232 return false; 233 } 234 235 for (const auto& l_tags : (i_parsedConfigJson["frus"][i_vpdFilePath].at( 236 0))["postFailAction"][i_flagToProcess] 237 .items()) 238 { 239 auto itrToFunction = funcionMap.find(l_tags.key()); 240 if (itrToFunction != funcionMap.end()) 241 { 242 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath, 243 "postFailAction", i_flagToProcess, 244 o_errCode)) 245 { 246 if (o_errCode) 247 { 248 logging::logMessage( 249 l_tags.key() + " failed for [" + i_vpdFilePath + 250 "]. Reason " + 251 vpdSpecificUtility::getErrCodeMsg(o_errCode)); 252 } 253 return false; 254 } 255 } 256 } 257 258 return true; 259 } 260 261 /** 262 * @brief Process "systemCmd" tag for a given FRU. 263 * 264 * The API will process "systemCmd" tag if it is defined in the config 265 * JSON for the given FRU. 266 * 267 * @param[in] i_parsedConfigJson - config JSON 268 * @param[in] i_vpdFilePath - EEPROM file path 269 * @param[in] i_baseAction - Base action for which this tag has been called. 270 * @param[in] i_flagToProcess - Flag nested under the base action for which this 271 * tag has been called. 272 * @param[out] o_errCode - To set error code in case of error. 273 * @return Execution status. 274 */ 275 inline bool processSystemCmdTag( 276 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, 277 const std::string& i_baseAction, const std::string& i_flagToProcess, 278 uint16_t& o_errCode) 279 { 280 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() || 281 i_baseAction.empty() || i_flagToProcess.empty()) 282 { 283 o_errCode = error_code::INVALID_INPUT_PARAMETER; 284 return false; 285 } 286 287 if (!((i_parsedConfigJson["frus"][i_vpdFilePath].at( 288 0)[i_baseAction][i_flagToProcess]["systemCmd"]) 289 .contains("cmd"))) 290 { 291 o_errCode = error_code::MISSING_FLAG; 292 return false; 293 } 294 295 const std::string& l_systemCommand = 296 i_parsedConfigJson["frus"][i_vpdFilePath].at( 297 0)[i_baseAction][i_flagToProcess]["systemCmd"]["cmd"]; 298 299 commonUtility::executeCmd(l_systemCommand); 300 return true; 301 } 302 303 /** 304 * @brief Checks for presence of a given FRU using GPIO line. 305 * 306 * This API returns the presence information of the FRU corresponding to the 307 * given VPD file path by setting the presence pin. 308 * 309 * @param[in] i_parsedConfigJson - config JSON 310 * @param[in] i_vpdFilePath - EEPROM file path 311 * @param[in] i_baseAction - Base action for which this tag has been called. 312 * @param[in] i_flagToProcess - Flag nested under the base action for which this 313 * tag has been called. 314 * @param[out] o_errCode - To set error code in case of error 315 * @return Execution status. 316 */ 317 inline bool processGpioPresenceTag( 318 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, 319 const std::string& i_baseAction, const std::string& i_flagToProcess, 320 uint16_t& o_errCode) 321 { 322 std::string l_presencePinName; 323 try 324 { 325 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() || 326 i_baseAction.empty() || i_flagToProcess.empty()) 327 { 328 o_errCode = error_code::INVALID_INPUT_PARAMETER; 329 return false; 330 } 331 332 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at( 333 0)[i_baseAction][i_flagToProcess]["gpioPresence"]) 334 .contains("pin")) && 335 ((i_parsedConfigJson["frus"][i_vpdFilePath].at( 336 0)[i_baseAction][i_flagToProcess]["gpioPresence"]) 337 .contains("value")))) 338 { 339 o_errCode = error_code::JSON_MISSING_GPIO_INFO; 340 return false; 341 } 342 343 // get the pin name 344 l_presencePinName = i_parsedConfigJson["frus"][i_vpdFilePath].at( 345 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["pin"]; 346 347 // get the pin value 348 uint8_t l_presencePinValue = 349 i_parsedConfigJson["frus"][i_vpdFilePath].at( 350 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["value"]; 351 352 gpiod::line l_presenceLine = gpiod::find_line(l_presencePinName); 353 354 if (!l_presenceLine) 355 { 356 o_errCode = error_code::DEVICE_PRESENCE_UNKNOWN; 357 throw GpioException("Couldn't find the GPIO line."); 358 } 359 360 l_presenceLine.request({"Read the presence line", 361 gpiod::line_request::DIRECTION_INPUT, 0}); 362 363 if (l_presencePinValue != l_presenceLine.get_value()) 364 { 365 // As false is being returned in this case, caller needs to know 366 // that it is not due to some exception. It is because the pin was 367 // read correctly but was not having expected value. 368 o_errCode = error_code::DEVICE_NOT_PRESENT; 369 return false; 370 } 371 372 return true; 373 } 374 catch (const std::exception& l_ex) 375 { 376 std::string l_errMsg = "Exception on GPIO line: "; 377 l_errMsg += l_presencePinName; 378 l_errMsg += " Reason: "; 379 l_errMsg += l_ex.what(); 380 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged"; 381 382 uint16_t l_errCode = 0; 383 384 // ToDo -- Update Internal Rc code. 385 EventLogger::createAsyncPelWithInventoryCallout( 386 EventLogger::getErrorType(l_ex), types::SeverityType::Informational, 387 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath, 388 l_errCode), 389 types::CalloutPriority::High}}, 390 std::source_location::current().file_name(), 391 std::source_location::current().function_name(), 0, l_errMsg, 392 std::nullopt, std::nullopt, std::nullopt, std::nullopt); 393 394 logging::logMessage(l_errMsg); 395 396 // Except when GPIO pin value is false, we go and try collecting the 397 // FRU VPD as we couldn't able to read GPIO pin value due to some 398 // error/exception. So returning true in error scenario. 399 return true; 400 } 401 } 402 403 /** 404 * @brief Process "setGpio" tag for a given FRU. 405 * 406 * This API enables the GPIO line. 407 * 408 * @param[in] i_parsedConfigJson - config JSON 409 * @param[in] i_vpdFilePath - EEPROM file path 410 * @param[in] i_baseAction - Base action for which this tag has been called. 411 * @param[in] i_flagToProcess - Flag nested under the base action for which this 412 * tag has been called. 413 * @param[out] o_errCode - To set error code in case of error 414 * @return Execution status. 415 */ 416 inline bool procesSetGpioTag( 417 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath, 418 const std::string& i_baseAction, const std::string& i_flagToProcess, 419 uint16_t& o_errCode) 420 { 421 std::string l_pinName; 422 try 423 { 424 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() || 425 i_baseAction.empty() || i_flagToProcess.empty()) 426 { 427 o_errCode = error_code::INVALID_INPUT_PARAMETER; 428 return false; 429 } 430 431 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at( 432 0)[i_baseAction][i_flagToProcess]["setGpio"]) 433 .contains("pin")) && 434 ((i_parsedConfigJson["frus"][i_vpdFilePath].at( 435 0)[i_baseAction][i_flagToProcess]["setGpio"]) 436 .contains("value")))) 437 { 438 o_errCode = error_code::JSON_MISSING_GPIO_INFO; 439 return false; 440 } 441 442 l_pinName = i_parsedConfigJson["frus"][i_vpdFilePath].at( 443 0)[i_baseAction][i_flagToProcess]["setGpio"]["pin"]; 444 445 // Get the value to set 446 uint8_t l_pinValue = i_parsedConfigJson["frus"][i_vpdFilePath].at( 447 0)[i_baseAction][i_flagToProcess]["setGpio"]["value"]; 448 449 logging::logMessage( 450 "Setting GPIO: " + l_pinName + " to " + std::to_string(l_pinValue)); 451 452 gpiod::line l_outputLine = gpiod::find_line(l_pinName); 453 454 if (!l_outputLine) 455 { 456 o_errCode = error_code::GPIO_LINE_EXCEPTION; 457 throw GpioException("Couldn't find GPIO line."); 458 } 459 460 l_outputLine.request( 461 {"FRU Action", ::gpiod::line_request::DIRECTION_OUTPUT, 0}, 462 l_pinValue); 463 return true; 464 } 465 catch (const std::exception& l_ex) 466 { 467 std::string l_errMsg = "Exception on GPIO line: "; 468 l_errMsg += l_pinName; 469 l_errMsg += " Reason: "; 470 l_errMsg += l_ex.what(); 471 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged"; 472 473 uint16_t l_errCode = 0; 474 475 // ToDo -- Update Internal RC code 476 EventLogger::createAsyncPelWithInventoryCallout( 477 EventLogger::getErrorType(l_ex), types::SeverityType::Informational, 478 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath, 479 l_errCode), 480 types::CalloutPriority::High}}, 481 std::source_location::current().file_name(), 482 std::source_location::current().function_name(), 0, l_errMsg, 483 std::nullopt, std::nullopt, std::nullopt, std::nullopt); 484 485 logging::logMessage(l_errMsg); 486 487 return false; 488 } 489 } 490 491 /** 492 * @brief Process any action, if defined in config JSON. 493 * 494 * If any FRU(s) requires any special handling, then this base action can be 495 * defined for that FRU in the config JSON, processing of which will be handled 496 * in this API. 497 * Examples of action - preAction, PostAction etc. 498 * 499 * @param[in] i_parsedConfigJson - config JSON 500 * @param[in] i_action - Base action to be performed. 501 * @param[in] i_vpdFilePath - EEPROM file path 502 * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed 503 * under PreAction tag of config JSON. 504 * @param[out] o_errCode - To set error code in case of error. 505 * @return - success or failure 506 */ 507 inline bool executeBaseAction( 508 const nlohmann::json& i_parsedConfigJson, const std::string& i_action, 509 const std::string& i_vpdFilePath, const std::string& i_flagToProcess, 510 uint16_t& o_errCode) 511 { 512 if (i_flagToProcess.empty() || i_action.empty() || i_vpdFilePath.empty() || 513 !i_parsedConfigJson.contains("frus")) 514 { 515 o_errCode = error_code::INVALID_INPUT_PARAMETER; 516 return false; 517 } 518 if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath)) 519 { 520 o_errCode = error_code::FILE_NOT_FOUND; 521 return false; 522 } 523 if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains(i_action)) 524 { 525 o_errCode = error_code::MISSING_ACTION_TAG; 526 return false; 527 } 528 529 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))[i_action].contains( 530 i_flagToProcess)) 531 { 532 o_errCode = error_code::MISSING_FLAG; 533 return false; 534 } 535 536 const nlohmann::json& l_tagsJson = 537 (i_parsedConfigJson["frus"][i_vpdFilePath].at( 538 0))[i_action][i_flagToProcess]; 539 540 for (const auto& l_tag : l_tagsJson.items()) 541 { 542 auto itrToFunction = funcionMap.find(l_tag.key()); 543 if (itrToFunction != funcionMap.end()) 544 { 545 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath, 546 i_action, i_flagToProcess, o_errCode)) 547 { 548 // In case any of the tag fails to execute. Mark action 549 // as failed for that flag. 550 if (o_errCode) 551 { 552 logging::logMessage( 553 l_tag.key() + " failed for [" + i_vpdFilePath + 554 "]. Reason " + 555 vpdSpecificUtility::getErrCodeMsg(o_errCode)); 556 } 557 return false; 558 } 559 } 560 } 561 562 return true; 563 } 564 565 /** 566 * @brief Get redundant FRU path from system config JSON 567 * 568 * Given either D-bus inventory path/FRU path/redundant FRU path, this 569 * API returns the redundant FRU path taken from "redundantEeprom" tag from 570 * system config JSON. 571 * 572 * @param[in] i_sysCfgJsonObj - System config JSON object. 573 * @param[in] i_vpdPath - Path to where VPD is stored. 574 * @param[out] o_errCode - To set error code in case of error. 575 * 576 * @return On success return valid path, on failure return empty string. 577 */ 578 inline std::string getRedundantEepromPathFromJson( 579 const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath, 580 uint16_t& o_errCode) 581 { 582 if (i_vpdPath.empty()) 583 { 584 o_errCode = error_code::INVALID_INPUT_PARAMETER; 585 return std::string{}; 586 } 587 588 if (!i_sysCfgJsonObj.contains("frus")) 589 { 590 o_errCode = error_code::INVALID_JSON; 591 return std::string{}; 592 } 593 594 // check if given path is FRU path 595 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath)) 596 { 597 return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value( 598 "redundantEeprom", ""); 599 } 600 601 const nlohmann::json& l_fruList = 602 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>(); 603 604 for (const auto& l_fru : l_fruList.items()) 605 { 606 const std::string& l_fruPath = l_fru.key(); 607 const std::string& l_redundantFruPath = 608 i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("redundantEeprom", 609 ""); 610 611 // check if given path is inventory path or redundant FRU path 612 if ((i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath", 613 "") == i_vpdPath) || 614 (l_redundantFruPath == i_vpdPath)) 615 { 616 return l_redundantFruPath; 617 } 618 } 619 620 return std::string(); 621 } 622 623 /** 624 * @brief Get FRU EEPROM path from system config JSON 625 * 626 * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path, 627 * this API returns FRU EEPROM path if present in JSON. 628 * 629 * @param[in] i_sysCfgJsonObj - System config JSON object 630 * @param[in] i_vpdPath - Path to where VPD is stored. 631 * @param[out] o_errCode - To set error code in case of error. 632 * 633 * @return On success return valid path, on failure return empty string. 634 */ 635 inline std::string getFruPathFromJson(const nlohmann::json& i_sysCfgJsonObj, 636 const std::string& i_vpdPath, 637 uint16_t& o_errCode) 638 { 639 if (i_vpdPath.empty()) 640 { 641 o_errCode = error_code::INVALID_INPUT_PARAMETER; 642 return std::string{}; 643 } 644 645 if (!i_sysCfgJsonObj.contains("frus")) 646 { 647 o_errCode = error_code::INVALID_JSON; 648 return std::string{}; 649 } 650 651 // check if given path is FRU path 652 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath)) 653 { 654 return i_vpdPath; 655 } 656 657 const nlohmann::json& l_fruList = 658 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>(); 659 660 for (const auto& l_fru : l_fruList.items()) 661 { 662 const auto l_fruPath = l_fru.key(); 663 664 // check if given path is redundant FRU path or inventory path 665 if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value( 666 "redundantEeprom", "") || 667 (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value( 668 "inventoryPath", ""))) 669 { 670 return l_fruPath; 671 } 672 } 673 674 return std::string(); 675 } 676 677 /** 678 * @brief An API to check backup and restore VPD is required. 679 * 680 * The API checks if there is provision for backup and restore mentioned in the 681 * system config JSON, by looking "backupRestoreConfigPath" tag. 682 * Checks if the path mentioned is a hardware path, by checking if the file path 683 * exists and size of contents in the path. 684 * 685 * @param[in] i_sysCfgJsonObj - System config JSON object. 686 * @param[out] o_errCode - To set error code in case of error. 687 * 688 * @return true if backup and restore is required, false otherwise. 689 */ 690 inline bool isBackupAndRestoreRequired(const nlohmann::json& i_sysCfgJsonObj, 691 uint16_t& o_errCode) 692 { 693 if (i_sysCfgJsonObj.empty()) 694 { 695 o_errCode = error_code::INVALID_INPUT_PARAMETER; 696 return false; 697 } 698 699 const std::string& l_backupAndRestoreCfgFilePath = 700 i_sysCfgJsonObj.value("backupRestoreConfigPath", ""); 701 702 if (!l_backupAndRestoreCfgFilePath.empty() && 703 std::filesystem::exists(l_backupAndRestoreCfgFilePath) && 704 !std::filesystem::is_empty(l_backupAndRestoreCfgFilePath)) 705 { 706 return true; 707 } 708 709 return false; 710 } 711 712 /** @brief API to check if an action is required for given EEPROM path. 713 * 714 * System config JSON can contain pre-action, post-action etc. like actions 715 * defined for an EEPROM path. The API will check if any such action is defined 716 * for the EEPROM. 717 * 718 * @param[in] i_sysCfgJsonObj - System config JSON object. 719 * @param[in] i_vpdFruPath - EEPROM path. 720 * @param[in] i_action - Action to be checked. 721 * @param[in] i_flowFlag - Denotes the flow w.r.t which the action should be 722 * triggered. 723 * @param[out] o_errCode - To set error code in case of error. 724 * @return - True if action is defined for the flow, false otherwise. 725 */ 726 inline bool isActionRequired(const nlohmann::json& i_sysCfgJsonObj, 727 const std::string& i_vpdFruPath, 728 const std::string& i_action, 729 const std::string& i_flowFlag, uint16_t& o_errCode) 730 { 731 if (i_vpdFruPath.empty() || i_action.empty() || i_flowFlag.empty()) 732 { 733 o_errCode = error_code::INVALID_INPUT_PARAMETER; 734 return false; 735 } 736 737 if (!i_sysCfgJsonObj.contains("frus")) 738 { 739 o_errCode = error_code::INVALID_JSON; 740 return false; 741 } 742 743 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath)) 744 { 745 o_errCode = error_code::FRU_PATH_NOT_FOUND; 746 return false; 747 } 748 749 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)).contains(i_action)) 750 { 751 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))[i_action].contains( 752 i_flowFlag)) 753 { 754 return true; 755 } 756 } 757 return false; 758 } 759 760 /** 761 * @brief An API to return list of FRUs that needs GPIO polling. 762 * 763 * An API that checks for the FRUs that requires GPIO polling and returns 764 * a list of FRUs that needs polling. Returns an empty list if there are 765 * no FRUs that requires polling. 766 * 767 * @param[in] i_sysCfgJsonObj - System config JSON object. 768 * @param[out] o_errCode - To set error codes in case of error. 769 * 770 * @return On success list of FRUs parameters that needs polling. On failure, 771 * empty list. 772 */ 773 inline std::vector<std::string> getListOfGpioPollingFrus( 774 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode) 775 { 776 std::vector<std::string> l_gpioPollingRequiredFrusList; 777 778 if (i_sysCfgJsonObj.empty()) 779 { 780 o_errCode = error_code::INVALID_INPUT_PARAMETER; 781 return l_gpioPollingRequiredFrusList; 782 } 783 784 if (!i_sysCfgJsonObj.contains("frus")) 785 { 786 o_errCode = error_code::INVALID_JSON; 787 return l_gpioPollingRequiredFrusList; 788 } 789 790 for (const auto& l_fru : i_sysCfgJsonObj["frus"].items()) 791 { 792 const auto l_fruPath = l_fru.key(); 793 794 bool l_isHotPluggableFru = 795 isActionRequired(i_sysCfgJsonObj, l_fruPath, "pollingRequired", 796 "hotPlugging", o_errCode); 797 798 if (o_errCode) 799 { 800 logging::logMessage( 801 "Error while checking if action required for FRU [" + 802 std::string(l_fruPath) + 803 "], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode)); 804 805 return l_gpioPollingRequiredFrusList; 806 } 807 808 if (l_isHotPluggableFru) 809 { 810 if (i_sysCfgJsonObj["frus"][l_fruPath] 811 .at(0)["pollingRequired"]["hotPlugging"] 812 .contains("gpioPresence")) 813 { 814 l_gpioPollingRequiredFrusList.push_back(l_fruPath); 815 } 816 } 817 } 818 819 return l_gpioPollingRequiredFrusList; 820 } 821 822 /** 823 * @brief Get all related path(s) to update keyword value. 824 * 825 * Given FRU EEPROM path/Inventory path needs keyword's value update, this API 826 * returns tuple of FRU EEPROM path, inventory path and redundant EEPROM path if 827 * exists in the system config JSON. 828 * 829 * Note: If the inventory object path or redundant EEPROM path(s) are not found 830 * in the system config JSON, corresponding fields will have empty value in the 831 * returning tuple. 832 * 833 * @param[in] i_sysCfgJsonObj - System config JSON object. 834 * @param[in,out] io_vpdPath - Inventory object path or FRU EEPROM path. 835 * @param[out] o_errCode - To set error code in case of error. 836 * 837 * @return On success returns tuple of EEPROM path, inventory path & redundant 838 * path, on failure returns tuple with given input path alone. 839 */ 840 inline std::tuple<std::string, std::string, std::string> 841 getAllPathsToUpdateKeyword(const nlohmann::json& i_sysCfgJsonObj, 842 std::string io_vpdPath, uint16_t& o_errCode) 843 { 844 types::Path l_inventoryObjPath; 845 types::Path l_redundantFruPath; 846 o_errCode = 0; 847 848 if (i_sysCfgJsonObj.empty() || io_vpdPath.empty()) 849 { 850 o_errCode = error_code::INVALID_INPUT_PARAMETER; 851 return std::make_tuple(io_vpdPath, l_inventoryObjPath, 852 l_redundantFruPath); 853 } 854 855 // Get hardware path from system config JSON. 856 const types::Path l_fruPath = 857 jsonUtility::getFruPathFromJson(i_sysCfgJsonObj, io_vpdPath, o_errCode); 858 859 if (!l_fruPath.empty()) 860 { 861 io_vpdPath = l_fruPath; 862 863 // Get inventory object path from system config JSON 864 l_inventoryObjPath = jsonUtility::getInventoryObjPathFromJson( 865 i_sysCfgJsonObj, l_fruPath, o_errCode); 866 867 if (l_inventoryObjPath.empty()) 868 { 869 if (o_errCode) 870 { 871 logging::logMessage( 872 "Failed to get inventory path from JSON for [" + 873 io_vpdPath + "], error : " + 874 vpdSpecificUtility::getErrCodeMsg(o_errCode)); 875 } 876 else 877 { 878 o_errCode = error_code::FRU_PATH_NOT_FOUND; 879 } 880 881 return std::make_tuple(io_vpdPath, l_inventoryObjPath, 882 l_redundantFruPath); 883 } 884 885 // Get redundant hardware path if present in system config JSON 886 l_redundantFruPath = jsonUtility::getRedundantEepromPathFromJson( 887 i_sysCfgJsonObj, l_fruPath, o_errCode); 888 889 if (l_redundantFruPath.empty()) 890 { 891 if (o_errCode) 892 { 893 logging::logMessage( 894 "Failed to get redundant EEPROM path for FRU [" + 895 l_fruPath + "], error : " + 896 vpdSpecificUtility::getErrCodeMsg(o_errCode)); 897 898 o_errCode = error_code::ERROR_GETTING_REDUNDANT_PATH; 899 } 900 else 901 { 902 o_errCode = error_code::REDUNDANT_PATH_NOT_FOUND; 903 } 904 905 return std::make_tuple(io_vpdPath, l_inventoryObjPath, 906 l_redundantFruPath); 907 } 908 } 909 else if (o_errCode) 910 { 911 logging::logMessage( 912 "Failed to get FRU path from JSON for [" + io_vpdPath + 913 "], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode)); 914 } 915 else 916 { 917 o_errCode = error_code::NO_EEPROM_PATH; 918 } 919 920 return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath); 921 } 922 923 /** 924 * @brief An API to get DBus service name. 925 * 926 * Given DBus inventory path, this API returns DBus service name if present in 927 * the JSON. 928 * 929 * @param[in] i_sysCfgJsonObj - System config JSON object. 930 * @param[in] l_inventoryPath - DBus inventory path. 931 * @param[out] o_errCode - To set error code in case of error. 932 * 933 * @return On success returns the service name present in the system config 934 * JSON, otherwise empty string. 935 * 936 * Note: Caller has to handle in case of empty string received. 937 */ 938 inline std::string getServiceName(const nlohmann::json& i_sysCfgJsonObj, 939 const std::string& l_inventoryPath, 940 uint16_t& o_errCode) 941 { 942 if (l_inventoryPath.empty()) 943 { 944 o_errCode = error_code::INVALID_INPUT_PARAMETER; 945 return std::string{}; 946 } 947 948 if (!i_sysCfgJsonObj.contains("frus")) 949 { 950 o_errCode = error_code::INVALID_JSON; 951 return std::string{}; 952 } 953 954 const nlohmann::json& l_listOfFrus = 955 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>(); 956 957 for (const auto& l_frus : l_listOfFrus.items()) 958 { 959 for (const auto& l_inventoryItem : l_frus.value()) 960 { 961 if (l_inventoryPath.compare(l_inventoryItem["inventoryPath"]) == 962 constants::STR_CMP_SUCCESS) 963 { 964 if (l_inventoryItem.contains("serviceName")) 965 { 966 return l_inventoryItem.value("serviceName", ""); 967 } 968 969 o_errCode = error_code::JSON_MISSING_SERVICE_NAME; 970 return std::string{}; 971 } 972 } 973 } 974 975 o_errCode = error_code::FRU_PATH_NOT_FOUND; 976 return std::string{}; 977 } 978 979 /** 980 * @brief An API to check if a FRU is tagged as "powerOffOnly" 981 * 982 * Given the system config JSON and VPD FRU path, this API checks if the FRU 983 * VPD can be collected at Chassis Power Off state only. 984 * 985 * @param[in] i_sysCfgJsonObj - System config JSON object. 986 * @param[in] i_vpdFruPath - EEPROM path. 987 * @param[out] o_errCode - To set error code for the error. 988 * @return - True if FRU VPD can be collected at Chassis Power Off state only. 989 * False otherwise 990 */ 991 inline bool isFruPowerOffOnly(const nlohmann::json& i_sysCfgJsonObj, 992 const std::string& i_vpdFruPath, 993 uint16_t& o_errCode) 994 { 995 if (i_vpdFruPath.empty()) 996 { 997 o_errCode = error_code::INVALID_INPUT_PARAMETER; 998 return false; 999 } 1000 1001 if (!i_sysCfgJsonObj.contains("frus")) 1002 { 1003 o_errCode = error_code::INVALID_JSON; 1004 return false; 1005 } 1006 1007 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath)) 1008 { 1009 o_errCode = error_code::FRU_PATH_NOT_FOUND; 1010 return false; 1011 } 1012 1013 return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)) 1014 .contains("powerOffOnly") && 1015 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["powerOffOnly"])); 1016 } 1017 1018 /** 1019 * @brief API which tells if the FRU is replaceable at runtime 1020 * 1021 * @param[in] i_sysCfgJsonObj - System config JSON object. 1022 * @param[in] i_vpdFruPath - EEPROM path. 1023 * @param[out] o_errCode - to set error code in case of error. 1024 * 1025 * @return true if FRU is replaceable at runtime. false otherwise. 1026 */ 1027 inline bool isFruReplaceableAtRuntime(const nlohmann::json& i_sysCfgJsonObj, 1028 const std::string& i_vpdFruPath, 1029 uint16_t& o_errCode) 1030 { 1031 if (i_vpdFruPath.empty()) 1032 { 1033 o_errCode = error_code::INVALID_INPUT_PARAMETER; 1034 return false; 1035 } 1036 1037 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus"))) 1038 { 1039 o_errCode = error_code::INVALID_JSON; 1040 return false; 1041 } 1042 1043 return ( 1044 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)) 1045 .contains("replaceableAtRuntime") && 1046 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtRuntime"])); 1047 1048 return false; 1049 } 1050 1051 /** 1052 * @brief API which tells if the FRU is replaceable at standby 1053 * 1054 * @param[in] i_sysCfgJsonObj - System config JSON object. 1055 * @param[in] i_vpdFruPath - EEPROM path. 1056 * @param[out] o_errCode - set error code in case of error. 1057 * 1058 * @return true if FRU is replaceable at standby. false otherwise. 1059 */ 1060 inline bool isFruReplaceableAtStandby(const nlohmann::json& i_sysCfgJsonObj, 1061 const std::string& i_vpdFruPath, 1062 uint16_t& o_errCode) 1063 { 1064 if (i_vpdFruPath.empty()) 1065 { 1066 o_errCode = error_code::INVALID_INPUT_PARAMETER; 1067 return false; 1068 } 1069 1070 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus"))) 1071 { 1072 o_errCode = error_code::INVALID_JSON; 1073 } 1074 1075 return ( 1076 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)) 1077 .contains("replaceableAtStandby") && 1078 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtStandby"])); 1079 1080 return false; 1081 } 1082 1083 /** 1084 * @brief API to get list of FRUs replaceable at standby from JSON. 1085 * 1086 * The API will return a vector of FRUs inventory path which are replaceable at 1087 * standby. 1088 * 1089 * @param[in] i_sysCfgJsonObj - System config JSON object. 1090 * @param[out] o_errCode - To set error code in case of error. 1091 * 1092 * @return - On success, list of FRUs replaceable at standby. On failure, empty 1093 * vector. 1094 */ 1095 inline std::vector<std::string> getListOfFrusReplaceableAtStandby( 1096 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode) 1097 { 1098 std::vector<std::string> l_frusReplaceableAtStandby; 1099 1100 if (!i_sysCfgJsonObj.contains("frus")) 1101 { 1102 o_errCode = error_code::INVALID_JSON; 1103 return l_frusReplaceableAtStandby; 1104 } 1105 1106 const nlohmann::json& l_fruList = 1107 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>(); 1108 1109 for (const auto& l_fru : l_fruList.items()) 1110 { 1111 if (i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value( 1112 "replaceableAtStandby", false)) 1113 { 1114 const std::string& l_inventoryObjectPath = 1115 i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value( 1116 "inventoryPath", ""); 1117 1118 if (!l_inventoryObjectPath.empty()) 1119 { 1120 l_frusReplaceableAtStandby.emplace_back(l_inventoryObjectPath); 1121 } 1122 } 1123 } 1124 1125 return l_frusReplaceableAtStandby; 1126 } 1127 1128 /** 1129 * @brief API to select powerVS JSON based on system IM. 1130 * 1131 * The API selects respective JSON based on system IM, parse it and return the 1132 * JSON object. Empty JSON will be returned in case of any error. Caller needs 1133 * to handle empty value. 1134 * 1135 * @param[in] i_imValue - IM value of the system. 1136 * @param[out] o_errCode - to set error code in case of error. 1137 * @return Parsed JSON object, empty JSON otherwise. 1138 */ 1139 inline nlohmann::json getPowerVsJson(const types::BinaryVector& i_imValue, 1140 uint16_t& o_errCode) 1141 { 1142 if (i_imValue.empty() || i_imValue.size() < 4) 1143 { 1144 o_errCode = error_code::INVALID_INPUT_PARAMETER; 1145 return nlohmann::json{}; 1146 } 1147 1148 o_errCode = 0; 1149 if ((i_imValue.at(0) == constants::HEX_VALUE_50) && 1150 (i_imValue.at(1) == constants::HEX_VALUE_00) && 1151 (i_imValue.at(2) == constants::HEX_VALUE_30)) 1152 { 1153 nlohmann::json l_parsedJson = jsonUtility::getParsedJson( 1154 constants::power_vs_50003_json, o_errCode); 1155 1156 if (o_errCode) 1157 { 1158 logging::logMessage( 1159 "Failed to parse JSON file [ " + 1160 std::string(constants::power_vs_50003_json) + 1161 " ], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode)); 1162 } 1163 1164 return l_parsedJson; 1165 } 1166 else if (i_imValue.at(0) == constants::HEX_VALUE_50 && 1167 (i_imValue.at(1) == constants::HEX_VALUE_00) && 1168 (i_imValue.at(2) == constants::HEX_VALUE_10)) 1169 { 1170 nlohmann::json l_parsedJson = jsonUtility::getParsedJson( 1171 constants::power_vs_50001_json, o_errCode); 1172 1173 if (o_errCode) 1174 { 1175 logging::logMessage( 1176 "Failed to parse JSON file [ " + 1177 std::string(constants::power_vs_50001_json) + 1178 " ], error : " + vpdSpecificUtility::getErrCodeMsg(o_errCode)); 1179 } 1180 1181 return l_parsedJson; 1182 } 1183 return nlohmann::json{}; 1184 } 1185 1186 /** 1187 * @brief API to get list of FRUs for which "monitorPresence" is true. 1188 * 1189 * @param[in] i_sysCfgJsonObj - System config JSON object. 1190 * @param[out] o_errCode - To set error code in case of error. 1191 * 1192 * @return On success, returns list of FRUs for which "monitorPresence" is true, 1193 * empty list on error. 1194 */ 1195 inline std::vector<types::Path> getFrusWithPresenceMonitoring( 1196 const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode) 1197 { 1198 std::vector<types::Path> l_frusWithPresenceMonitoring; 1199 1200 if (!i_sysCfgJsonObj.contains("frus")) 1201 { 1202 o_errCode = error_code::INVALID_JSON; 1203 return l_frusWithPresenceMonitoring; 1204 } 1205 1206 const nlohmann::json& l_listOfFrus = 1207 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>(); 1208 1209 for (const auto& l_aFru : l_listOfFrus) 1210 { 1211 if (l_aFru.at(0).value("monitorPresence", false)) 1212 { 1213 l_frusWithPresenceMonitoring.emplace_back( 1214 l_aFru.at(0).value("inventoryPath", "")); 1215 } 1216 } 1217 1218 return l_frusWithPresenceMonitoring; 1219 } 1220 1221 /** 1222 * @brief API which tells if the FRU's presence is handled 1223 * 1224 * For a given FRU, this API checks if it's presence is handled by vpd-manager 1225 * by checking the "handlePresence" tag. 1226 * 1227 * @param[in] i_sysCfgJsonObj - System config JSON object. 1228 * @param[in] i_vpdFruPath - EEPROM path. 1229 * @param[out] o_errCode - To set error code in case of failure. 1230 * 1231 * @return true if FRU presence is handled, false otherwise. 1232 */ 1233 inline bool isFruPresenceHandled(const nlohmann::json& i_sysCfgJsonObj, 1234 const std::string& i_vpdFruPath, 1235 uint16_t& o_errCode) 1236 { 1237 if (i_vpdFruPath.empty()) 1238 { 1239 o_errCode = error_code::INVALID_INPUT_PARAMETER; 1240 return false; 1241 } 1242 1243 if (!i_sysCfgJsonObj.contains("frus")) 1244 { 1245 o_errCode = error_code::INVALID_JSON; 1246 return false; 1247 } 1248 1249 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath)) 1250 { 1251 o_errCode = error_code::FRU_PATH_NOT_FOUND; 1252 return false; 1253 } 1254 1255 return i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0).value( 1256 "handlePresence", true); 1257 } 1258 } // namespace jsonUtility 1259 } // namespace vpd 1260