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