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