xref: /openbmc/openpower-vpd-parser/vpd-manager/include/utility/json_utility.hpp (revision a39aafa337352262596e07577fdf88cc294284c9)
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  */
getVPDOffset(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFilePath,uint16_t & o_errCode)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  */
getParsedJson(const std::string & pathToJson,uint16_t & o_errCode)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  */
getInventoryObjPathFromJson(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdPath,uint16_t & o_errCode)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  */
executePostFailAction(const nlohmann::json & i_parsedConfigJson,const std::string & i_vpdFilePath,const std::string & i_flagToProcess,uint16_t & o_errCode)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  */
processSystemCmdTag(const nlohmann::json & i_parsedConfigJson,const std::string & i_vpdFilePath,const std::string & i_baseAction,const std::string & i_flagToProcess,uint16_t & o_errCode)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  */
processGpioPresenceTag(const nlohmann::json & i_parsedConfigJson,const std::string & i_vpdFilePath,const std::string & i_baseAction,const std::string & i_flagToProcess,uint16_t & o_errCode)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  */
procesSetGpioTag(const nlohmann::json & i_parsedConfigJson,const std::string & i_vpdFilePath,const std::string & i_baseAction,const std::string & i_flagToProcess,uint16_t & o_errCode)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  */
executeBaseAction(const nlohmann::json & i_parsedConfigJson,const std::string & i_action,const std::string & i_vpdFilePath,const std::string & i_flagToProcess,uint16_t & o_errCode)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  */
getRedundantEepromPathFromJson(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdPath,uint16_t & o_errCode)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  */
getFruPathFromJson(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdPath,uint16_t & o_errCode)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  */
isBackupAndRestoreRequired(const nlohmann::json & i_sysCfgJsonObj,uint16_t & o_errCode)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  */
isActionRequired(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,const std::string & i_action,const std::string & i_flowFlag,uint16_t & o_errCode)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  */
getListOfGpioPollingFrus(const nlohmann::json & i_sysCfgJsonObj,uint16_t & o_errCode)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>
getAllPathsToUpdateKeyword(const nlohmann::json & i_sysCfgJsonObj,std::string io_vpdPath,uint16_t & o_errCode)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  */
getServiceName(const nlohmann::json & i_sysCfgJsonObj,const std::string & l_inventoryPath,uint16_t & o_errCode)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  */
isFruPowerOffOnly(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,uint16_t & o_errCode)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  */
isFruReplaceableAtRuntime(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,uint16_t & o_errCode)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  */
isFruReplaceableAtStandby(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,uint16_t & o_errCode)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  */
getListOfFrusReplaceableAtStandby(const nlohmann::json & i_sysCfgJsonObj,uint16_t & o_errCode)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  */
getPowerVsJson(const types::BinaryVector & i_imValue,uint16_t & o_errCode)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  */
getFrusWithPresenceMonitoring(const nlohmann::json & i_sysCfgJsonObj,uint16_t & o_errCode)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  */
isFruPresenceHandled(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,uint16_t & o_errCode)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