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