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