blob: e30d1f6c2d7852299b9c99ec2c5e21e16754b797 [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#pragma once
2
Rekha Aparna017567a2025-08-13 02:07:06 -05003#include "error_codes.hpp"
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05004#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
13#include <fstream>
14#include <type_traits>
15#include <unordered_map>
16
17namespace vpd
18{
19namespace jsonUtility
20{
21
22// forward declaration of API for function map.
23bool processSystemCmdTag(const nlohmann::json& i_parsedConfigJson,
24 const std::string& i_vpdFilePath,
25 const std::string& i_baseAction,
26 const std::string& i_flagToProcess);
27
28// forward declaration of API for function map.
29bool processGpioPresenceTag(
30 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
31 const std::string& i_baseAction, const std::string& i_flagToProcess);
32
33// forward declaration of API for function map.
34bool procesSetGpioTag(const nlohmann::json& i_parsedConfigJson,
35 const std::string& i_vpdFilePath,
36 const std::string& i_baseAction,
37 const std::string& i_flagToProcess);
38
39// Function pointers to process tags from config JSON.
40typedef 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
44inline std::unordered_map<std::string, functionPtr> funcionMap{
45 {"gpioPresence", processGpioPresenceTag},
46 {"setGpio", procesSetGpioTag},
47 {"systemCmd", processSystemCmdTag}};
48
49/**
50 * @brief API to read VPD offset from JSON file.
51 *
52 * @param[in] i_sysCfgJsonObj - Parsed system config JSON object.
53 * @param[in] i_vpdFilePath - VPD file path.
Rekha Aparna017567a2025-08-13 02:07:06 -050054 * @param[in] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050055 * @return VPD offset if found in JSON, 0 otherwise.
56 */
57inline size_t getVPDOffset(const nlohmann::json& i_sysCfgJsonObj,
Rekha Aparna017567a2025-08-13 02:07:06 -050058 const std::string& i_vpdFilePath,
59 uint16_t& o_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050060{
61 if (i_vpdFilePath.empty() || (i_sysCfgJsonObj.empty()) ||
62 (!i_sysCfgJsonObj.contains("frus")))
63 {
Rekha Aparna017567a2025-08-13 02:07:06 -050064 o_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050065 return 0;
66 }
67
68 if (i_sysCfgJsonObj["frus"].contains(i_vpdFilePath))
69 {
70 return i_sysCfgJsonObj["frus"][i_vpdFilePath].at(0).value("offset", 0);
71 }
72
73 const nlohmann::json& l_fruList =
74 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
75
76 for (const auto& l_fru : l_fruList.items())
77 {
78 const auto l_fruPath = l_fru.key();
79
80 // check if given path is redundant FRU path
81 if (i_vpdFilePath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
82 "redundantEeprom", ""))
83 {
84 // Return the offset of redundant EEPROM taken from JSON.
85 return i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("offset", 0);
86 }
87 }
88
89 return 0;
90}
91
92/**
93 * @brief API to parse respective JSON.
94 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050095 * @param[in] pathToJson - Path to JSON.
RekhaAparna011ef21002025-02-18 23:47:36 -060096 * @return on success parsed JSON. On failure empty JSON object.
97 *
98 * Note: Caller has to handle it in case an empty JSON object is received.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050099 */
RekhaAparna011ef21002025-02-18 23:47:36 -0600100inline nlohmann::json getParsedJson(const std::string& pathToJson) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500101{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500102 try
103 {
RekhaAparna011ef21002025-02-18 23:47:36 -0600104 if (pathToJson.empty())
105 {
106 throw std::runtime_error("Path to JSON is missing");
107 }
108
109 if (!std::filesystem::exists(pathToJson) ||
110 std::filesystem::is_empty(pathToJson))
111 {
Souvik Roy3e9f63c2025-04-23 06:28:17 -0500112 throw std::runtime_error(
113 "File does not exist or empty file: [" + pathToJson + "]");
RekhaAparna011ef21002025-02-18 23:47:36 -0600114 }
115
116 std::ifstream l_jsonFile(pathToJson);
117 if (!l_jsonFile)
118 {
119 throw std::runtime_error(
120 "Failed to access Json path = " + pathToJson);
121 }
122
123 return nlohmann::json::parse(l_jsonFile);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500124 }
RekhaAparna011ef21002025-02-18 23:47:36 -0600125 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500126 {
RekhaAparna011ef21002025-02-18 23:47:36 -0600127 logging::logMessage(
128 "Failed to parse JSON file, error: " + std::string(l_ex.what()));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500129 }
RekhaAparna011ef21002025-02-18 23:47:36 -0600130
131 return nlohmann::json{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500132}
133
134/**
135 * @brief Get inventory object path from system config JSON.
136 *
137 * Given either D-bus inventory path/FRU EEPROM path/redundant EEPROM path,
138 * this API returns D-bus inventory path if present in JSON.
139 *
140 * @param[in] i_sysCfgJsonObj - System config JSON object
141 * @param[in] i_vpdPath - Path to where VPD is stored.
Rekha Aparna017567a2025-08-13 02:07:06 -0500142 * @param[in] o_errCode - To set error code in case of error.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500143 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500144 * @return On success a valid path is returned, on failure an empty string is
RekhaAparna011ef21002025-02-18 23:47:36 -0600145 * returned.
146 *
147 * Note: Caller has to handle it in case an empty string is received.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500148 */
149inline std::string getInventoryObjPathFromJson(
Rekha Aparna017567a2025-08-13 02:07:06 -0500150 const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdPath,
151 uint16_t& o_errCode) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500152{
Rekha Aparna017567a2025-08-13 02:07:06 -0500153 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500154 {
Rekha Aparna017567a2025-08-13 02:07:06 -0500155 o_errCode = error_code::INVALID_INPUT_PARAMETER;
156 return std::string{};
RekhaAparna011ef21002025-02-18 23:47:36 -0600157 }
158
Rekha Aparna017567a2025-08-13 02:07:06 -0500159 if (!i_sysCfgJsonObj.contains("frus"))
160 {
161 o_errCode = error_code::INVALID_JSON;
162 return std::string{};
163 }
164
165 // check if given path is FRU path
166 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
167 {
168 return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value(
169 "inventoryPath", "");
170 }
171
172 const nlohmann::json& l_fruList =
173 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
174
175 for (const auto& l_fru : l_fruList.items())
176 {
177 const auto l_fruPath = l_fru.key();
178 const auto l_invObjPath =
179 i_sysCfgJsonObj["frus"][l_fruPath].at(0).value("inventoryPath", "");
180
181 // check if given path is redundant FRU path or inventory path
182 if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
183 "redundantEeprom", "") ||
184 (i_vpdPath == l_invObjPath))
185 {
186 return l_invObjPath;
187 }
188 }
189
190 return std::string{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500191}
192
193/**
194 * @brief Process "PostFailAction" defined in config JSON.
195 *
196 * In case there is some error in the processing of "preAction" execution and a
197 * set of procedure needs to be done as a part of post fail action. This base
198 * action can be defined in the config JSON for that FRU and it will be handled
199 * under this API.
200 *
201 * @param[in] i_parsedConfigJson - config JSON
202 * @param[in] i_vpdFilePath - EEPROM file path
203 * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed
204 * under PostFailAction tag of config JSON.
205 * @return - success or failure
206 */
207inline bool executePostFailAction(const nlohmann::json& i_parsedConfigJson,
208 const std::string& i_vpdFilePath,
209 const std::string& i_flagToProcess)
210{
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600211 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500212 {
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600213 if (i_parsedConfigJson.empty() || i_vpdFilePath.empty() ||
214 i_flagToProcess.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500215 {
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600216 throw std::runtime_error(
217 "Invalid parameters. Abort processing for post fail action");
218 }
219
220 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))["postFailAction"]
221 .contains(i_flagToProcess))
222 {
223 throw std::runtime_error(
224 "Config JSON missing flag " + i_flagToProcess +
225 " to execute post fail action for path = " + i_vpdFilePath);
226 }
227
228 for (const auto& l_tags : (i_parsedConfigJson["frus"][i_vpdFilePath].at(
229 0))["postFailAction"][i_flagToProcess]
230 .items())
231 {
232 auto itrToFunction = funcionMap.find(l_tags.key());
233 if (itrToFunction != funcionMap.end())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500234 {
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600235 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
236 "postFailAction", i_flagToProcess))
237 {
238 return false;
239 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500240 }
241 }
242 }
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600243 catch (const std::exception& l_ex)
244 {
245 logging::logMessage("Execute post fail action failed. Error : " +
246 std::string(l_ex.what()));
247 return false;
248 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500249
250 return true;
251}
252
253/**
254 * @brief Process "systemCmd" tag for a given FRU.
255 *
256 * The API will process "systemCmd" tag if it is defined in the config
257 * JSON for the given FRU.
258 *
259 * @param[in] i_parsedConfigJson - config JSON
260 * @param[in] i_vpdFilePath - EEPROM file path
261 * @param[in] i_baseAction - Base action for which this tag has been called.
262 * @param[in] i_flagToProcess - Flag nested under the base action for which this
263 * tag has been called.
264 * @return Execution status.
265 */
266inline bool processSystemCmdTag(
267 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
268 const std::string& i_baseAction, const std::string& i_flagToProcess)
269{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500270 try
271 {
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600272 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
273 i_baseAction.empty() || i_flagToProcess.empty())
274 {
275 throw std::runtime_error(
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530276 std::string(__FUNCTION__) +
277 " Invalid parameter. Abort processing of processSystemCmd.");
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600278 }
279
280 if (!((i_parsedConfigJson["frus"][i_vpdFilePath].at(
281 0)[i_baseAction][i_flagToProcess]["systemCmd"])
282 .contains("cmd")))
283 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530284 throw JsonException(
285 std::string(__FUNCTION__) +
286 " Config JSON missing required information to execute system command for EEPROM " +
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600287 i_vpdFilePath);
288 }
289
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500290 const std::string& l_systemCommand =
291 i_parsedConfigJson["frus"][i_vpdFilePath].at(
292 0)[i_baseAction][i_flagToProcess]["systemCmd"]["cmd"];
293
294 commonUtility::executeCmd(l_systemCommand);
295 return true;
296 }
RekhaAparna01c11e8b62025-02-20 00:34:35 -0600297 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500298 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530299 EventLogger::createSyncPel(
300 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
301 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
302 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500303 return false;
304 }
305}
306
307/**
308 * @brief Checks for presence of a given FRU using GPIO line.
309 *
310 * This API returns the presence information of the FRU corresponding to the
311 * given VPD file path by setting the presence pin.
312 *
313 * @param[in] i_parsedConfigJson - config JSON
314 * @param[in] i_vpdFilePath - EEPROM file path
315 * @param[in] i_baseAction - Base action for which this tag has been called.
316 * @param[in] i_flagToProcess - Flag nested under the base action for which this
317 * tag has been called.
318 * @return Execution status.
319 */
320inline bool processGpioPresenceTag(
321 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
322 const std::string& i_baseAction, const std::string& i_flagToProcess)
323{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530324 std::string l_presencePinName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500325 try
326 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530327 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
328 i_baseAction.empty() || i_flagToProcess.empty())
329 {
330 throw std::runtime_error(
331 std::string(__FUNCTION__) +
332 "Invalid parameter. Abort processing of processGpioPresence tag");
333 }
334
335 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
336 0)[i_baseAction][i_flagToProcess]["gpioPresence"])
337 .contains("pin")) &&
338 ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
339 0)[i_baseAction][i_flagToProcess]["gpioPresence"])
340 .contains("value"))))
341 {
342 throw JsonException(
343 std::string(__FUNCTION__) +
344 "Config JSON missing required information to detect presence for EEPROM " +
345 i_vpdFilePath);
346 }
347
348 // get the pin name
349 l_presencePinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
350 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["pin"];
351
352 // get the pin value
353 uint8_t l_presencePinValue =
354 i_parsedConfigJson["frus"][i_vpdFilePath].at(
355 0)[i_baseAction][i_flagToProcess]["gpioPresence"]["value"];
356
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500357 gpiod::line l_presenceLine = gpiod::find_line(l_presencePinName);
358
359 if (!l_presenceLine)
360 {
361 throw GpioException("Couldn't find the GPIO line.");
362 }
363
364 l_presenceLine.request({"Read the presence line",
365 gpiod::line_request::DIRECTION_INPUT, 0});
366
367 return (l_presencePinValue == l_presenceLine.get_value());
368 }
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530369 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500370 {
Sunny Srivastavac09e2102025-04-23 10:47:06 +0530371 // No need to continue in case of JSON failure or Firmware error
372 // as these are errors internal to the code and in that case the FRU
373 // should not be processed. Any other error is considered as external
374 // error in this case and a try to read the EEPROM should be done.
375 if (EventLogger::getErrorType(l_ex) == types::ErrorType::JsonFailure ||
376 EventLogger::getErrorType(l_ex) == types::ErrorType::FirmwareError)
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530377 {
378 EventLogger::createSyncPel(
379 EventLogger::getErrorType(l_ex),
380 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
381 EventLogger::getErrorMsg(l_ex), std::nullopt, std::nullopt,
382 std::nullopt, std::nullopt);
383 return false;
384 }
385
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500386 std::string l_errMsg = "Exception on GPIO line: ";
387 l_errMsg += l_presencePinName;
388 l_errMsg += " Reason: ";
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530389 l_errMsg += l_ex.what();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500390 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
391
Rekha Aparna017567a2025-08-13 02:07:06 -0500392 uint16_t l_errCode = 0;
393
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500394 // ToDo -- Update Internal Rc code.
395 EventLogger::createAsyncPelWithInventoryCallout(
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530396 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
Rekha Aparna017567a2025-08-13 02:07:06 -0500397 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
398 l_errCode),
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500399 types::CalloutPriority::High}},
400 std::source_location::current().file_name(),
401 std::source_location::current().function_name(), 0, l_errMsg,
402 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
403
404 logging::logMessage(l_errMsg);
405
406 // Except when GPIO pin value is false, we go and try collecting the
407 // FRU VPD as we couldn't able to read GPIO pin value due to some
408 // error/exception. So returning true in error scenario.
409 return true;
410 }
411}
412
413/**
414 * @brief Process "setGpio" tag for a given FRU.
415 *
416 * This API enables the GPIO line.
417 *
418 * @param[in] i_parsedConfigJson - config JSON
419 * @param[in] i_vpdFilePath - EEPROM file path
420 * @param[in] i_baseAction - Base action for which this tag has been called.
421 * @param[in] i_flagToProcess - Flag nested under the base action for which this
422 * tag has been called.
423 * @return Execution status.
424 */
425inline bool procesSetGpioTag(
426 const nlohmann::json& i_parsedConfigJson, const std::string& i_vpdFilePath,
427 const std::string& i_baseAction, const std::string& i_flagToProcess)
428{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530429 std::string l_pinName;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500430 try
431 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530432 if (i_vpdFilePath.empty() || i_parsedConfigJson.empty() ||
433 i_baseAction.empty() || i_flagToProcess.empty())
434 {
435 throw std::runtime_error(
436 std::string(__FUNCTION__) +
437 " Invalid parameter. Abort processing of procesSetGpio.");
438 }
439
440 if (!(((i_parsedConfigJson["frus"][i_vpdFilePath].at(
441 0)[i_baseAction][i_flagToProcess]["setGpio"])
442 .contains("pin")) &&
443 ((i_parsedConfigJson["frus"][i_vpdFilePath].at(
444 0)[i_baseAction][i_flagToProcess]["setGpio"])
445 .contains("value"))))
446 {
447 throw JsonException(
448 std::string(__FUNCTION__) +
449 " Config JSON missing required information to set gpio line for EEPROM " +
450 i_vpdFilePath);
451 }
452
453 l_pinName = i_parsedConfigJson["frus"][i_vpdFilePath].at(
454 0)[i_baseAction][i_flagToProcess]["setGpio"]["pin"];
455
456 // Get the value to set
457 uint8_t l_pinValue = i_parsedConfigJson["frus"][i_vpdFilePath].at(
458 0)[i_baseAction][i_flagToProcess]["setGpio"]["value"];
459
460 logging::logMessage(
461 "Setting GPIO: " + l_pinName + " to " + std::to_string(l_pinValue));
462
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500463 gpiod::line l_outputLine = gpiod::find_line(l_pinName);
464
465 if (!l_outputLine)
466 {
467 throw GpioException("Couldn't find GPIO line.");
468 }
469
470 l_outputLine.request(
471 {"FRU Action", ::gpiod::line_request::DIRECTION_OUTPUT, 0},
472 l_pinValue);
473 return true;
474 }
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530475 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500476 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530477 if (EventLogger::getErrorType(l_ex) != types::ErrorType::GpioError)
478 {
479 EventLogger::createSyncPel(
480 EventLogger::getErrorType(l_ex),
481 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
482 EventLogger::getErrorMsg(l_ex), std::nullopt, std::nullopt,
483 std::nullopt, std::nullopt);
484 }
485 else
486 {
487 std::string l_errMsg = "Exception on GPIO line: ";
488 l_errMsg += l_pinName;
489 l_errMsg += " Reason: ";
490 l_errMsg += l_ex.what();
491 l_errMsg += " File: " + i_vpdFilePath + " Pel Logged";
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500492
Rekha Aparna017567a2025-08-13 02:07:06 -0500493 uint16_t l_errCode = 0;
494
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530495 // ToDo -- Update Internal RC code
496 EventLogger::createAsyncPelWithInventoryCallout(
497 EventLogger::getErrorType(l_ex),
498 types::SeverityType::Informational,
Rekha Aparna017567a2025-08-13 02:07:06 -0500499 {{getInventoryObjPathFromJson(i_parsedConfigJson, i_vpdFilePath,
500 l_errCode),
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530501 types::CalloutPriority::High}},
502 std::source_location::current().file_name(),
503 std::source_location::current().function_name(), 0, l_errMsg,
504 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500505
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530506 logging::logMessage(l_errMsg);
507 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500508
509 return false;
510 }
511}
512
513/**
514 * @brief Process any action, if defined in config JSON.
515 *
516 * If any FRU(s) requires any special handling, then this base action can be
517 * defined for that FRU in the config JSON, processing of which will be handled
518 * in this API.
519 * Examples of action - preAction, PostAction etc.
520 *
521 * @param[in] i_parsedConfigJson - config JSON
522 * @param[in] i_action - Base action to be performed.
523 * @param[in] i_vpdFilePath - EEPROM file path
524 * @param[in] i_flagToProcess - To identify which flag(s) needs to be processed
525 * under PreAction tag of config JSON.
526 * @return - success or failure
527 */
528inline bool executeBaseAction(
529 const nlohmann::json& i_parsedConfigJson, const std::string& i_action,
530 const std::string& i_vpdFilePath, const std::string& i_flagToProcess)
531{
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530532 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500533 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530534 if (i_flagToProcess.empty() || i_action.empty() ||
535 i_vpdFilePath.empty() || !i_parsedConfigJson.contains("frus"))
536 {
537 throw std::runtime_error(
538 std::string(__FUNCTION__) + " Invalid parameter");
539 }
540
541 if (!i_parsedConfigJson["frus"].contains(i_vpdFilePath))
542 {
543 throw JsonException(std::string(__FUNCTION__) + " File path: " +
544 i_vpdFilePath + " not found in JSON");
545 }
546
547 if (!i_parsedConfigJson["frus"][i_vpdFilePath].at(0).contains(i_action))
548 {
549 throw JsonException(
550 std::string(__FUNCTION__) + " Action [" + i_action +
551 "] not defined for file path:" + i_vpdFilePath);
552 }
553
554 if (!(i_parsedConfigJson["frus"][i_vpdFilePath].at(0))[i_action]
555 .contains(i_flagToProcess))
556 {
557 throw JsonException(
558 std::string(__FUNCTION__) + "Config JSON missing flag [" +
559 i_flagToProcess +
560 "] to execute action for path = " + i_vpdFilePath);
561 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500562 }
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530563 catch (const std::exception& l_ex)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500564 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +0530565 EventLogger::createSyncPel(
566 EventLogger::getErrorType(l_ex), types::SeverityType::Informational,
567 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
568 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500569 return false;
570 }
571
572 const nlohmann::json& l_tagsJson =
573 (i_parsedConfigJson["frus"][i_vpdFilePath].at(
574 0))[i_action][i_flagToProcess];
575
576 for (const auto& l_tag : l_tagsJson.items())
577 {
578 auto itrToFunction = funcionMap.find(l_tag.key());
579 if (itrToFunction != funcionMap.end())
580 {
581 if (!itrToFunction->second(i_parsedConfigJson, i_vpdFilePath,
582 i_action, i_flagToProcess))
583 {
584 // In case any of the tag fails to execute. Mark action
585 // as failed for that flag.
586 return false;
587 }
588 }
589 }
590
591 return true;
592}
593
594/**
595 * @brief Get redundant FRU path from system config JSON
596 *
597 * Given either D-bus inventory path/FRU path/redundant FRU path, this
598 * API returns the redundant FRU path taken from "redundantEeprom" tag from
599 * system config JSON.
600 *
601 * @param[in] i_sysCfgJsonObj - System config JSON object.
602 * @param[in] i_vpdPath - Path to where VPD is stored.
603 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500604 * @return On success return valid path, on failure return empty string.
605 */
606inline std::string getRedundantEepromPathFromJson(
RekhaAparna017fea9f52025-02-17 04:14:02 -0600607 const nlohmann::json& i_sysCfgJsonObj,
608 const std::string& i_vpdPath) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500609{
RekhaAparna017fea9f52025-02-17 04:14:02 -0600610 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500611 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600612 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500613 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600614 throw std::runtime_error("Path parameter is empty.");
615 }
616
617 if (!i_sysCfgJsonObj.contains("frus"))
618 {
619 throw std::runtime_error("Missing frus tag in system config JSON.");
620 }
621
622 // check if given path is FRU path
623 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
624 {
625 return i_sysCfgJsonObj["frus"][i_vpdPath].at(0).value(
626 "redundantEeprom", "");
627 }
628
629 const nlohmann::json& l_fruList =
630 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
631
632 for (const auto& l_fru : l_fruList.items())
633 {
634 const std::string& l_fruPath = l_fru.key();
635 const std::string& l_redundantFruPath =
636 i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
637 "redundantEeprom", "");
638
639 // check if given path is inventory path or redundant FRU path
640 if ((i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
641 "inventoryPath", "") == i_vpdPath) ||
642 (l_redundantFruPath == i_vpdPath))
643 {
644 return l_redundantFruPath;
645 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500646 }
647 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600648 catch (const std::exception& l_ex)
649 {
650 logging::logMessage("Failed to get redundant EEPROM path, error: " +
651 std::string(l_ex.what()));
652 }
653
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500654 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 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500666 * @return On success return valid path, on failure return empty string.
667 */
668inline std::string getFruPathFromJson(const nlohmann::json& i_sysCfgJsonObj,
RekhaAparna017fea9f52025-02-17 04:14:02 -0600669 const std::string& i_vpdPath) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500670{
RekhaAparna017fea9f52025-02-17 04:14:02 -0600671 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500672 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600673 if (i_vpdPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500674 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600675 throw std::runtime_error("Path parameter is empty.");
676 }
677
678 if (!i_sysCfgJsonObj.contains("frus"))
679 {
680 throw std::runtime_error("Missing frus tag in system config JSON.");
681 }
682
683 // check if given path is FRU path
684 if (i_sysCfgJsonObj["frus"].contains(i_vpdPath))
685 {
686 return i_vpdPath;
687 }
688
689 const nlohmann::json& l_fruList =
690 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
691
692 for (const auto& l_fru : l_fruList.items())
693 {
694 const auto l_fruPath = l_fru.key();
695
696 // check if given path is redundant FRU path or inventory path
697 if (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
698 "redundantEeprom", "") ||
699 (i_vpdPath == i_sysCfgJsonObj["frus"][l_fruPath].at(0).value(
700 "inventoryPath", "")))
701 {
702 return l_fruPath;
703 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500704 }
705 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600706 catch (const std::exception& l_ex)
707 {
708 logging::logMessage("Failed to get FRU path from JSON, error: " +
709 std::string(l_ex.what()));
710 }
711
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500712 return std::string();
713}
714
715/**
716 * @brief An API to check backup and restore VPD is required.
717 *
718 * The API checks if there is provision for backup and restore mentioned in the
719 * system config JSON, by looking "backupRestoreConfigPath" tag.
720 * Checks if the path mentioned is a hardware path, by checking if the file path
721 * exists and size of contents in the path.
722 *
723 * @param[in] i_sysCfgJsonObj - System config JSON object.
724 *
725 * @return true if backup and restore is required, false otherwise.
726 */
727inline bool isBackupAndRestoreRequired(const nlohmann::json& i_sysCfgJsonObj)
728{
729 try
730 {
731 const std::string& l_backupAndRestoreCfgFilePath =
732 i_sysCfgJsonObj.value("backupRestoreConfigPath", "");
733 if (!l_backupAndRestoreCfgFilePath.empty() &&
734 std::filesystem::exists(l_backupAndRestoreCfgFilePath) &&
735 !std::filesystem::is_empty(l_backupAndRestoreCfgFilePath))
736 {
737 return true;
738 }
739 }
740 catch (std::exception& ex)
741 {
742 logging::logMessage(ex.what());
743 }
744 return false;
745}
746
747/** @brief API to check if an action is required for given EEPROM path.
748 *
749 * System config JSON can contain pre-action, post-action etc. like actions
750 * defined for an EEPROM path. The API will check if any such action is defined
751 * for the EEPROM.
752 *
753 * @param[in] i_sysCfgJsonObj - System config JSON object.
754 * @param[in] i_vpdFruPath - EEPROM path.
755 * @param[in] i_action - Action to be checked.
756 * @param[in] i_flowFlag - Denotes the flow w.r.t which the action should be
757 * triggered.
758 * @return - True if action is defined for the flow, false otherwise.
759 */
760inline bool isActionRequired(
761 const nlohmann::json& i_sysCfgJsonObj, const std::string& i_vpdFruPath,
762 const std::string& i_action, const std::string& i_flowFlag)
763{
764 if (i_vpdFruPath.empty() || i_action.empty() || i_flowFlag.empty())
765 {
766 logging::logMessage("Invalid parameters recieved.");
767 return false;
768 }
769
770 if (!i_sysCfgJsonObj.contains("frus"))
771 {
772 logging::logMessage("Invalid JSON object recieved.");
773 return false;
774 }
775
776 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
777 {
778 logging::logMessage(
779 "JSON object does not contain EEPROM path " + i_vpdFruPath);
780 return false;
781 }
782
783 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)).contains(i_action))
784 {
785 if ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))[i_action].contains(
786 i_flowFlag))
787 {
788 return true;
789 }
790
791 logging::logMessage("Flow flag: [" + i_flowFlag +
Souvik Roy410d96c2025-05-09 02:30:15 -0500792 "], not found in JSON for path: " + i_vpdFruPath +
793 " while checking for action: " + i_action);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500794 return false;
795 }
796 return false;
797}
798
799/**
800 * @brief An API to return list of FRUs that needs GPIO polling.
801 *
802 * An API that checks for the FRUs that requires GPIO polling and returns
803 * a list of FRUs that needs polling. Returns an empty list if there are
804 * no FRUs that requires polling.
805 *
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500806 * @param[in] i_sysCfgJsonObj - System config JSON object.
807 *
RekhaAparna017fea9f52025-02-17 04:14:02 -0600808 * @return On success list of FRUs parameters that needs polling. On failure,
809 * empty list.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500810 */
Patrick Williams43fedab2025-02-03 14:28:05 -0500811inline std::vector<std::string> getListOfGpioPollingFrus(
RekhaAparna017fea9f52025-02-17 04:14:02 -0600812 const nlohmann::json& i_sysCfgJsonObj) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500813{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500814 std::vector<std::string> l_gpioPollingRequiredFrusList;
815
RekhaAparna017fea9f52025-02-17 04:14:02 -0600816 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500817 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600818 if (i_sysCfgJsonObj.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500819 {
RekhaAparna017fea9f52025-02-17 04:14:02 -0600820 throw std::runtime_error("Invalid Parameters");
821 }
822
823 if (!i_sysCfgJsonObj.contains("frus"))
824 {
825 throw std::runtime_error(
826 "Missing frus section in system config JSON");
827 }
828
829 for (const auto& l_fru : i_sysCfgJsonObj["frus"].items())
830 {
831 const auto l_fruPath = l_fru.key();
832
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500833 if (isActionRequired(i_sysCfgJsonObj, l_fruPath, "pollingRequired",
834 "hotPlugging"))
835 {
836 if (i_sysCfgJsonObj["frus"][l_fruPath]
837 .at(0)["pollingRequired"]["hotPlugging"]
838 .contains("gpioPresence"))
839 {
840 l_gpioPollingRequiredFrusList.push_back(l_fruPath);
841 }
842 }
843 }
RekhaAparna017fea9f52025-02-17 04:14:02 -0600844 }
845 catch (const std::exception& l_ex)
846 {
847 logging::logMessage("Failed to get list of GPIO polling FRUs, error: " +
848 std::string(l_ex.what()));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500849 }
850
851 return l_gpioPollingRequiredFrusList;
852}
853
854/**
855 * @brief Get all related path(s) to update keyword value.
856 *
857 * Given FRU EEPROM path/Inventory path needs keyword's value update, this API
858 * returns tuple of FRU EEPROM path, inventory path and redundant EEPROM path if
859 * exists in the system config JSON.
860 *
861 * Note: If the inventory object path or redundant EEPROM path(s) are not found
862 * in the system config JSON, corresponding fields will have empty value in the
863 * returning tuple.
864 *
865 * @param[in] i_sysCfgJsonObj - System config JSON object.
866 * @param[in,out] io_vpdPath - Inventory object path or FRU EEPROM path.
867 *
868 * @return On success returns tuple of EEPROM path, inventory path & redundant
869 * path, on failure returns tuple with given input path alone.
870 */
871inline std::tuple<std::string, std::string, std::string>
872 getAllPathsToUpdateKeyword(const nlohmann::json& i_sysCfgJsonObj,
873 std::string io_vpdPath)
874{
875 types::Path l_inventoryObjPath;
876 types::Path l_redundantFruPath;
877 try
878 {
879 if (!i_sysCfgJsonObj.empty())
880 {
881 // Get hardware path from system config JSON.
882 const types::Path l_fruPath =
883 jsonUtility::getFruPathFromJson(i_sysCfgJsonObj, io_vpdPath);
884
885 if (!l_fruPath.empty())
886 {
887 io_vpdPath = l_fruPath;
888
Rekha Aparna017567a2025-08-13 02:07:06 -0500889 uint16_t l_errCode = 0;
890
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500891 // Get inventory object path from system config JSON
892 l_inventoryObjPath = jsonUtility::getInventoryObjPathFromJson(
Rekha Aparna017567a2025-08-13 02:07:06 -0500893 i_sysCfgJsonObj, l_fruPath, l_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500894
895 // Get redundant hardware path if present in system config JSON
896 l_redundantFruPath =
897 jsonUtility::getRedundantEepromPathFromJson(i_sysCfgJsonObj,
898 l_fruPath);
899 }
900 }
901 }
902 catch (const std::exception& l_exception)
903 {
904 logging::logMessage(
905 "Failed to get all paths to update keyword value, error " +
906 std::string(l_exception.what()));
907 }
908 return std::make_tuple(io_vpdPath, l_inventoryObjPath, l_redundantFruPath);
909}
910
911/**
912 * @brief An API to get DBus service name.
913 *
914 * Given DBus inventory path, this API returns DBus service name if present in
915 * the JSON.
916 *
917 * @param[in] i_sysCfgJsonObj - System config JSON object.
918 * @param[in] l_inventoryPath - DBus inventory path.
919 *
920 * @return On success returns the service name present in the system config
921 * JSON, otherwise empty string.
922 *
923 * Note: Caller has to handle in case of empty string received.
924 */
925inline std::string getServiceName(const nlohmann::json& i_sysCfgJsonObj,
926 const std::string& l_inventoryPath)
927{
928 try
929 {
930 if (l_inventoryPath.empty())
931 {
932 throw std::runtime_error("Path parameter is empty.");
933 }
934
935 if (!i_sysCfgJsonObj.contains("frus"))
936 {
937 throw std::runtime_error("Missing frus tag in system config JSON.");
938 }
939
940 const nlohmann::json& l_listOfFrus =
941 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
942
943 for (const auto& l_frus : l_listOfFrus.items())
944 {
945 for (const auto& l_inventoryItem : l_frus.value())
946 {
947 if (l_inventoryPath.compare(l_inventoryItem["inventoryPath"]) ==
948 constants::STR_CMP_SUCCESS)
949 {
950 return l_inventoryItem["serviceName"];
951 }
952 }
953 }
954 throw std::runtime_error(
955 "Inventory path not found in the system config JSON");
956 }
957 catch (const std::exception& l_exception)
958 {
959 logging::logMessage(
960 "Error while getting DBus service name for given path " +
961 l_inventoryPath + ", error: " + std::string(l_exception.what()));
962 // TODO:log PEL
963 }
964 return std::string{};
965}
966
967/**
968 * @brief An API to check if a FRU is tagged as "powerOffOnly"
969 *
970 * Given the system config JSON and VPD FRU path, this API checks if the FRU
971 * VPD can be collected at Chassis Power Off state only.
972 *
973 * @param[in] i_sysCfgJsonObj - System config JSON object.
974 * @param[in] i_vpdFruPath - EEPROM path.
975 * @return - True if FRU VPD can be collected at Chassis Power Off state only.
976 * False otherwise
977 */
978inline bool isFruPowerOffOnly(const nlohmann::json& i_sysCfgJsonObj,
979 const std::string& i_vpdFruPath)
980{
981 if (i_vpdFruPath.empty())
982 {
983 logging::logMessage("FRU path is empty.");
984 return false;
985 }
986
987 if (!i_sysCfgJsonObj.contains("frus"))
988 {
989 logging::logMessage("Missing frus tag in system config JSON.");
990 return false;
991 }
992
993 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
994 {
995 logging::logMessage("JSON object does not contain EEPROM path \'" +
996 i_vpdFruPath + "\'");
997 return false;
998 }
999
1000 return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1001 .contains("powerOffOnly") &&
1002 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0)["powerOffOnly"]));
1003}
1004
1005/**
1006 * @brief API which tells if the FRU is replaceable at runtime
1007 *
1008 * @param[in] i_sysCfgJsonObj - System config JSON object.
1009 * @param[in] i_vpdFruPath - EEPROM path.
1010 *
1011 * @return true if FRU is replaceable at runtime. false otherwise.
1012 */
1013inline bool isFruReplaceableAtRuntime(const nlohmann::json& i_sysCfgJsonObj,
1014 const std::string& i_vpdFruPath)
1015{
1016 try
1017 {
1018 if (i_vpdFruPath.empty())
1019 {
1020 throw std::runtime_error("Given FRU path is empty.");
1021 }
1022
1023 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
1024 {
1025 throw std::runtime_error("Invalid system config JSON object.");
1026 }
1027
1028 return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1029 .contains("replaceableAtRuntime") &&
1030 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(
1031 0)["replaceableAtRuntime"]));
1032 }
1033 catch (const std::exception& l_error)
1034 {
1035 // TODO: Log PEL
1036 logging::logMessage(l_error.what());
1037 }
1038
1039 return false;
1040}
1041
1042/**
1043 * @brief API which tells if the FRU is replaceable at standby
1044 *
1045 * @param[in] i_sysCfgJsonObj - System config JSON object.
1046 * @param[in] i_vpdFruPath - EEPROM path.
1047 *
1048 * @return true if FRU is replaceable at standby. false otherwise.
1049 */
1050inline bool isFruReplaceableAtStandby(const nlohmann::json& i_sysCfgJsonObj,
1051 const std::string& i_vpdFruPath)
1052{
1053 try
1054 {
1055 if (i_vpdFruPath.empty())
1056 {
1057 throw std::runtime_error("Given FRU path is empty.");
1058 }
1059
1060 if (i_sysCfgJsonObj.empty() || (!i_sysCfgJsonObj.contains("frus")))
1061 {
1062 throw std::runtime_error("Invalid system config JSON object.");
1063 }
1064
1065 return ((i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0))
1066 .contains("replaceableAtStandby") &&
1067 (i_sysCfgJsonObj["frus"][i_vpdFruPath].at(
1068 0)["replaceableAtStandby"]));
1069 }
1070 catch (const std::exception& l_error)
1071 {
1072 // TODO: Log PEL
1073 logging::logMessage(l_error.what());
1074 }
1075
1076 return false;
1077}
1078
1079/**
1080 * @brief API to get list of FRUs replaceable at standby from JSON.
1081 *
1082 * The API will return a vector of FRUs inventory path which are replaceable at
1083 * standby.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001084 *
1085 * @param[in] i_sysCfgJsonObj - System config JSON object.
1086 *
RekhaAparna017fea9f52025-02-17 04:14:02 -06001087 * @return - On success, list of FRUs replaceable at standby. On failure, empty
1088 * vector.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001089 */
Patrick Williams43fedab2025-02-03 14:28:05 -05001090inline std::vector<std::string> getListOfFrusReplaceableAtStandby(
RekhaAparna017fea9f52025-02-17 04:14:02 -06001091 const nlohmann::json& i_sysCfgJsonObj) noexcept
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001092{
1093 std::vector<std::string> l_frusReplaceableAtStandby;
1094
RekhaAparna017fea9f52025-02-17 04:14:02 -06001095 try
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001096 {
RekhaAparna017fea9f52025-02-17 04:14:02 -06001097 if (!i_sysCfgJsonObj.contains("frus"))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001098 {
RekhaAparna017fea9f52025-02-17 04:14:02 -06001099 throw std::runtime_error("Missing frus tag in system config JSON.");
1100 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001101
RekhaAparna017fea9f52025-02-17 04:14:02 -06001102 const nlohmann::json& l_fruList =
1103 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
1104
1105 for (const auto& l_fru : l_fruList.items())
1106 {
1107 if (i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1108 "replaceableAtStandby", false))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001109 {
RekhaAparna017fea9f52025-02-17 04:14:02 -06001110 const std::string& l_inventoryObjectPath =
1111 i_sysCfgJsonObj["frus"][l_fru.key()].at(0).value(
1112 "inventoryPath", "");
1113
1114 if (!l_inventoryObjectPath.empty())
1115 {
1116 l_frusReplaceableAtStandby.emplace_back(
1117 l_inventoryObjectPath);
1118 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001119 }
1120 }
1121 }
RekhaAparna017fea9f52025-02-17 04:14:02 -06001122 catch (const std::exception& l_ex)
1123 {
1124 logging::logMessage(
1125 "Failed to get list of FRUs replaceable at standby, error: " +
1126 std::string(l_ex.what()));
1127 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001128
1129 return l_frusReplaceableAtStandby;
1130}
1131
Sunny Srivastava022112b2025-02-19 19:53:29 +05301132/**
1133 * @brief API to select powerVS JSON based on system IM.
1134 *
1135 * The API selects respective JSON based on system IM, parse it and return the
1136 * JSON object. Empty JSON will be returned in case of any error. Caller needs
1137 * to handle empty value.
1138 *
1139 * @param[in] i_imValue - IM value of the system.
1140 * @return Parsed JSON object, empty JSON otherwise.
1141 */
1142inline nlohmann::json getPowerVsJson(const types::BinaryVector& i_imValue)
1143{
1144 try
1145 {
1146 if ((i_imValue.at(0) == constants::HEX_VALUE_50) &&
1147 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1148 (i_imValue.at(2) == constants::HEX_VALUE_30))
1149 {
1150 return jsonUtility::getParsedJson(constants::power_vs_50003_json);
1151 }
1152 else if (i_imValue.at(0) == constants::HEX_VALUE_50 &&
1153 (i_imValue.at(1) == constants::HEX_VALUE_00) &&
1154 (i_imValue.at(2) == constants::HEX_VALUE_10))
1155 {
1156 return jsonUtility::getParsedJson(constants::power_vs_50001_json);
1157 }
1158 return nlohmann::json{};
1159 }
1160 catch (const std::exception& l_ex)
1161 {
1162 return nlohmann::json{};
1163 }
1164}
Souvik Roy495eedd2025-07-02 02:13:43 -05001165
1166/**
1167 * @brief API to get list of FRUs for which "monitorPresence" is true.
1168 *
1169 * @param[in] i_sysCfgJsonObj - System config JSON object.
1170 *
1171 * @return On success, returns list of FRUs for which "monitorPresence" is true,
1172 * empty list on error.
1173 */
1174inline std::vector<types::Path> getFrusWithPresenceMonitoring(
1175 const nlohmann::json& i_sysCfgJsonObj) noexcept
1176{
1177 std::vector<types::Path> l_frusWithPresenceMonitoring;
1178 try
1179 {
1180 if (!i_sysCfgJsonObj.contains("frus"))
1181 {
1182 throw JsonException("Missing frus tag in system config JSON.");
1183 }
1184
1185 const nlohmann::json& l_listOfFrus =
1186 i_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
1187
1188 for (const auto& l_aFru : l_listOfFrus)
1189 {
1190 if (l_aFru.at(0).value("monitorPresence", false))
1191 {
1192 l_frusWithPresenceMonitoring.emplace_back(
1193 l_aFru.at(0).value("inventoryPath", ""));
1194 }
1195 }
1196 }
1197 catch (const std::exception& l_ex)
1198 {
1199 logging::logMessage(
1200 "Failed to get list of FRUs with presence monitoring, error: " +
1201 std::string(l_ex.what()));
1202 }
1203 return l_frusWithPresenceMonitoring;
1204}
Souvik Roye9120152025-07-02 08:24:38 -05001205
1206/**
1207 * @brief API which tells if the FRU's presence is handled
1208 *
1209 * For a given FRU, this API checks if it's presence is handled by vpd-manager
1210 * by checking the "handlePresence" tag.
1211 *
1212 * @param[in] i_sysCfgJsonObj - System config JSON object.
1213 * @param[in] i_vpdFruPath - EEPROM path.
1214 *
1215 * @return true if FRU presence is handled, false otherwise.
1216 */
1217inline bool isFruPresenceHandled(const nlohmann::json& i_sysCfgJsonObj,
1218 const std::string& i_vpdFruPath)
1219{
1220 try
1221 {
1222 if (i_vpdFruPath.empty())
1223 {
1224 throw std::runtime_error("Given FRU path is empty.");
1225 }
1226
1227 if (!i_sysCfgJsonObj.contains("frus"))
1228 {
1229 throw JsonException("Invalid system config JSON object.");
1230 }
1231
1232 if (!i_sysCfgJsonObj["frus"].contains(i_vpdFruPath))
1233 {
1234 logging::logMessage(
1235 "JSON object does not contain EEPROM path " + i_vpdFruPath);
1236 return false;
1237 }
1238
1239 return i_sysCfgJsonObj["frus"][i_vpdFruPath].at(0).value(
1240 "handlePresence", true);
1241 }
1242 catch (const std::exception& l_ex)
1243 {
1244 logging::logMessage(
1245 "Failed to check if FRU's presence is handled, reason:" +
1246 std::string(l_ex.what()));
1247 }
1248
1249 return false;
1250}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001251} // namespace jsonUtility
1252} // namespace vpd