xref: /openbmc/openpower-vpd-parser/vpd-manager/include/utility/json_utility.hpp (revision 7b1f0354c732215d5102c0e77cfd296cce43f9d7)
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, o_errCode);
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     o_errCode = error_code::FRU_PATH_NOT_FOUND;
710     return std::string();
711 }
712 
713 /**
714  * @brief An API to check backup and restore VPD is required.
715  *
716  * The API checks if there is provision for backup and restore mentioned in the
717  * system config JSON, by looking "backupRestoreConfigPath" tag.
718  * Checks if the path mentioned is a hardware path, by checking if the file path
719  * exists and size of contents in the path.
720  *
721  * @param[in] i_sysCfgJsonObj - System config JSON object.
722  * @param[out] o_errCode - To set error code in case of error.
723  *
724  * @return true if backup and restore is required, false otherwise.
725  */
isBackupAndRestoreRequired(const nlohmann::json & i_sysCfgJsonObj,uint16_t & o_errCode)726 inline bool isBackupAndRestoreRequired(const nlohmann::json& i_sysCfgJsonObj,
727                                        uint16_t& o_errCode)
728 {
729     o_errCode = 0;
730     if (i_sysCfgJsonObj.empty())
731     {
732         o_errCode = error_code::INVALID_INPUT_PARAMETER;
733         return false;
734     }
735 
736     const std::string& l_backupAndRestoreCfgFilePath =
737         i_sysCfgJsonObj.value("backupRestoreConfigPath", "");
738 
739     if (!l_backupAndRestoreCfgFilePath.empty() &&
740         std::filesystem::exists(l_backupAndRestoreCfgFilePath) &&
741         !std::filesystem::is_empty(l_backupAndRestoreCfgFilePath))
742     {
743         return true;
744     }
745 
746     return false;
747 }
748 
749 /** @brief API to check if an action is required for given EEPROM path.
750  *
751  * System config JSON can contain pre-action, post-action etc. like actions
752  * defined for an EEPROM path. The API will check if any such action is defined
753  * for the EEPROM.
754  *
755  * @param[in] i_sysCfgJsonObj - System config JSON object.
756  * @param[in] i_vpdFruPath - EEPROM path.
757  * @param[in] i_action - Action to be checked.
758  * @param[in] i_flowFlag - Denotes the flow w.r.t which the action should be
759  * triggered.
760  * @param[out] o_errCode - To set error code in case of error.
761  * @return - True if action is defined for the flow, false otherwise.
762  */
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)763 inline bool isActionRequired(const nlohmann::json& i_sysCfgJsonObj,
764                              const std::string& i_vpdFruPath,
765                              const std::string& i_action,
766                              const std::string& i_flowFlag, uint16_t& o_errCode)
767 {
768     o_errCode = 0;
769     if (i_vpdFruPath.empty() || i_action.empty() || i_flowFlag.empty())
770     {
771         o_errCode = error_code::INVALID_INPUT_PARAMETER;
772         return false;
773     }
774 
775     if (!i_sysCfgJsonObj.contains("frus"))
776     {
777         o_errCode = error_code::INVALID_JSON;
778         return false;
779     }
780 
781     if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
782     {
783         o_errCode = error_code::FRU_PATH_NOT_FOUND;
784         return false;
785     }
786 
787     if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)).contains(i_action))
788     {
789         if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))[i_action].contains(
790                 i_flowFlag))
791         {
792             return true;
793         }
794     }
795     return false;
796 }
797 
798 /**
799  * @brief An API to return list of FRUs that needs GPIO polling.
800  *
801  * An API that checks for the FRUs that requires GPIO polling and returns
802  * a list of FRUs that needs polling. Returns an empty list if there are
803  * no FRUs that requires polling.
804  *
805  * @param[in] i_sysCfgJsonObj - System config JSON object.
806  * @param[out] o_errCode - To set error codes in case of error.
807  *
808  * @return On success list of FRUs parameters that needs polling. On failure,
809  * empty list.
810  */
getListOfGpioPollingFrus(const nlohmann::json & i_sysCfgJsonObj,uint16_t & o_errCode)811 inline std::vector<std::string> getListOfGpioPollingFrus(
812     const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
813 {
814     std::vector<std::string> l_gpioPollingRequiredFrusList;
815     o_errCode = 0;
816 
817     if (i_sysCfgJsonObj.empty())
818     {
819         o_errCode = error_code::INVALID_INPUT_PARAMETER;
820         return l_gpioPollingRequiredFrusList;
821     }
822 
823     if (!i_sysCfgJsonObj.contains("frus"))
824     {
825         o_errCode = error_code::INVALID_JSON;
826         return l_gpioPollingRequiredFrusList;
827     }
828 
829     for (const auto& l_fru : i_sysCfgJsonObj["frus"].items())
830     {
831         const auto l_fruPath = l_fru.key();
832 
833         bool l_isHotPluggableFru =
834             isActionRequired(i_sysCfgJsonObj, l_fruPath, "pollingRequired",
835                              "hotPlugging", o_errCode);
836 
837         if (o_errCode)
838         {
839             logging::logMessage(
840                 "Error while checking if action required for FRU [" +
841                 std::string(l_fruPath) +
842                 "], error : " + commonUtility::getErrCodeMsg(o_errCode));
843 
844             return l_gpioPollingRequiredFrusList;
845         }
846 
847         if (l_isHotPluggableFru)
848         {
849             if (i_sysCfgJsonObj["frus"][l_fruPath]
850                     .at(0)["pollingRequired"]["hotPlugging"]
851                     .contains("gpioPresence"))
852             {
853                 l_gpioPollingRequiredFrusList.push_back(l_fruPath);
854             }
855         }
856     }
857 
858     return l_gpioPollingRequiredFrusList;
859 }
860 
861 /**
862  * @brief Get all related path(s) to update keyword value.
863  *
864  * Given FRU EEPROM path/Inventory path needs keyword's value update, this API
865  * returns tuple of FRU EEPROM path, inventory path and redundant EEPROM path if
866  * exists in the system config JSON.
867  *
868  * Note: If the inventory object path or redundant EEPROM path(s) are not found
869  * in the system config JSON, corresponding fields will have empty value in the
870  * returning tuple.
871  *
872  * @param[in] i_sysCfgJsonObj - System config JSON object.
873  * @param[in,out] io_vpdPath - Inventory object path or FRU EEPROM path.
874  * @param[out] o_errCode - To set error code in case of error.
875  *
876  * @return On success returns tuple of EEPROM path, inventory path & redundant
877  * path, on failure returns tuple with given input path alone.
878  */
879 inline std::tuple<std::string, std::string, std::string>
getAllPathsToUpdateKeyword(const nlohmann::json & i_sysCfgJsonObj,std::string io_vpdPath,uint16_t & o_errCode)880     getAllPathsToUpdateKeyword(const nlohmann::json& i_sysCfgJsonObj,
881                                std::string io_vpdPath, uint16_t& o_errCode)
882 {
883     types::Path l_inventoryObjPath;
884     types::Path l_redundantFruPath;
885     o_errCode = 0;
886 
887     if (i_sysCfgJsonObj.empty() || io_vpdPath.empty())
888     {
889         o_errCode = error_code::INVALID_INPUT_PARAMETER;
890         return std::make_tuple(io_vpdPath, l_inventoryObjPath,
891                                l_redundantFruPath);
892     }
893 
894     // Get hardware path from system config JSON.
895     const types::Path l_fruPath =
896         jsonUtility::getFruPathFromJson(i_sysCfgJsonObj, io_vpdPath, o_errCode);
897 
898     if (!l_fruPath.empty())
899     {
900         io_vpdPath = l_fruPath;
901 
902         // Get inventory object path from system config JSON
903         l_inventoryObjPath = jsonUtility::getInventoryObjPathFromJson(
904             i_sysCfgJsonObj, l_fruPath, o_errCode);
905 
906         if (l_inventoryObjPath.empty())
907         {
908             if (o_errCode)
909             {
910                 logging::logMessage(
911                     "Failed to get inventory path from JSON for [" +
912                     io_vpdPath +
913                     "], error : " + commonUtility::getErrCodeMsg(o_errCode));
914             }
915             else
916             {
917                 o_errCode = error_code::FRU_PATH_NOT_FOUND;
918             }
919 
920             return std::make_tuple(io_vpdPath, l_inventoryObjPath,
921                                    l_redundantFruPath);
922         }
923 
924         // Get redundant hardware path if present in system config JSON
925         l_redundantFruPath = jsonUtility::getRedundantEepromPathFromJson(
926             i_sysCfgJsonObj, l_fruPath, o_errCode);
927 
928         if (l_redundantFruPath.empty())
929         {
930             if (o_errCode)
931             {
932                 logging::logMessage(
933                     "Failed to get redundant EEPROM path for FRU [" +
934                     l_fruPath +
935                     "], error : " + commonUtility::getErrCodeMsg(o_errCode));
936 
937                 o_errCode = error_code::ERROR_GETTING_REDUNDANT_PATH;
938             }
939             else
940             {
941                 o_errCode = error_code::REDUNDANT_PATH_NOT_FOUND;
942             }
943 
944             return std::make_tuple(io_vpdPath, l_inventoryObjPath,
945                                    l_redundantFruPath);
946         }
947     }
948     else if (o_errCode)
949     {
950         logging::logMessage(
951             "Failed to get FRU path from JSON for [" + io_vpdPath +
952             "], error : " + commonUtility::getErrCodeMsg(o_errCode));
953     }
954     else
955     {
956         o_errCode = error_code::NO_EEPROM_PATH;
957     }
958 
959     return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath);
960 }
961 
962 /**
963  * @brief An API to get DBus service name.
964  *
965  * Given DBus inventory path, this API returns DBus service name if present in
966  * the JSON.
967  *
968  * @param[in] i_sysCfgJsonObj - System config JSON object.
969  * @param[in] l_inventoryPath - DBus inventory path.
970  * @param[out] o_errCode - To set error code in case of error.
971  *
972  * @return On success returns the service name present in the system config
973  * JSON, otherwise empty string.
974  *
975  * Note: Caller has to handle in case of empty string received.
976  */
getServiceName(const nlohmann::json & i_sysCfgJsonObj,const std::string & l_inventoryPath,uint16_t & o_errCode)977 inline std::string getServiceName(const nlohmann::json& i_sysCfgJsonObj,
978                                   const std::string& l_inventoryPath,
979                                   uint16_t& o_errCode)
980 {
981     o_errCode = 0;
982     if (l_inventoryPath.empty())
983     {
984         o_errCode = error_code::INVALID_INPUT_PARAMETER;
985         return std::string{};
986     }
987 
988     if (!i_sysCfgJsonObj.contains("frus"))
989     {
990         o_errCode = error_code::INVALID_JSON;
991         return std::string{};
992     }
993 
994     const nlohmann::json& l_listOfFrus =
995         i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
996 
997     for (const auto& l_frus : l_listOfFrus.items())
998     {
999         for (const auto& l_inventoryItem : l_frus.value())
1000         {
1001             if (l_inventoryPath.compare(l_inventoryItem["inventoryPath"]) ==
1002                 constants::STR_CMP_SUCCESS)
1003             {
1004                 if (l_inventoryItem.contains("serviceName"))
1005                 {
1006                     return l_inventoryItem.value("serviceName", "");
1007                 }
1008 
1009                 o_errCode = error_code::JSON_MISSING_SERVICE_NAME;
1010                 return std::string{};
1011             }
1012         }
1013     }
1014 
1015     o_errCode = error_code::FRU_PATH_NOT_FOUND;
1016     return std::string{};
1017 }
1018 
1019 /**
1020  * @brief An API to check if a FRU is tagged as "powerOffOnly"
1021  *
1022  * Given the system config JSON and VPD FRU path, this API checks if the FRU
1023  * VPD can be collected at Chassis Power Off state only.
1024  *
1025  * @param[in] i_sysCfgJsonObj - System config JSON object.
1026  * @param[in] i_vpdFruPath - EEPROM path.
1027  * @param[out] o_errCode - To set error code for the error.
1028  * @return - True if FRU VPD can be collected at Chassis Power Off state only.
1029  *           False otherwise
1030  */
isFruPowerOffOnly(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,uint16_t & o_errCode)1031 inline bool isFruPowerOffOnly(const nlohmann::json& i_sysCfgJsonObj,
1032                               const std::string& i_vpdFruPath,
1033                               uint16_t& o_errCode)
1034 {
1035     o_errCode = 0;
1036     if (i_vpdFruPath.empty())
1037     {
1038         o_errCode = error_code::INVALID_INPUT_PARAMETER;
1039         return false;
1040     }
1041 
1042     if (!i_sysCfgJsonObj.contains("frus"))
1043     {
1044         o_errCode = error_code::INVALID_JSON;
1045         return false;
1046     }
1047 
1048     if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1049     {
1050         o_errCode = error_code::FRU_PATH_NOT_FOUND;
1051         return false;
1052     }
1053 
1054     return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1055                 .contains("powerOffOnly") &&
1056             (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["powerOffOnly"]));
1057 }
1058 
1059 /**
1060  * @brief API which tells if the FRU is replaceable at runtime
1061  *
1062  * @param[in] i_sysCfgJsonObj - System config JSON object.
1063  * @param[in] i_vpdFruPath - EEPROM path.
1064  * @param[out] o_errCode - to set error code in case of error.
1065  *
1066  * @return true if FRU is replaceable at runtime. false otherwise.
1067  */
isFruReplaceableAtRuntime(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,uint16_t & o_errCode)1068 inline bool isFruReplaceableAtRuntime(const nlohmann::json& i_sysCfgJsonObj,
1069                                       const std::string& i_vpdFruPath,
1070                                       uint16_t& o_errCode)
1071 {
1072     o_errCode = 0;
1073     if (i_vpdFruPath.empty())
1074     {
1075         o_errCode = error_code::INVALID_INPUT_PARAMETER;
1076         return false;
1077     }
1078 
1079     if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
1080     {
1081         o_errCode = error_code::INVALID_JSON;
1082         return false;
1083     }
1084 
1085     if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1086     {
1087         o_errCode = error_code::FRU_PATH_NOT_FOUND;
1088         return false;
1089     }
1090 
1091     return (
1092         (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1093             .contains("replaceableAtRuntime") &&
1094         (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtRuntime"]));
1095 
1096     return false;
1097 }
1098 
1099 /**
1100  * @brief API which tells if the FRU is replaceable at standby
1101  *
1102  * @param[in] i_sysCfgJsonObj - System config JSON object.
1103  * @param[in] i_vpdFruPath - EEPROM path.
1104  * @param[out] o_errCode - set error code in case of error.
1105  *
1106  * @return true if FRU is replaceable at standby. false otherwise.
1107  */
isFruReplaceableAtStandby(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,uint16_t & o_errCode)1108 inline bool isFruReplaceableAtStandby(const nlohmann::json& i_sysCfgJsonObj,
1109                                       const std::string& i_vpdFruPath,
1110                                       uint16_t& o_errCode)
1111 {
1112     o_errCode = 0;
1113     if (i_vpdFruPath.empty())
1114     {
1115         o_errCode = error_code::INVALID_INPUT_PARAMETER;
1116         return false;
1117     }
1118 
1119     if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
1120     {
1121         o_errCode = error_code::INVALID_JSON;
1122         return false;
1123     }
1124 
1125     if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1126     {
1127         o_errCode = error_code::FRU_PATH_NOT_FOUND;
1128         return false;
1129     }
1130 
1131     return (
1132         (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1133             .contains("replaceableAtStandby") &&
1134         (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["replaceableAtStandby"]));
1135 
1136     return false;
1137 }
1138 
1139 /**
1140  * @brief API to get list of FRUs replaceable at standby from JSON.
1141  *
1142  * The API will return a vector of FRUs inventory path which are replaceable at
1143  * standby.
1144  *
1145  * @param[in] i_sysCfgJsonObj - System config JSON object.
1146  * @param[out] o_errCode - To set error code in case of error.
1147  *
1148  * @return - On success, list of FRUs replaceable at standby. On failure, empty
1149  * vector.
1150  */
getListOfFrusReplaceableAtStandby(const nlohmann::json & i_sysCfgJsonObj,uint16_t & o_errCode)1151 inline std::vector<std::string> getListOfFrusReplaceableAtStandby(
1152     const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
1153 {
1154     std::vector<std::string> l_frusReplaceableAtStandby;
1155     o_errCode = 0;
1156 
1157     if (!i_sysCfgJsonObj.contains("frus"))
1158     {
1159         o_errCode = error_code::INVALID_JSON;
1160         return l_frusReplaceableAtStandby;
1161     }
1162 
1163     const nlohmann::json& l_fruList =
1164         i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
1165 
1166     for (const auto& l_fru : l_fruList.items())
1167     {
1168         if (i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1169                 "replaceableAtStandby", false))
1170         {
1171             const std::string& l_inventoryObjectPath =
1172                 i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1173                     "inventoryPath", "");
1174 
1175             if (!l_inventoryObjectPath.empty())
1176             {
1177                 l_frusReplaceableAtStandby.emplace_back(l_inventoryObjectPath);
1178             }
1179         }
1180     }
1181 
1182     return l_frusReplaceableAtStandby;
1183 }
1184 
1185 /**
1186  * @brief API to select powerVS JSON based on system IM.
1187  *
1188  * The API selects respective JSON based on system IM, parse it and return the
1189  * JSON object. Empty JSON will be returned in case of any error. Caller needs
1190  * to handle empty value.
1191  *
1192  * @param[in] i_imValue - IM value of the system.
1193  * @param[out] o_errCode - to set error code in case of error.
1194  * @return Parsed JSON object, empty JSON otherwise.
1195  */
getPowerVsJson(const types::BinaryVector & i_imValue,uint16_t & o_errCode)1196 inline nlohmann::json getPowerVsJson(const types::BinaryVector& i_imValue,
1197                                      uint16_t& o_errCode)
1198 {
1199     o_errCode = 0;
1200     if (i_imValue.empty() || i_imValue.size() < 4)
1201     {
1202         o_errCode = error_code::INVALID_INPUT_PARAMETER;
1203         return nlohmann::json{};
1204     }
1205 
1206     if ((i_imValue.at(0) == constants::HEX_VALUE_50) &&
1207         (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1208         (i_imValue.at(2) == constants::HEX_VALUE_30))
1209     {
1210         nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1211             constants::power_vs_50003_json, o_errCode);
1212 
1213         if (o_errCode)
1214         {
1215             logging::logMessage(
1216                 "Failed to parse JSON file [ " +
1217                 std::string(constants::power_vs_50003_json) +
1218                 " ], error : " + commonUtility::getErrCodeMsg(o_errCode));
1219         }
1220 
1221         return l_parsedJson;
1222     }
1223     else if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
1224              (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1225              (i_imValue.at(2) == constants::HEX_VALUE_10))
1226     {
1227         nlohmann::json l_parsedJson = jsonUtility::getParsedJson(
1228             constants::power_vs_50001_json, o_errCode);
1229 
1230         if (o_errCode)
1231         {
1232             logging::logMessage(
1233                 "Failed to parse JSON file [ " +
1234                 std::string(constants::power_vs_50001_json) +
1235                 " ], error : " + commonUtility::getErrCodeMsg(o_errCode));
1236         }
1237 
1238         return l_parsedJson;
1239     }
1240     return nlohmann::json{};
1241 }
1242 
1243 /**
1244  * @brief API to get list of FRUs for which "monitorPresence" is true.
1245  *
1246  * @param[in] i_sysCfgJsonObj - System config JSON object.
1247  * @param[out] o_errCode - To set error code in case of error.
1248  *
1249  * @return On success, returns list of FRUs for which "monitorPresence" is true,
1250  * empty list on error.
1251  */
getFrusWithPresenceMonitoring(const nlohmann::json & i_sysCfgJsonObj,uint16_t & o_errCode)1252 inline std::vector<types::Path> getFrusWithPresenceMonitoring(
1253     const nlohmann::json& i_sysCfgJsonObj, uint16_t& o_errCode)
1254 {
1255     std::vector<types::Path> l_frusWithPresenceMonitoring;
1256     o_errCode = 0;
1257 
1258     if (!i_sysCfgJsonObj.contains("frus"))
1259     {
1260         o_errCode = error_code::INVALID_JSON;
1261         return l_frusWithPresenceMonitoring;
1262     }
1263 
1264     const nlohmann::json& l_listOfFrus =
1265         i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
1266 
1267     for (const auto& l_aFru : l_listOfFrus)
1268     {
1269         if (l_aFru.at(0).value("monitorPresence", false))
1270         {
1271             l_frusWithPresenceMonitoring.emplace_back(
1272                 l_aFru.at(0).value("inventoryPath", ""));
1273         }
1274     }
1275 
1276     return l_frusWithPresenceMonitoring;
1277 }
1278 
1279 /**
1280  * @brief API which tells if the FRU's presence is handled
1281  *
1282  * For a given FRU, this API checks if it's presence is handled by vpd-manager
1283  * by checking the "handlePresence" tag.
1284  *
1285  * @param[in] i_sysCfgJsonObj - System config JSON object.
1286  * @param[in] i_vpdFruPath - EEPROM path.
1287  * @param[out] o_errCode - To set error code in case of failure.
1288  *
1289  * @return true if FRU presence is handled, false otherwise.
1290  */
isFruPresenceHandled(const nlohmann::json & i_sysCfgJsonObj,const std::string & i_vpdFruPath,uint16_t & o_errCode)1291 inline bool isFruPresenceHandled(const nlohmann::json& i_sysCfgJsonObj,
1292                                  const std::string& i_vpdFruPath,
1293                                  uint16_t& o_errCode)
1294 {
1295     o_errCode = 0;
1296     if (i_vpdFruPath.empty())
1297     {
1298         o_errCode = error_code::INVALID_INPUT_PARAMETER;
1299         return false;
1300     }
1301 
1302     if (!i_sysCfgJsonObj.contains("frus"))
1303     {
1304         o_errCode = error_code::INVALID_JSON;
1305         return false;
1306     }
1307 
1308     if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1309     {
1310         o_errCode = error_code::FRU_PATH_NOT_FOUND;
1311         return false;
1312     }
1313 
1314     return i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0).value(
1315         "handlePresence", true);
1316 }
1317 } // namespace jsonUtility
1318 } // namespace vpd
1319