blob: 373883b7885855b61d1efc592252bea8d229ee16 [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#include "config.h"
2
3#include "worker.hpp"
4
5#include "backup_restore.hpp"
6#include "configuration.hpp"
7#include "constants.hpp"
8#include "event_logger.hpp"
9#include "exceptions.hpp"
10#include "logger.hpp"
11#include "parser.hpp"
12#include "parser_factory.hpp"
13#include "parser_interface.hpp"
14
Rekha Aparnac6159a22025-10-09 12:20:20 +053015#include <utility/common_utility.hpp>
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050016#include <utility/dbus_utility.hpp>
17#include <utility/json_utility.hpp>
18#include <utility/vpd_specific_utility.hpp>
19
20#include <filesystem>
21#include <fstream>
22#include <future>
23#include <typeindex>
24#include <unordered_set>
25
26namespace vpd
27{
28
Sunny Srivastava765cf7b2025-02-04 05:24:11 -060029Worker::Worker(std::string pathToConfigJson, uint8_t i_maxThreadCount) :
30 m_configJsonPath(pathToConfigJson), m_semaphore(i_maxThreadCount)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050031{
32 // Implies the processing is based on some config JSON
33 if (!m_configJsonPath.empty())
34 {
35 // Check if symlink is already there to confirm fresh boot/factory
36 // reset.
37 if (std::filesystem::exists(INVENTORY_JSON_SYM_LINK))
38 {
39 logging::logMessage("Sym Link already present");
40 m_configJsonPath = INVENTORY_JSON_SYM_LINK;
41 m_isSymlinkPresent = true;
42 }
43
44 try
45 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -050046 uint16_t l_errCode = 0;
47 m_parsedJson =
48 jsonUtility::getParsedJson(m_configJsonPath, l_errCode);
49
50 if (l_errCode)
51 {
52 throw std::runtime_error(
53 "JSON parsing failed for file [ " + m_configJsonPath +
Rekha Aparnac6159a22025-10-09 12:20:20 +053054 " ], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaca9a0862025-08-29 04:08:33 -050055 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050056
57 // check for mandatory fields at this point itself.
58 if (!m_parsedJson.contains("frus"))
59 {
60 throw std::runtime_error("Mandatory tag(s) missing from JSON");
61 }
62 }
63 catch (const std::exception& ex)
64 {
65 throw(JsonException(ex.what(), m_configJsonPath));
66 }
67 }
68 else
69 {
70 logging::logMessage("Processing in not based on any config JSON");
71 }
72}
73
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050074static std::string readFitConfigValue()
75{
76 std::vector<std::string> output =
77 commonUtility::executeCmd("/sbin/fw_printenv");
78 std::string fitConfigValue;
79
80 for (const auto& entry : output)
81 {
82 auto pos = entry.find("=");
83 auto key = entry.substr(0, pos);
84 if (key != "fitconfig")
85 {
86 continue;
87 }
88
89 if (pos + 1 < entry.size())
90 {
91 fitConfigValue = entry.substr(pos + 1);
92 }
93 }
94
95 return fitConfigValue;
96}
97
98bool Worker::isSystemVPDOnDBus() const
99{
100 const std::string& mboardPath =
101 m_parsedJson["frus"][SYSTEM_VPD_FILE_PATH].at(0).value(
102 "inventoryPath", "");
103
104 if (mboardPath.empty())
105 {
106 throw JsonException("System vpd file path missing in JSON",
107 INVENTORY_JSON_SYM_LINK);
108 }
109
Anupama B R68a70432025-09-25 02:09:37 -0500110 std::vector<std::string> interfaces = {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500111 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
112
113 const types::MapperGetObject& objectMap =
114 dbusUtility::getObjectMap(mboardPath, interfaces);
115
116 if (objectMap.empty())
117 {
118 return false;
119 }
120 return true;
121}
122
123std::string Worker::getIMValue(const types::IPZVpdMap& parsedVpd) const
124{
125 if (parsedVpd.empty())
126 {
127 throw std::runtime_error("Empty VPD map. Can't Extract IM value");
128 }
129
130 const auto& itrToVSBP = parsedVpd.find("VSBP");
131 if (itrToVSBP == parsedVpd.end())
132 {
133 throw DataException("VSBP record missing.");
134 }
135
136 const auto& itrToIM = (itrToVSBP->second).find("IM");
137 if (itrToIM == (itrToVSBP->second).end())
138 {
139 throw DataException("IM keyword missing.");
140 }
141
142 types::BinaryVector imVal;
143 std::copy(itrToIM->second.begin(), itrToIM->second.end(),
144 back_inserter(imVal));
145
146 std::ostringstream imData;
147 for (auto& aByte : imVal)
148 {
149 imData << std::setw(2) << std::setfill('0') << std::hex
150 << static_cast<int>(aByte);
151 }
152
153 return imData.str();
154}
155
156std::string Worker::getHWVersion(const types::IPZVpdMap& parsedVpd) const
157{
158 if (parsedVpd.empty())
159 {
160 throw std::runtime_error("Empty VPD map. Can't Extract HW value");
161 }
162
163 const auto& itrToVINI = parsedVpd.find("VINI");
164 if (itrToVINI == parsedVpd.end())
165 {
166 throw DataException("VINI record missing.");
167 }
168
169 const auto& itrToHW = (itrToVINI->second).find("HW");
170 if (itrToHW == (itrToVINI->second).end())
171 {
172 throw DataException("HW keyword missing.");
173 }
174
175 types::BinaryVector hwVal;
176 std::copy(itrToHW->second.begin(), itrToHW->second.end(),
177 back_inserter(hwVal));
178
179 // The planar pass only comes from the LSB of the HW keyword,
180 // where as the MSB is used for other purposes such as signifying clock
181 // termination.
182 hwVal[0] = 0x00;
183
184 std::ostringstream hwString;
185 for (auto& aByte : hwVal)
186 {
187 hwString << std::setw(2) << std::setfill('0') << std::hex
188 << static_cast<int>(aByte);
189 }
190
191 return hwString.str();
192}
193
194void Worker::fillVPDMap(const std::string& vpdFilePath,
195 types::VPDMapVariant& vpdMap)
196{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500197 if (vpdFilePath.empty())
198 {
199 throw std::runtime_error("Invalid file path passed to fillVPDMap API.");
200 }
201
202 if (!std::filesystem::exists(vpdFilePath))
203 {
204 throw std::runtime_error("Can't Find physical file");
205 }
206
Sunny Srivastava043955d2025-01-21 18:04:49 +0530207 std::shared_ptr<Parser> vpdParser =
208 std::make_shared<Parser>(vpdFilePath, m_parsedJson);
209 vpdMap = vpdParser->parse();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500210}
211
212void Worker::getSystemJson(std::string& systemJson,
213 const types::VPDMapVariant& parsedVpdMap)
214{
215 if (auto pVal = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
216 {
217 std::string hwKWdValue = getHWVersion(*pVal);
218 if (hwKWdValue.empty())
219 {
220 throw DataException("HW value fetched is empty.");
221 }
222
223 const std::string& imKwdValue = getIMValue(*pVal);
224 if (imKwdValue.empty())
225 {
226 throw DataException("IM value fetched is empty.");
227 }
228
229 auto itrToIM = config::systemType.find(imKwdValue);
230 if (itrToIM == config::systemType.end())
231 {
232 throw DataException("IM keyword does not map to any system type");
233 }
234
235 const types::HWVerList hwVersionList = itrToIM->second.second;
236 if (!hwVersionList.empty())
237 {
238 transform(hwKWdValue.begin(), hwKWdValue.end(), hwKWdValue.begin(),
239 ::toupper);
240
241 auto itrToHW =
242 std::find_if(hwVersionList.begin(), hwVersionList.end(),
243 [&hwKWdValue](const auto& aPair) {
244 return aPair.first == hwKWdValue;
245 });
246
247 if (itrToHW != hwVersionList.end())
248 {
249 if (!(*itrToHW).second.empty())
250 {
251 systemJson += (*itrToIM).first + "_" + (*itrToHW).second +
252 ".json";
253 }
254 else
255 {
256 systemJson += (*itrToIM).first + ".json";
257 }
258 return;
259 }
260 }
261 systemJson += itrToIM->second.first + ".json";
262 return;
263 }
264
Sunny Srivastava043955d2025-01-21 18:04:49 +0530265 throw DataException(
266 "Invalid VPD type returned from Parser. Can't get system JSON.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500267}
268
269static void setEnvAndReboot(const std::string& key, const std::string& value)
270{
271 // set env and reboot and break.
272 commonUtility::executeCmd("/sbin/fw_setenv", key, value);
273 logging::logMessage("Rebooting BMC to pick up new device tree");
274
275 // make dbus call to reboot
276 auto bus = sdbusplus::bus::new_default_system();
277 auto method = bus.new_method_call(
278 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
279 "org.freedesktop.systemd1.Manager", "Reboot");
280 bus.call_noreply(method);
281}
282
283void Worker::setJsonSymbolicLink(const std::string& i_systemJson)
284{
285 std::error_code l_ec;
286 l_ec.clear();
Sunny Srivastavaadff7882025-03-13 11:41:05 +0530287
288 // Check if symlink file path exists and if the JSON at this location is a
289 // symlink.
290 if (m_isSymlinkPresent &&
291 std::filesystem::is_symlink(INVENTORY_JSON_SYM_LINK, l_ec))
292 { // Don't care about exception in "is_symlink". Will continue with creation
293 // of symlink.
294
295 const auto& l_symlinkFilePth =
296 std::filesystem::read_symlink(INVENTORY_JSON_SYM_LINK, l_ec);
297
298 if (l_ec)
299 {
300 logging::logMessage(
301 "Can't read existing symlink. Error =" + l_ec.message() +
302 "Trying removal of symlink and creation of new symlink.");
303 }
304
305 // If currently set JSON is the required one. No further processing
306 // required.
307 if (i_systemJson == l_symlinkFilePth)
308 {
309 // Correct symlink already set.
310 return;
311 }
312
313 if (!std::filesystem::remove(INVENTORY_JSON_SYM_LINK, l_ec))
314 {
315 // No point going further. If removal fails for existing symlink,
316 // create will anyways throw.
317 throw std::runtime_error(
318 "Removal of symlink failed with Error = " + l_ec.message() +
319 ". Can't proceed with create_symlink.");
320 }
321 }
322
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500323 if (!std::filesystem::exists(VPD_SYMLIMK_PATH, l_ec))
324 {
325 if (l_ec)
326 {
327 throw std::runtime_error(
328 "File system call to exist failed with error = " +
329 l_ec.message());
330 }
331
332 // implies it is a fresh boot/factory reset.
333 // Create the directory for hosting the symlink
334 if (!std::filesystem::create_directories(VPD_SYMLIMK_PATH, l_ec))
335 {
336 if (l_ec)
337 {
338 throw std::runtime_error(
339 "File system call to create directory failed with error = " +
340 l_ec.message());
341 }
342 }
343 }
344
345 // create a new symlink based on the system
346 std::filesystem::create_symlink(i_systemJson, INVENTORY_JSON_SYM_LINK,
347 l_ec);
348
349 if (l_ec)
350 {
351 throw std::runtime_error(
352 "create_symlink system call failed with error: " + l_ec.message());
353 }
354
355 // If the flow is at this point implies the symlink was not present there.
356 // Considering this as factory reset.
357 m_isFactoryResetDone = true;
358}
359
360void Worker::setDeviceTreeAndJson()
361{
Anupama B R4c65fcd2025-09-01 08:09:00 -0500362 setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
363 constants::vpdCollectionInProgress);
364
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500365 // JSON is madatory for processing of this API.
366 if (m_parsedJson.empty())
367 {
Sunny Srivastava043955d2025-01-21 18:04:49 +0530368 throw JsonException("System config JSON is empty", m_configJsonPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500369 }
370
371 types::VPDMapVariant parsedVpdMap;
372 fillVPDMap(SYSTEM_VPD_FILE_PATH, parsedVpdMap);
373
374 // Implies it is default JSON.
375 std::string systemJson{JSON_ABSOLUTE_PATH_PREFIX};
376
377 // ToDo: Need to check if INVENTORY_JSON_SYM_LINK pointing to correct system
378 // This is required to support movement from rainier to Blue Ridge on the
379 // fly.
380
Sunny Srivastavaadff7882025-03-13 11:41:05 +0530381 getSystemJson(systemJson, parsedVpdMap);
382
383 if (!systemJson.compare(JSON_ABSOLUTE_PATH_PREFIX))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500384 {
Sunny Srivastava043955d2025-01-21 18:04:49 +0530385 throw DataException(
386 "No system JSON found corresponding to IM read from VPD.");
Sunny Srivastavaadff7882025-03-13 11:41:05 +0530387 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500388
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500389 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500390
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500391 // re-parse the JSON once appropriate JSON has been selected.
392 m_parsedJson = jsonUtility::getParsedJson(systemJson, l_errCode);
393
394 if (l_errCode)
Sunny Srivastavaadff7882025-03-13 11:41:05 +0530395 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500396 throw(JsonException(
397 "JSON parsing failed for file [ " + systemJson +
Rekha Aparnac6159a22025-10-09 12:20:20 +0530398 " ], error : " + commonUtility::getErrCodeMsg(l_errCode),
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500399 systemJson));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500400 }
401
402 std::string devTreeFromJson;
403 if (m_parsedJson.contains("devTree"))
404 {
405 devTreeFromJson = m_parsedJson["devTree"];
406
407 if (devTreeFromJson.empty())
408 {
Sunny Srivastava043955d2025-01-21 18:04:49 +0530409 EventLogger::createSyncPel(
410 types::ErrorType::JsonFailure, types::SeverityType::Error,
411 __FILE__, __FUNCTION__, 0,
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500412 "Mandatory value for device tree missing from JSON[" +
Sunny Srivastava043955d2025-01-21 18:04:49 +0530413 systemJson + "]",
414 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500415 }
416 }
417
418 auto fitConfigVal = readFitConfigValue();
419
420 if (devTreeFromJson.empty() ||
421 fitConfigVal.find(devTreeFromJson) != std::string::npos)
422 { // Skipping setting device tree as either devtree info is missing from
423 // Json or it is rightly set.
424
Sunny Srivastavaadff7882025-03-13 11:41:05 +0530425 setJsonSymbolicLink(systemJson);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500426
Rekha Aparna196e3082025-09-08 20:40:35 -0500427 if (isSystemVPDOnDBus())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500428 {
Rekha Aparna196e3082025-09-08 20:40:35 -0500429 uint16_t l_errCode = 0;
430 if (jsonUtility::isBackupAndRestoreRequired(m_parsedJson,
431 l_errCode))
432 {
433 performBackupAndRestore(parsedVpdMap);
434 }
435 else if (l_errCode)
436 {
437 logging::logMessage(
438 "Failed to check if backup and restore required. Reason : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +0530439 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna196e3082025-09-08 20:40:35 -0500440 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500441 }
442
443 // proceed to publish system VPD.
444 publishSystemVPD(parsedVpdMap);
Anupama B R4c65fcd2025-09-01 08:09:00 -0500445 setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
446 constants::vpdCollectionCompleted);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500447 return;
448 }
449
450 setEnvAndReboot("fitconfig", devTreeFromJson);
451 exit(EXIT_SUCCESS);
452}
453
454void Worker::populateIPZVPDpropertyMap(
455 types::InterfaceMap& interfacePropMap,
456 const types::IPZKwdValueMap& keyordValueMap,
457 const std::string& interfaceName)
458{
459 types::PropertyMap propertyValueMap;
460 for (const auto& kwdVal : keyordValueMap)
461 {
462 auto kwd = kwdVal.first;
463
464 if (kwd[0] == '#')
465 {
466 kwd = std::string("PD_") + kwd[1];
467 }
468 else if (isdigit(kwd[0]))
469 {
470 kwd = std::string("N_") + kwd;
471 }
472
473 types::BinaryVector value(kwdVal.second.begin(), kwdVal.second.end());
474 propertyValueMap.emplace(move(kwd), move(value));
475 }
476
477 if (!propertyValueMap.empty())
478 {
479 interfacePropMap.emplace(interfaceName, propertyValueMap);
480 }
481}
482
483void Worker::populateKwdVPDpropertyMap(const types::KeywordVpdMap& keyordVPDMap,
484 types::InterfaceMap& interfaceMap)
485{
486 for (const auto& kwdValMap : keyordVPDMap)
487 {
488 types::PropertyMap propertyValueMap;
489 auto kwd = kwdValMap.first;
490
491 if (kwd[0] == '#')
492 {
493 kwd = std::string("PD_") + kwd[1];
494 }
495 else if (isdigit(kwd[0]))
496 {
497 kwd = std::string("N_") + kwd;
498 }
499
500 if (auto keywordValue = get_if<types::BinaryVector>(&kwdValMap.second))
501 {
502 types::BinaryVector value((*keywordValue).begin(),
503 (*keywordValue).end());
504 propertyValueMap.emplace(move(kwd), move(value));
505 }
506 else if (auto keywordValue = get_if<std::string>(&kwdValMap.second))
507 {
508 types::BinaryVector value((*keywordValue).begin(),
509 (*keywordValue).end());
510 propertyValueMap.emplace(move(kwd), move(value));
511 }
512 else if (auto keywordValue = get_if<size_t>(&kwdValMap.second))
513 {
514 if (kwd == "MemorySizeInKB")
515 {
516 types::PropertyMap memProp;
517 memProp.emplace(move(kwd), ((*keywordValue)));
518 interfaceMap.emplace("xyz.openbmc_project.Inventory.Item.Dimm",
519 move(memProp));
520 continue;
521 }
522 else
523 {
524 logging::logMessage(
525 "Unknown Keyword =" + kwd + " found in keyword VPD map");
526 continue;
527 }
528 }
529 else
530 {
531 logging::logMessage(
532 "Unknown variant type found in keyword VPD map.");
533 continue;
534 }
535
536 if (!propertyValueMap.empty())
537 {
Rekha Aparnad3662222025-10-14 10:33:17 -0500538 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500539 vpdSpecificUtility::insertOrMerge(
Rekha Aparnad3662222025-10-14 10:33:17 -0500540 interfaceMap, constants::kwdVpdInf, move(propertyValueMap),
541 l_errCode);
542
543 if (l_errCode)
544 {
545 logging::logMessage(
546 "Failed to insert value into map, error : " +
547 commonUtility::getErrCodeMsg(l_errCode));
548 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500549 }
550 }
551}
552
553void Worker::populateInterfaces(const nlohmann::json& interfaceJson,
554 types::InterfaceMap& interfaceMap,
555 const types::VPDMapVariant& parsedVpdMap)
556{
557 for (const auto& interfacesPropPair : interfaceJson.items())
558 {
Rekha Aparnad3662222025-10-14 10:33:17 -0500559 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500560 const std::string& interface = interfacesPropPair.key();
561 types::PropertyMap propertyMap;
562
563 for (const auto& propValuePair : interfacesPropPair.value().items())
564 {
565 const std::string property = propValuePair.key();
566
567 if (propValuePair.value().is_boolean())
568 {
569 propertyMap.emplace(property,
570 propValuePair.value().get<bool>());
571 }
572 else if (propValuePair.value().is_string())
573 {
574 if (property.compare("LocationCode") == 0 &&
575 interface.compare("com.ibm.ipzvpd.Location") == 0)
576 {
577 std::string value =
578 vpdSpecificUtility::getExpandedLocationCode(
579 propValuePair.value().get<std::string>(),
580 parsedVpdMap);
581 propertyMap.emplace(property, value);
582
583 auto l_locCodeProperty = propertyMap;
584 vpdSpecificUtility::insertOrMerge(
585 interfaceMap,
586 std::string(constants::xyzLocationCodeInf),
Rekha Aparnad3662222025-10-14 10:33:17 -0500587 move(l_locCodeProperty), l_errCode);
588
589 if (l_errCode)
590 {
591 logging::logMessage(
592 "Failed to insert value into map, error : " +
593 commonUtility::getErrCodeMsg(l_errCode));
594 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500595 }
596 else
597 {
598 propertyMap.emplace(
599 property, propValuePair.value().get<std::string>());
600 }
601 }
602 else if (propValuePair.value().is_array())
603 {
604 try
605 {
606 propertyMap.emplace(
607 property,
608 propValuePair.value().get<types::BinaryVector>());
609 }
610 catch (const nlohmann::detail::type_error& e)
611 {
612 std::cerr << "Type exception: " << e.what() << "\n";
613 }
614 }
615 else if (propValuePair.value().is_number())
616 {
617 // For now assume the value is a size_t. In the future it would
618 // be nice to come up with a way to get the type from the JSON.
619 propertyMap.emplace(property,
620 propValuePair.value().get<size_t>());
621 }
622 else if (propValuePair.value().is_object())
623 {
624 const std::string& record =
625 propValuePair.value().value("recordName", "");
626 const std::string& keyword =
627 propValuePair.value().value("keywordName", "");
628 const std::string& encoding =
629 propValuePair.value().value("encoding", "");
630
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500631 uint16_t l_errCode = 0;
632
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500633 if (auto ipzVpdMap =
634 std::get_if<types::IPZVpdMap>(&parsedVpdMap))
635 {
636 if (!record.empty() && !keyword.empty() &&
637 (*ipzVpdMap).count(record) &&
638 (*ipzVpdMap).at(record).count(keyword))
639 {
640 auto encoded = vpdSpecificUtility::encodeKeyword(
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500641 ((*ipzVpdMap).at(record).at(keyword)), encoding,
642 l_errCode);
643
644 if (l_errCode)
645 {
646 logging::logMessage(
647 std::string(
648 "Failed to get encoded keyword value for : ") +
649 keyword + std::string(", error : ") +
650 commonUtility::getErrCodeMsg(l_errCode));
651 }
652
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500653 propertyMap.emplace(property, encoded);
654 }
655 }
656 else if (auto kwdVpdMap =
657 std::get_if<types::KeywordVpdMap>(&parsedVpdMap))
658 {
659 if (!keyword.empty() && (*kwdVpdMap).count(keyword))
660 {
661 if (auto kwValue = std::get_if<types::BinaryVector>(
662 &(*kwdVpdMap).at(keyword)))
663 {
664 auto encodedValue =
665 vpdSpecificUtility::encodeKeyword(
666 std::string((*kwValue).begin(),
667 (*kwValue).end()),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500668 encoding, l_errCode);
669
670 if (l_errCode)
671 {
672 logging::logMessage(
673 std::string(
674 "Failed to get encoded keyword value for : ") +
675 keyword + std::string(", error : ") +
676 commonUtility::getErrCodeMsg(l_errCode));
677 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500678
679 propertyMap.emplace(property, encodedValue);
680 }
681 else if (auto kwValue = std::get_if<std::string>(
682 &(*kwdVpdMap).at(keyword)))
683 {
684 auto encodedValue =
685 vpdSpecificUtility::encodeKeyword(
686 std::string((*kwValue).begin(),
687 (*kwValue).end()),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500688 encoding, l_errCode);
689
690 if (l_errCode)
691 {
692 logging::logMessage(
693 "Failed to get encoded keyword value for : " +
694 keyword + ", error : " +
695 commonUtility::getErrCodeMsg(l_errCode));
696 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500697
698 propertyMap.emplace(property, encodedValue);
699 }
700 else if (auto uintValue = std::get_if<size_t>(
701 &(*kwdVpdMap).at(keyword)))
702 {
703 propertyMap.emplace(property, *uintValue);
704 }
705 else
706 {
707 logging::logMessage(
708 "Unknown keyword found, Keywrod = " + keyword);
709 }
710 }
711 }
712 }
713 }
Rekha Aparnad3662222025-10-14 10:33:17 -0500714 l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500715 vpdSpecificUtility::insertOrMerge(interfaceMap, interface,
Rekha Aparnad3662222025-10-14 10:33:17 -0500716 move(propertyMap), l_errCode);
717
718 if (l_errCode)
719 {
720 logging::logMessage("Failed to insert value into map, error : " +
721 commonUtility::getErrCodeMsg(l_errCode));
722 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500723 }
724}
725
726bool Worker::isCPUIOGoodOnly(const std::string& i_pgKeyword)
727{
728 const unsigned char l_io[] = {
729 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF,
730 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF};
731
732 // EQ0 index (in PG keyword) starts at 97 (with offset starting from 0).
733 // Each EQ carries 3 bytes of data. Totally there are 8 EQs. If all EQs'
734 // value equals 0xE7F9FF, then the cpu has no good cores and its treated as
735 // IO.
736 if (memcmp(l_io, i_pgKeyword.data() + constants::INDEX_OF_EQ0_IN_PG,
737 constants::SIZE_OF_8EQ_IN_PG) == 0)
738 {
739 return true;
740 }
741
742 // The CPU is not an IO
743 return false;
744}
745
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500746void Worker::processEmbeddedAndSynthesizedFrus(const nlohmann::json& singleFru,
747 types::InterfaceMap& interfaces)
748{
749 // embedded property(true or false) says whether the subfru is embedded
750 // into the parent fru (or) not. VPD sets Present property only for
751 // embedded frus. If the subfru is not an embedded FRU, the subfru may
752 // or may not be physically present. Those non embedded frus will always
753 // have Present=false irrespective of its physical presence or absence.
754 // Eg: nvme drive in nvme slot is not an embedded FRU. So don't set
755 // Present to true for such sub frus.
756 // Eg: ethernet port is embedded into bmc card. So set Present to true
757 // for such sub frus. Also donot populate present property for embedded
758 // subfru which is synthesized. Currently there is no subfru which are
759 // both embedded and synthesized. But still the case is handled here.
760
761 // Check if its required to handle presence for this FRU.
762 if (singleFru.value("handlePresence", true))
763 {
Rekha Aparnad3662222025-10-14 10:33:17 -0500764 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500765 types::PropertyMap presProp;
766 presProp.emplace("Present", true);
Rekha Aparnad3662222025-10-14 10:33:17 -0500767 vpdSpecificUtility::insertOrMerge(interfaces,
768 "xyz.openbmc_project.Inventory.Item",
769 move(presProp), l_errCode);
770
771 if (l_errCode)
772 {
773 logging::logMessage("Failed to insert value into map, error : " +
774 commonUtility::getErrCodeMsg(l_errCode));
775 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500776 }
777}
778
779void Worker::processExtraInterfaces(const nlohmann::json& singleFru,
780 types::InterfaceMap& interfaces,
781 const types::VPDMapVariant& parsedVpdMap)
782{
783 populateInterfaces(singleFru["extraInterfaces"], interfaces, parsedVpdMap);
784 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
785 {
786 if (singleFru["extraInterfaces"].contains(
787 "xyz.openbmc_project.Inventory.Item.Cpu"))
788 {
789 auto itrToRec = (*ipzVpdMap).find("CP00");
790 if (itrToRec == (*ipzVpdMap).end())
791 {
792 return;
793 }
794
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500795 uint16_t l_errCode = 0;
796 const std::string pgKeywordValue{vpdSpecificUtility::getKwVal(
797 itrToRec->second, "PG", l_errCode)};
Souvik Roya55fcca2025-02-19 01:33:58 -0600798
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500799 if (!pgKeywordValue.empty())
800 {
801 if (isCPUIOGoodOnly(pgKeywordValue))
802 {
803 interfaces["xyz.openbmc_project.Inventory.Item"]
804 ["PrettyName"] = "IO Module";
805 }
806 }
Souvik Roya55fcca2025-02-19 01:33:58 -0600807 else
808 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500809 throw DataException(
810 std::string(__FUNCTION__) +
811 "Failed to get value for keyword PG, error : " +
812 commonUtility::getErrCodeMsg(l_errCode));
Souvik Roya55fcca2025-02-19 01:33:58 -0600813 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500814 }
815 }
816}
817
818void Worker::processCopyRecordFlag(const nlohmann::json& singleFru,
819 const types::VPDMapVariant& parsedVpdMap,
820 types::InterfaceMap& interfaces)
821{
822 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
823 {
824 for (const auto& record : singleFru["copyRecords"])
825 {
826 const std::string& recordName = record;
827 if ((*ipzVpdMap).find(recordName) != (*ipzVpdMap).end())
828 {
829 populateIPZVPDpropertyMap(interfaces,
830 (*ipzVpdMap).at(recordName),
831 constants::ipzVpdInf + recordName);
832 }
833 }
834 }
835}
836
837void Worker::processInheritFlag(const types::VPDMapVariant& parsedVpdMap,
838 types::InterfaceMap& interfaces)
839{
840 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
841 {
842 for (const auto& [recordName, kwdValueMap] : *ipzVpdMap)
843 {
844 populateIPZVPDpropertyMap(interfaces, kwdValueMap,
845 constants::ipzVpdInf + recordName);
846 }
847 }
848 else if (auto kwdVpdMap = std::get_if<types::KeywordVpdMap>(&parsedVpdMap))
849 {
850 populateKwdVPDpropertyMap(*kwdVpdMap, interfaces);
851 }
852
853 if (m_parsedJson.contains("commonInterfaces"))
854 {
855 populateInterfaces(m_parsedJson["commonInterfaces"], interfaces,
856 parsedVpdMap);
857 }
858}
859
860bool Worker::processFruWithCCIN(const nlohmann::json& singleFru,
861 const types::VPDMapVariant& parsedVpdMap)
862{
863 if (auto ipzVPDMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
864 {
865 auto itrToRec = (*ipzVPDMap).find("VINI");
866 if (itrToRec == (*ipzVPDMap).end())
867 {
868 return false;
869 }
870
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500871 uint16_t l_errCode = 0;
Souvik Roya55fcca2025-02-19 01:33:58 -0600872 std::string ccinFromVpd{
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500873 vpdSpecificUtility::getKwVal(itrToRec->second, "CC", l_errCode)};
Souvik Roya55fcca2025-02-19 01:33:58 -0600874
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500875 if (ccinFromVpd.empty())
876 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500877 logging::logMessage("Failed to get CCIN kwd value, error : " +
878 commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500879 return false;
880 }
881
882 transform(ccinFromVpd.begin(), ccinFromVpd.end(), ccinFromVpd.begin(),
883 ::toupper);
884
885 std::vector<std::string> ccinList;
886 for (std::string ccin : singleFru["ccin"])
887 {
888 transform(ccin.begin(), ccin.end(), ccin.begin(), ::toupper);
889 ccinList.push_back(ccin);
890 }
891
892 if (ccinList.empty())
893 {
894 return false;
895 }
896
897 if (find(ccinList.begin(), ccinList.end(), ccinFromVpd) ==
898 ccinList.end())
899 {
900 return false;
901 }
902 }
903 return true;
904}
905
906void Worker::processFunctionalProperty(const std::string& i_inventoryObjPath,
907 types::InterfaceMap& io_interfaces)
908{
909 if (!dbusUtility::isChassisPowerOn())
910 {
Anupama B R68a70432025-09-25 02:09:37 -0500911 std::vector<std::string> l_operationalStatusInf = {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500912 constants::operationalStatusInf};
913
914 auto mapperObjectMap = dbusUtility::getObjectMap(
915 i_inventoryObjPath, l_operationalStatusInf);
916
917 // If the object has been found. Check if it is under PIM.
918 if (mapperObjectMap.size() != 0)
919 {
920 for (const auto& [l_serviceName, l_interfaceLsit] : mapperObjectMap)
921 {
922 if (l_serviceName == constants::pimServiceName)
923 {
924 // The object is already under PIM. No need to process
925 // again. Retain the old value.
926 return;
927 }
928 }
929 }
930
931 // Implies value is not there in D-Bus. Populate it with default
932 // value "true".
Rekha Aparnad3662222025-10-14 10:33:17 -0500933 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500934 types::PropertyMap l_functionalProp;
935 l_functionalProp.emplace("Functional", true);
936 vpdSpecificUtility::insertOrMerge(io_interfaces,
937 constants::operationalStatusInf,
Rekha Aparnad3662222025-10-14 10:33:17 -0500938 move(l_functionalProp), l_errCode);
939
940 if (l_errCode)
941 {
942 logging::logMessage(
943 "Failed to insert interface into map, error : " +
944 commonUtility::getErrCodeMsg(l_errCode));
945 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500946 }
947
948 // if chassis is power on. Functional property should be there on D-Bus.
949 // Don't process.
950 return;
951}
952
953void Worker::processEnabledProperty(const std::string& i_inventoryObjPath,
954 types::InterfaceMap& io_interfaces)
955{
956 if (!dbusUtility::isChassisPowerOn())
957 {
Anupama B R68a70432025-09-25 02:09:37 -0500958 std::vector<std::string> l_enableInf = {constants::enableInf};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500959
960 auto mapperObjectMap =
961 dbusUtility::getObjectMap(i_inventoryObjPath, l_enableInf);
962
963 // If the object has been found. Check if it is under PIM.
964 if (mapperObjectMap.size() != 0)
965 {
966 for (const auto& [l_serviceName, l_interfaceLsit] : mapperObjectMap)
967 {
968 if (l_serviceName == constants::pimServiceName)
969 {
970 // The object is already under PIM. No need to process
971 // again. Retain the old value.
972 return;
973 }
974 }
975 }
976
977 // Implies value is not there in D-Bus. Populate it with default
978 // value "true".
Rekha Aparnad3662222025-10-14 10:33:17 -0500979 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500980 types::PropertyMap l_enabledProp;
981 l_enabledProp.emplace("Enabled", true);
982 vpdSpecificUtility::insertOrMerge(io_interfaces, constants::enableInf,
Rekha Aparnad3662222025-10-14 10:33:17 -0500983 move(l_enabledProp), l_errCode);
984
985 if (l_errCode)
986 {
987 logging::logMessage(
988 "Failed to insert interface into map, error : " +
989 commonUtility::getErrCodeMsg(l_errCode));
990 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500991 }
992
993 // if chassis is power on. Enabled property should be there on D-Bus.
994 // Don't process.
995 return;
996}
997
998void Worker::populateDbus(const types::VPDMapVariant& parsedVpdMap,
999 types::ObjectMap& objectInterfaceMap,
1000 const std::string& vpdFilePath)
1001{
1002 if (vpdFilePath.empty())
1003 {
1004 throw std::runtime_error(
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301005 std::string(__FUNCTION__) +
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001006 "Invalid parameter passed to populateDbus API.");
1007 }
1008
1009 // JSON config is mandatory for processing of "if". Add "else" for any
1010 // processing without config JSON.
1011 if (!m_parsedJson.empty())
1012 {
1013 types::InterfaceMap interfaces;
1014
1015 for (const auto& aFru : m_parsedJson["frus"][vpdFilePath])
1016 {
1017 const auto& inventoryPath = aFru["inventoryPath"];
1018 sdbusplus::message::object_path fruObjectPath(inventoryPath);
1019 if (aFru.contains("ccin"))
1020 {
1021 if (!processFruWithCCIN(aFru, parsedVpdMap))
1022 {
1023 continue;
1024 }
1025 }
1026
1027 if (aFru.value("inherit", true))
1028 {
1029 processInheritFlag(parsedVpdMap, interfaces);
1030 }
1031
1032 // If specific record needs to be copied.
1033 if (aFru.contains("copyRecords"))
1034 {
1035 processCopyRecordFlag(aFru, parsedVpdMap, interfaces);
1036 }
1037
1038 if (aFru.contains("extraInterfaces"))
1039 {
1040 // Process extra interfaces w.r.t a FRU.
1041 processExtraInterfaces(aFru, interfaces, parsedVpdMap);
1042 }
1043
1044 // Process FRUS which are embedded in the parent FRU and whose VPD
1045 // will be synthesized.
1046 if ((aFru.value("embedded", true)) &&
1047 (!aFru.value("synthesized", false)))
1048 {
1049 processEmbeddedAndSynthesizedFrus(aFru, interfaces);
1050 }
1051
1052 processFunctionalProperty(inventoryPath, interfaces);
1053 processEnabledProperty(inventoryPath, interfaces);
1054
1055 objectInterfaceMap.emplace(std::move(fruObjectPath),
1056 std::move(interfaces));
1057 }
1058 }
1059}
1060
Patrick Williams43fedab2025-02-03 14:28:05 -05001061std::string Worker::createAssetTagString(
1062 const types::VPDMapVariant& i_parsedVpdMap)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001063{
1064 std::string l_assetTag;
1065
1066 // system VPD will be in IPZ format.
1067 if (auto l_parsedVpdMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
1068 {
1069 auto l_itrToVsys = (*l_parsedVpdMap).find(constants::recVSYS);
1070 if (l_itrToVsys != (*l_parsedVpdMap).end())
1071 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001072 uint16_t l_errCode = 0;
Souvik Roya55fcca2025-02-19 01:33:58 -06001073 const std::string l_tmKwdValue{vpdSpecificUtility::getKwVal(
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001074 l_itrToVsys->second, constants::kwdTM, l_errCode)};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001075
Souvik Roya55fcca2025-02-19 01:33:58 -06001076 if (l_tmKwdValue.empty())
1077 {
1078 throw std::runtime_error(
1079 std::string("Failed to get value for keyword [") +
1080 constants::kwdTM +
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001081 std::string("] while creating Asset tag. Error : " +
1082 commonUtility::getErrCodeMsg(l_errCode)));
Souvik Roya55fcca2025-02-19 01:33:58 -06001083 }
1084
1085 const std::string l_seKwdValue{vpdSpecificUtility::getKwVal(
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001086 l_itrToVsys->second, constants::kwdSE, l_errCode)};
Souvik Roya55fcca2025-02-19 01:33:58 -06001087
1088 if (l_seKwdValue.empty())
1089 {
1090 throw std::runtime_error(
1091 std::string("Failed to get value for keyword [") +
1092 constants::kwdSE +
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001093 std::string("] while creating Asset tag. Error : " +
1094 commonUtility::getErrCodeMsg(l_errCode)));
Souvik Roya55fcca2025-02-19 01:33:58 -06001095 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001096
1097 l_assetTag = std::string{"Server-"} + l_tmKwdValue +
1098 std::string{"-"} + l_seKwdValue;
1099 }
1100 else
1101 {
1102 throw std::runtime_error(
1103 "VSYS record not found in parsed VPD map to create Asset tag.");
1104 }
1105 }
1106 else
1107 {
1108 throw std::runtime_error(
1109 "Invalid VPD type recieved to create Asset tag.");
1110 }
1111
1112 return l_assetTag;
1113}
1114
1115void Worker::publishSystemVPD(const types::VPDMapVariant& parsedVpdMap)
1116{
1117 types::ObjectMap objectInterfaceMap;
1118
1119 if (std::get_if<types::IPZVpdMap>(&parsedVpdMap))
1120 {
1121 populateDbus(parsedVpdMap, objectInterfaceMap, SYSTEM_VPD_FILE_PATH);
1122
1123 try
1124 {
1125 if (m_isFactoryResetDone)
1126 {
1127 const auto& l_assetTag = createAssetTagString(parsedVpdMap);
1128
1129 auto l_itrToSystemPath = objectInterfaceMap.find(
1130 sdbusplus::message::object_path(constants::systemInvPath));
1131 if (l_itrToSystemPath == objectInterfaceMap.end())
1132 {
1133 throw std::runtime_error(
Sunny Srivastava043955d2025-01-21 18:04:49 +05301134 "Asset tag update failed. System Path not found in object map.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001135 }
1136
1137 types::PropertyMap l_assetTagProperty;
1138 l_assetTagProperty.emplace("AssetTag", l_assetTag);
1139
1140 (l_itrToSystemPath->second)
1141 .emplace(constants::assetTagInf,
1142 std::move(l_assetTagProperty));
1143 }
1144 }
1145 catch (const std::exception& l_ex)
1146 {
1147 EventLogger::createSyncPel(
Sunny Srivastava043955d2025-01-21 18:04:49 +05301148 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
1149 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001150 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
1151 }
1152
1153 // Notify PIM
1154 if (!dbusUtility::callPIM(move(objectInterfaceMap)))
1155 {
1156 throw std::runtime_error("Call to PIM failed for system VPD");
1157 }
1158 }
1159 else
1160 {
1161 throw DataException("Invalid format of parsed VPD map.");
1162 }
1163}
1164
1165bool Worker::processPreAction(const std::string& i_vpdFilePath,
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001166 const std::string& i_flagToProcess,
1167 uint16_t& i_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001168{
1169 if (i_vpdFilePath.empty() || i_flagToProcess.empty())
1170 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001171 i_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001172 return false;
1173 }
1174
1175 if ((!jsonUtility::executeBaseAction(m_parsedJson, "preAction",
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001176 i_vpdFilePath, i_flagToProcess,
1177 i_errCode)) &&
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001178 (i_flagToProcess.compare("collection") == constants::STR_CMP_SUCCESS))
1179 {
1180 // TODO: Need a way to delete inventory object from Dbus and persisted
1181 // data section in case any FRU is not present or there is any
1182 // problem in collecting it. Once it has been deleted, it can be
1183 // re-created in the flow of priming the inventory. This needs to be
1184 // done either here or in the exception section of "parseAndPublishVPD"
1185 // API. Any failure in the process of collecting FRU will land up in the
1186 // excpetion of "parseAndPublishVPD".
1187
1188 // If the FRU is not there, clear the VINI/CCIN data.
1189 // Enity manager probes for this keyword to look for this
1190 // FRU, now if the data is persistent on BMC and FRU is
1191 // removed this can lead to ambiguity. Hence clearing this
1192 // Keyword if FRU is absent.
1193 const auto& inventoryPath =
1194 m_parsedJson["frus"][i_vpdFilePath].at(0).value("inventoryPath",
1195 "");
1196
1197 if (!inventoryPath.empty())
1198 {
1199 types::ObjectMap l_pimObjMap{
1200 {inventoryPath,
1201 {{constants::kwdVpdInf,
1202 {{constants::kwdCCIN, types::BinaryVector{}}}}}}};
1203
1204 if (!dbusUtility::callPIM(std::move(l_pimObjMap)))
1205 {
1206 logging::logMessage(
1207 "Call to PIM failed for file " + i_vpdFilePath);
1208 }
1209 }
1210 else
1211 {
1212 logging::logMessage(
1213 "Inventory path is empty in Json for file " + i_vpdFilePath);
1214 }
1215
1216 return false;
1217 }
1218 return true;
1219}
1220
1221bool Worker::processPostAction(
1222 const std::string& i_vpdFruPath, const std::string& i_flagToProcess,
1223 const std::optional<types::VPDMapVariant> i_parsedVpd)
1224{
1225 if (i_vpdFruPath.empty() || i_flagToProcess.empty())
1226 {
1227 logging::logMessage(
1228 "Invalid input parameter. Abort processing post action");
1229 return false;
1230 }
1231
1232 // Check if post action tag is to be triggered in the flow of collection
1233 // based on some CCIN value?
1234 if (m_parsedJson["frus"][i_vpdFruPath]
1235 .at(0)["postAction"][i_flagToProcess]
1236 .contains("ccin"))
1237 {
1238 if (!i_parsedVpd.has_value())
1239 {
1240 logging::logMessage("Empty VPD Map");
1241 return false;
1242 }
1243
1244 // CCIN match is required to process post action for this FRU as it
1245 // contains the flag.
1246 if (!vpdSpecificUtility::findCcinInVpd(
1247 m_parsedJson["frus"][i_vpdFruPath].at(
1248 0)["postAction"]["collection"],
1249 i_parsedVpd.value()))
1250 {
1251 // If CCIN is not found, implies post action processing is not
1252 // required for this FRU. Let the flow continue.
1253 return true;
1254 }
1255 }
1256
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001257 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001258 if (!jsonUtility::executeBaseAction(m_parsedJson, "postAction",
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001259 i_vpdFruPath, i_flagToProcess,
1260 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001261 {
1262 logging::logMessage(
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001263 "Execution of post action failed for path: " + i_vpdFruPath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301264 " . Reason: " + commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001265
1266 // If post action was required and failed only in that case return
1267 // false. In all other case post action is considered passed.
1268 return false;
1269 }
1270
1271 return true;
1272}
1273
1274types::VPDMapVariant Worker::parseVpdFile(const std::string& i_vpdFilePath)
1275{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001276 try
1277 {
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001278 uint16_t l_errCode = 0;
1279
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301280 if (i_vpdFilePath.empty())
1281 {
1282 throw std::runtime_error(
1283 std::string(__FUNCTION__) +
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301284 " Empty VPD file path passed. Abort processing");
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301285 }
1286
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301287 bool isPreActionRequired = false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001288 if (jsonUtility::isActionRequired(m_parsedJson, i_vpdFilePath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001289 "preAction", "collection", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001290 {
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001291 l_errCode = 0;
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301292 isPreActionRequired = true;
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001293 if (!processPreAction(i_vpdFilePath, "collection", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001294 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001295 if (l_errCode == error_code::DEVICE_NOT_PRESENT)
1296 {
1297 logging::logMessage(
Rekha Aparnac6159a22025-10-09 12:20:20 +05301298 commonUtility::getErrCodeMsg(l_errCode) +
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001299 i_vpdFilePath);
1300 // Presence pin has been read successfully and has been read
1301 // as false, so this is not a failure case, hence returning
1302 // empty variant so that pre action is not marked as failed.
1303 return types::VPDMapVariant{};
1304 }
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301305 throw std::runtime_error(
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001306 std::string(__FUNCTION__) +
1307 " Pre-Action failed with error: " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301308 commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001309 }
1310 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001311 else if (l_errCode)
1312 {
1313 logging::logMessage(
1314 "Failed to check if pre action required for FRU [" +
1315 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301316 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001317 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001318
1319 if (!std::filesystem::exists(i_vpdFilePath))
1320 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301321 if (isPreActionRequired)
1322 {
1323 throw std::runtime_error(
1324 std::string(__FUNCTION__) + " Could not find file path " +
1325 i_vpdFilePath + "Skipping parser trigger for the EEPROM");
1326 }
1327 return types::VPDMapVariant{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001328 }
1329
1330 std::shared_ptr<Parser> vpdParser =
1331 std::make_shared<Parser>(i_vpdFilePath, m_parsedJson);
1332
1333 types::VPDMapVariant l_parsedVpd = vpdParser->parse();
1334
1335 // Before returning, as collection is over, check if FRU qualifies for
1336 // any post action in the flow of collection.
1337 // Note: Don't change the order, post action needs to be processed only
1338 // after collection for FRU is successfully done.
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001339 l_errCode = 0;
1340
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001341 if (jsonUtility::isActionRequired(m_parsedJson, i_vpdFilePath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001342 "postAction", "collection",
1343 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001344 {
1345 if (!processPostAction(i_vpdFilePath, "collection", l_parsedVpd))
1346 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301347 // Post action was required but failed while executing.
1348 // Behaviour can be undefined.
1349 EventLogger::createSyncPel(
1350 types::ErrorType::InternalFailure,
1351 types::SeverityType::Warning, __FILE__, __FUNCTION__, 0,
1352 std::string("Required post action failed for path [" +
1353 i_vpdFilePath + "]"),
1354 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001355 }
1356 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001357 else if (l_errCode)
1358 {
1359 logging::logMessage(
1360 "Error while checking if post action required for FRU [" +
1361 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301362 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001363 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001364
1365 return l_parsedVpd;
1366 }
1367 catch (std::exception& l_ex)
1368 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001369 uint16_t l_errCode = 0;
Souvik Roy37c6bef2025-07-17 00:55:59 -05001370 std::string l_exMsg{
1371 std::string(__FUNCTION__) + " : VPD parsing failed for " +
1372 i_vpdFilePath + " due to error: " + l_ex.what()};
1373
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001374 // If post fail action is required, execute it.
1375 if (jsonUtility::isActionRequired(m_parsedJson, i_vpdFilePath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001376 "postFailAction", "collection",
1377 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001378 {
1379 if (!jsonUtility::executePostFailAction(m_parsedJson, i_vpdFilePath,
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001380 "collection", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001381 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001382 l_exMsg += ". Post fail action also failed. Error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301383 commonUtility::getErrCodeMsg(l_errCode) +
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001384 " Aborting collection for this FRU.";
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001385 }
1386 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001387 else if (l_errCode)
1388 {
1389 l_exMsg +=
1390 ". Failed to check if post fail action required, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301391 commonUtility::getErrCodeMsg(l_errCode);
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001392 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001393
Souvik Roy37c6bef2025-07-17 00:55:59 -05001394 if (typeid(l_ex) == typeid(DataException))
1395 {
1396 throw DataException(l_exMsg);
1397 }
1398 else if (typeid(l_ex) == typeid(EccException))
1399 {
1400 throw EccException(l_exMsg);
1401 }
1402 throw std::runtime_error(l_exMsg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001403 }
1404}
1405
Patrick Williams43fedab2025-02-03 14:28:05 -05001406std::tuple<bool, std::string> Worker::parseAndPublishVPD(
1407 const std::string& i_vpdFilePath)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001408{
Priyanga Ramasamy1aad7832024-12-12 22:13:52 -06001409 std::string l_inventoryPath{};
1410
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001411 try
1412 {
1413 m_semaphore.acquire();
1414
1415 // Thread launched.
1416 m_mutex.lock();
1417 m_activeCollectionThreadCount++;
1418 m_mutex.unlock();
1419
Anupama B R4c65fcd2025-09-01 08:09:00 -05001420 setCollectionStatusProperty(i_vpdFilePath,
1421 constants::vpdCollectionInProgress);
Priyanga Ramasamy1aad7832024-12-12 22:13:52 -06001422
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001423 const types::VPDMapVariant& parsedVpdMap = parseVpdFile(i_vpdFilePath);
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301424 if (!std::holds_alternative<std::monostate>(parsedVpdMap))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001425 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301426 types::ObjectMap objectInterfaceMap;
1427 populateDbus(parsedVpdMap, objectInterfaceMap, i_vpdFilePath);
1428
1429 // Notify PIM
1430 if (!dbusUtility::callPIM(move(objectInterfaceMap)))
1431 {
1432 throw std::runtime_error(
1433 std::string(__FUNCTION__) +
1434 "Call to PIM failed while publishing VPD.");
1435 }
1436 }
1437 else
1438 {
1439 logging::logMessage("Empty parsedVpdMap recieved for path [" +
1440 i_vpdFilePath + "]. Check PEL for reason.");
Anupama B R4c65fcd2025-09-01 08:09:00 -05001441
1442 // As empty parsedVpdMap recieved for some reason, but still
1443 // considered VPD collection is completed. Hence FRU collection
1444 // Status will be set as completed.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001445 }
1446 }
1447 catch (const std::exception& ex)
1448 {
Anupama B R24691d22025-05-21 08:14:15 -05001449 setCollectionStatusProperty(i_vpdFilePath,
Anupama B R5cd1b2d2025-08-05 04:57:40 -05001450 constants::vpdCollectionFailed);
Priyanga Ramasamy1aad7832024-12-12 22:13:52 -06001451
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001452 // handle all the exceptions internally. Return only true/false
1453 // based on status of execution.
1454 if (typeid(ex) == std::type_index(typeid(DataException)))
1455 {
Rekha Aparna017567a2025-08-13 02:07:06 -05001456 uint16_t l_errCode = 0;
Sunny Srivastava78c91072025-02-05 14:09:50 +05301457 // In case of pass1 planar, VPD can be corrupted on PCIe cards. Skip
1458 // logging error for these cases.
1459 if (vpdSpecificUtility::isPass1Planar())
1460 {
Rekha Aparna017567a2025-08-13 02:07:06 -05001461 std::string l_invPath =
1462 jsonUtility::getInventoryObjPathFromJson(
1463 m_parsedJson, i_vpdFilePath, l_errCode);
1464
1465 if (l_errCode != 0)
1466 {
1467 logging::logMessage(
1468 "Failed to get inventory object path from JSON for FRU [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301469 i_vpdFilePath +
1470 "], error: " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna017567a2025-08-13 02:07:06 -05001471 }
1472
RekhaAparna011ef21002025-02-18 23:47:36 -06001473 const std::string& l_invPathLeafValue =
Rekha Aparna017567a2025-08-13 02:07:06 -05001474 sdbusplus::message::object_path(l_invPath).filename();
Sunny Srivastava78c91072025-02-05 14:09:50 +05301475
RekhaAparna011ef21002025-02-18 23:47:36 -06001476 if ((l_invPathLeafValue.find("pcie_card", 0) !=
1477 std::string::npos))
Sunny Srivastava78c91072025-02-05 14:09:50 +05301478 {
1479 // skip logging any PEL for PCIe cards on pass 1 planar.
1480 return std::make_tuple(false, i_vpdFilePath);
1481 }
1482 }
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301483 }
Sunny Srivastava78c91072025-02-05 14:09:50 +05301484
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301485 EventLogger::createSyncPel(
Souvik Roy37c6bef2025-07-17 00:55:59 -05001486 EventLogger::getErrorType(ex),
1487 (typeid(ex) == typeid(DataException)) ||
1488 (typeid(ex) == typeid(EccException))
1489 ? types::SeverityType::Warning
1490 : types::SeverityType::Informational,
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301491 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(ex),
1492 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001493
1494 // TODO: Figure out a way to clear data in case of any failure at
1495 // runtime.
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301496
1497 // set present property to false for any error case. In future this will
1498 // be replaced by presence logic.
Souvik Roy6a9553c2025-02-07 01:16:32 -06001499 // Update Present property for this FRU only if we handle Present
1500 // property for the FRU.
1501 if (isPresentPropertyHandlingRequired(
1502 m_parsedJson["frus"][i_vpdFilePath].at(0)))
1503 {
1504 setPresentProperty(i_vpdFilePath, false);
1505 }
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301506
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001507 m_semaphore.release();
1508 return std::make_tuple(false, i_vpdFilePath);
1509 }
Anupama B R4c65fcd2025-09-01 08:09:00 -05001510
1511 setCollectionStatusProperty(i_vpdFilePath,
1512 constants::vpdCollectionCompleted);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001513 m_semaphore.release();
1514 return std::make_tuple(true, i_vpdFilePath);
1515}
1516
Sunny Srivastava61611752025-02-04 00:29:33 -06001517bool Worker::skipPathForCollection(const std::string& i_vpdFilePath)
1518{
1519 if (i_vpdFilePath.empty())
1520 {
1521 return true;
1522 }
1523
1524 // skip processing of system VPD again as it has been already collected.
1525 if (i_vpdFilePath == SYSTEM_VPD_FILE_PATH)
1526 {
1527 return true;
1528 }
1529
1530 if (dbusUtility::isChassisPowerOn())
1531 {
1532 // If chassis is powered on, skip collecting FRUs which are
1533 // powerOffOnly.
Rekha Aparna52041882025-09-01 20:48:07 -05001534
1535 uint16_t l_errCode = 0;
1536 if (jsonUtility::isFruPowerOffOnly(m_parsedJson, i_vpdFilePath,
1537 l_errCode))
Sunny Srivastava61611752025-02-04 00:29:33 -06001538 {
1539 return true;
1540 }
Rekha Aparna52041882025-09-01 20:48:07 -05001541 else if (l_errCode)
1542 {
1543 logging::logMessage(
1544 "Failed to check if FRU is power off only for FRU [" +
1545 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301546 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna52041882025-09-01 20:48:07 -05001547 }
Sunny Srivastava61611752025-02-04 00:29:33 -06001548
Rekha Aparna52041882025-09-01 20:48:07 -05001549 l_errCode = 0;
Rekha Aparna017567a2025-08-13 02:07:06 -05001550 std::string l_invPath = jsonUtility::getInventoryObjPathFromJson(
1551 m_parsedJson, i_vpdFilePath, l_errCode);
1552
1553 if (l_errCode)
1554 {
1555 logging::logMessage(
1556 "Failed to get inventory path from JSON for FRU [" +
1557 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301558 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna017567a2025-08-13 02:07:06 -05001559
1560 return false;
1561 }
1562
Sunny Srivastava61611752025-02-04 00:29:33 -06001563 const std::string& l_invPathLeafValue =
Rekha Aparna017567a2025-08-13 02:07:06 -05001564 sdbusplus::message::object_path(l_invPath).filename();
Sunny Srivastava61611752025-02-04 00:29:33 -06001565
1566 if ((l_invPathLeafValue.find("pcie_card", 0) != std::string::npos))
1567 {
1568 return true;
1569 }
1570 }
1571
1572 return false;
1573}
1574
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001575void Worker::collectFrusFromJson()
1576{
1577 // A parsed JSON file should be present to pick FRUs EEPROM paths
1578 if (m_parsedJson.empty())
1579 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301580 throw JsonException(
1581 std::string(__FUNCTION__) +
1582 ": Config JSON is mandatory for processing of FRUs through this API.",
1583 m_configJsonPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001584 }
1585
1586 const nlohmann::json& listOfFrus =
1587 m_parsedJson["frus"].get_ref<const nlohmann::json::object_t&>();
1588
1589 for (const auto& itemFRUS : listOfFrus.items())
1590 {
1591 const std::string& vpdFilePath = itemFRUS.key();
1592
Sunny Srivastava61611752025-02-04 00:29:33 -06001593 if (skipPathForCollection(vpdFilePath))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001594 {
1595 continue;
1596 }
1597
Souvik Roy1f4c8f82025-01-23 00:37:43 -06001598 try
1599 {
1600 std::thread{[vpdFilePath, this]() {
1601 const auto& l_parseResult = parseAndPublishVPD(vpdFilePath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001602
Souvik Roy1f4c8f82025-01-23 00:37:43 -06001603 m_mutex.lock();
1604 m_activeCollectionThreadCount--;
1605 m_mutex.unlock();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001606
Souvik Roy1f4c8f82025-01-23 00:37:43 -06001607 if (!m_activeCollectionThreadCount)
1608 {
1609 m_isAllFruCollected = true;
1610 }
1611 }}.detach();
1612 }
1613 catch (const std::exception& l_ex)
1614 {
1615 // add vpdFilePath(EEPROM path) to failed list
1616 m_failedEepromPaths.push_front(vpdFilePath);
1617 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001618 }
1619}
1620
1621// ToDo: Move the API under IBM_SYSTEM
1622void Worker::performBackupAndRestore(types::VPDMapVariant& io_srcVpdMap)
1623{
1624 try
1625 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001626 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001627 std::string l_backupAndRestoreCfgFilePath =
1628 m_parsedJson.value("backupRestoreConfigPath", "");
1629
1630 nlohmann::json l_backupAndRestoreCfgJsonObj =
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001631 jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath,
1632 l_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001633
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001634 if (l_errCode)
RekhaAparna011ef21002025-02-18 23:47:36 -06001635 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001636 throw JsonException(
1637 "JSON parsing failed for file [ " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301638 l_backupAndRestoreCfgFilePath +
1639 " ], error : " + commonUtility::getErrCodeMsg(l_errCode),
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001640 l_backupAndRestoreCfgFilePath);
RekhaAparna011ef21002025-02-18 23:47:36 -06001641 }
1642
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001643 // check if either of "source" or "destination" has inventory path.
1644 // this indicates that this sytem has System VPD on hardware
1645 // and other copy on D-Bus (BMC cache).
1646 if (!l_backupAndRestoreCfgJsonObj.empty() &&
1647 ((l_backupAndRestoreCfgJsonObj.contains("source") &&
1648 l_backupAndRestoreCfgJsonObj["source"].contains(
1649 "inventoryPath")) ||
1650 (l_backupAndRestoreCfgJsonObj.contains("destination") &&
1651 l_backupAndRestoreCfgJsonObj["destination"].contains(
1652 "inventoryPath"))))
1653 {
1654 BackupAndRestore l_backupAndRestoreObj(m_parsedJson);
1655 auto [l_srcVpdVariant,
1656 l_dstVpdVariant] = l_backupAndRestoreObj.backupAndRestore();
1657
1658 // ToDo: Revisit is this check is required or not.
1659 if (auto l_srcVpdMap =
1660 std::get_if<types::IPZVpdMap>(&l_srcVpdVariant);
1661 l_srcVpdMap && !(*l_srcVpdMap).empty())
1662 {
1663 io_srcVpdMap = std::move(l_srcVpdVariant);
1664 }
1665 }
1666 }
1667 catch (const std::exception& l_ex)
1668 {
1669 EventLogger::createSyncPel(
Sunny Srivastava043955d2025-01-21 18:04:49 +05301670 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
Sunny Srivastava15a189a2025-02-26 16:53:19 +05301671 __FILE__, __FUNCTION__, 0,
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001672 std::string(
1673 "Exception caught while backup and restore VPD keyword's.") +
Sunny Srivastava15a189a2025-02-26 16:53:19 +05301674 EventLogger::getErrorMsg(l_ex),
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001675 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
1676 }
1677}
1678
1679void Worker::deleteFruVpd(const std::string& i_dbusObjPath)
1680{
1681 if (i_dbusObjPath.empty())
1682 {
1683 throw std::runtime_error("Given DBus object path is empty.");
1684 }
1685
Rekha Aparna0578dd22025-09-02 08:20:21 -05001686 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001687 const std::string& l_fruPath =
Rekha Aparna0578dd22025-09-02 08:20:21 -05001688 jsonUtility::getFruPathFromJson(m_parsedJson, i_dbusObjPath, l_errCode);
1689
1690 if (l_errCode)
1691 {
1692 logging::logMessage(
1693 "Failed to get FRU path for inventory path [" + i_dbusObjPath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301694 "], error : " + commonUtility::getErrCodeMsg(l_errCode) +
Rekha Aparna0578dd22025-09-02 08:20:21 -05001695 " Aborting FRU VPD deletion.");
1696 return;
1697 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001698
1699 try
1700 {
1701 auto l_presentPropValue = dbusUtility::readDbusProperty(
1702 constants::pimServiceName, i_dbusObjPath,
1703 constants::inventoryItemInf, "Present");
1704
1705 if (auto l_value = std::get_if<bool>(&l_presentPropValue))
1706 {
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001707 uint16_t l_errCode = 0;
Souvik Roye9120152025-07-02 08:24:38 -05001708 // check if FRU's Present property is handled by vpd-manager
1709 const auto& l_isFruPresenceHandled =
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001710 jsonUtility::isFruPresenceHandled(m_parsedJson, l_fruPath,
1711 l_errCode);
1712
1713 if (l_errCode)
1714 {
1715 throw std::runtime_error(
1716 "Failed to check if FRU's presence is handled, reason: " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301717 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001718 }
Souvik Roye9120152025-07-02 08:24:38 -05001719
1720 if (!(*l_value) && l_isFruPresenceHandled)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001721 {
1722 throw std::runtime_error("Given FRU is not present");
1723 }
Souvik Roye9120152025-07-02 08:24:38 -05001724 else if (*l_value && !l_isFruPresenceHandled)
1725 {
1726 throw std::runtime_error(
1727 "Given FRU is present and its presence is not handled by vpd-manager.");
1728 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001729 else
1730 {
1731 if (jsonUtility::isActionRequired(m_parsedJson, l_fruPath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001732 "preAction", "deletion",
1733 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001734 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001735 if (!processPreAction(l_fruPath, "deletion", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001736 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001737 std::string l_msg = "Pre action failed";
1738 if (l_errCode)
1739 {
Rekha Aparnac6159a22025-10-09 12:20:20 +05301740 l_msg += " Reason: " +
1741 commonUtility::getErrCodeMsg(l_errCode);
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001742 }
1743 throw std::runtime_error(l_msg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001744 }
1745 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001746 else if (l_errCode)
1747 {
1748 logging::logMessage(
1749 "Failed to check if pre action required for FRU [" +
1750 l_fruPath + "], error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301751 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001752 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001753
1754 std::vector<std::string> l_interfaceList{
1755 constants::operationalStatusInf};
1756
1757 types::MapperGetSubTree l_subTreeMap =
1758 dbusUtility::getObjectSubTree(i_dbusObjPath, 0,
1759 l_interfaceList);
1760
1761 types::ObjectMap l_objectMap;
1762
1763 // Updates VPD specific interfaces property value under PIM for
1764 // sub FRUs.
1765 for (const auto& [l_objectPath, l_serviceInterfaceMap] :
1766 l_subTreeMap)
1767 {
Rekha Aparna2c04eeb2025-10-22 22:15:07 -05001768 l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001769 types::InterfaceMap l_interfaceMap;
Rekha Aparna2c04eeb2025-10-22 22:15:07 -05001770 vpdSpecificUtility::resetDataUnderPIM(
1771 l_objectPath, l_interfaceMap, l_errCode);
1772
1773 if (l_errCode)
1774 {
1775 throw std::runtime_error(
1776 "Failed to reset data under PIM for sub FRU [" +
1777 l_objectPath + "], error : " +
1778 commonUtility::getErrCodeMsg(l_errCode));
1779 }
1780
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001781 l_objectMap.emplace(l_objectPath,
1782 std::move(l_interfaceMap));
1783 }
1784
Rekha Aparna2c04eeb2025-10-22 22:15:07 -05001785 l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001786 types::InterfaceMap l_interfaceMap;
Rekha Aparna2c04eeb2025-10-22 22:15:07 -05001787 vpdSpecificUtility::resetDataUnderPIM(
1788 i_dbusObjPath, l_interfaceMap, l_errCode);
1789
1790 if (l_errCode)
1791 {
1792 throw std::runtime_error(
1793 "Failed to reset data under PIM, error : " +
1794 commonUtility::getErrCodeMsg(l_errCode));
1795 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001796
1797 l_objectMap.emplace(i_dbusObjPath, std::move(l_interfaceMap));
1798
1799 if (!dbusUtility::callPIM(std::move(l_objectMap)))
1800 {
1801 throw std::runtime_error("Call to PIM failed.");
1802 }
1803
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001804 l_errCode = 0;
1805
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001806 if (jsonUtility::isActionRequired(m_parsedJson, l_fruPath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001807 "postAction", "deletion",
1808 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001809 {
1810 if (!processPostAction(l_fruPath, "deletion"))
1811 {
1812 throw std::runtime_error("Post action failed");
1813 }
1814 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001815 else if (l_errCode)
1816 {
1817 logging::logMessage(
1818 "Failed to check if post action required during deletion for FRU [" +
1819 l_fruPath + "], error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301820 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001821 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001822 }
1823 }
1824 else
1825 {
1826 logging::logMessage(
1827 "Can't process delete VPD for FRU [" + i_dbusObjPath +
1828 "] as unable to read present property");
1829 return;
1830 }
1831
1832 logging::logMessage(
1833 "Successfully completed deletion of FRU VPD for " + i_dbusObjPath);
1834 }
1835 catch (const std::exception& l_ex)
1836 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001837 uint16_t l_errCode = 0;
1838 std::string l_errMsg =
1839 "Failed to delete VPD for FRU : " + i_dbusObjPath +
1840 " error: " + std::string(l_ex.what());
1841
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001842 if (jsonUtility::isActionRequired(m_parsedJson, l_fruPath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001843 "postFailAction", "deletion",
1844 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001845 {
1846 if (!jsonUtility::executePostFailAction(m_parsedJson, l_fruPath,
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001847 "deletion", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001848 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001849 l_errMsg += ". Post fail action also failed, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301850 commonUtility::getErrCodeMsg(l_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001851 }
1852 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001853 else if (l_errCode)
1854 {
1855 l_errMsg +=
1856 ". Failed to check if post fail action required, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301857 commonUtility::getErrCodeMsg(l_errCode);
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001858 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001859
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001860 logging::logMessage(l_errMsg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001861 }
1862}
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301863
1864void Worker::setPresentProperty(const std::string& i_vpdPath,
1865 const bool& i_value)
1866{
1867 try
1868 {
1869 if (i_vpdPath.empty())
1870 {
1871 throw std::runtime_error(
1872 "Path is empty. Can't set present property");
1873 }
1874
1875 types::ObjectMap l_objectInterfaceMap;
1876
1877 // If the given path is EEPROM path.
1878 if (m_parsedJson["frus"].contains(i_vpdPath))
1879 {
1880 for (const auto& l_Fru : m_parsedJson["frus"][i_vpdPath])
1881 {
1882 sdbusplus::message::object_path l_fruObjectPath(
1883 l_Fru["inventoryPath"]);
1884
1885 types::PropertyMap l_propertyValueMap;
1886 l_propertyValueMap.emplace("Present", i_value);
1887
Rekha Aparnad3662222025-10-14 10:33:17 -05001888 uint16_t l_errCode = 0;
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301889 types::InterfaceMap l_interfaces;
Rekha Aparnad3662222025-10-14 10:33:17 -05001890 vpdSpecificUtility::insertOrMerge(
1891 l_interfaces, constants::inventoryItemInf,
1892 move(l_propertyValueMap), l_errCode);
1893
1894 if (l_errCode)
1895 {
1896 logging::logMessage(
1897 "Failed to insert value into map, error : " +
1898 commonUtility::getErrCodeMsg(l_errCode));
1899 }
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301900
1901 l_objectInterfaceMap.emplace(std::move(l_fruObjectPath),
1902 std::move(l_interfaces));
1903 }
1904 }
1905 else
1906 {
1907 // consider it as an inventory path.
1908 if (i_vpdPath.find(constants::pimPath) != constants::VALUE_0)
1909 {
1910 throw std::runtime_error(
1911 "Invalid inventory path: " + i_vpdPath);
1912 }
1913
1914 types::PropertyMap l_propertyValueMap;
1915 l_propertyValueMap.emplace("Present", i_value);
1916
Rekha Aparnad3662222025-10-14 10:33:17 -05001917 uint16_t l_errCode = 0;
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301918 types::InterfaceMap l_interfaces;
Rekha Aparnad3662222025-10-14 10:33:17 -05001919 vpdSpecificUtility::insertOrMerge(
1920 l_interfaces, constants::inventoryItemInf,
1921 move(l_propertyValueMap), l_errCode);
1922
1923 if (l_errCode)
1924 {
1925 logging::logMessage(
1926 "Failed to insert value into map, error : " +
1927 commonUtility::getErrCodeMsg(l_errCode));
1928 }
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301929
1930 l_objectInterfaceMap.emplace(i_vpdPath, std::move(l_interfaces));
1931 }
1932
1933 // Notify PIM
1934 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
1935 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301936 throw DbusException(
1937 std::string(__FUNCTION__) +
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301938 "Call to PIM failed while setting present property for path " +
1939 i_vpdPath);
1940 }
1941 }
1942 catch (const std::exception& l_ex)
1943 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301944 EventLogger::createSyncPel(
1945 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
1946 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
1947 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301948 }
1949}
1950
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301951void Worker::performVpdRecollection()
1952{
1953 try
1954 {
1955 // Check if system config JSON is present
1956 if (m_parsedJson.empty())
1957 {
1958 throw std::runtime_error(
1959 "System config json object is empty, can't process recollection.");
1960 }
1961
Rekha Aparna88d53302025-09-01 18:16:55 -05001962 uint16_t l_errCode = 0;
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301963 const auto& l_frusReplaceableAtStandby =
Rekha Aparna88d53302025-09-01 18:16:55 -05001964 jsonUtility::getListOfFrusReplaceableAtStandby(m_parsedJson,
1965 l_errCode);
1966
1967 if (l_errCode)
1968 {
1969 logging::logMessage(
1970 "Failed to get list of FRUs replaceable at runtime, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301971 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna88d53302025-09-01 18:16:55 -05001972 return;
1973 }
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301974
1975 for (const auto& l_fruInventoryPath : l_frusReplaceableAtStandby)
1976 {
1977 // ToDo: Add some logic/trace to know the flow to
1978 // collectSingleFruVpd has been directed via
1979 // performVpdRecollection.
1980 collectSingleFruVpd(l_fruInventoryPath);
1981 }
1982 return;
1983 }
1984
1985 catch (const std::exception& l_ex)
1986 {
1987 // TODO Log PEL
1988 logging::logMessage(
1989 "VPD recollection failed with error: " + std::string(l_ex.what()));
1990 }
1991}
1992
1993void Worker::collectSingleFruVpd(
1994 const sdbusplus::message::object_path& i_dbusObjPath)
1995{
Anupama B R48f297b2025-08-13 04:29:06 -05001996 std::string l_fruPath{};
Rekha Aparna0578dd22025-09-02 08:20:21 -05001997 uint16_t l_errCode = 0;
1998
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301999 try
2000 {
2001 // Check if system config JSON is present
2002 if (m_parsedJson.empty())
2003 {
2004 logging::logMessage(
2005 "System config JSON object not present. Single FRU VPD collection is not performed for " +
2006 std::string(i_dbusObjPath));
2007 return;
2008 }
2009
2010 // Get FRU path for the given D-bus object path from JSON
Rekha Aparna0578dd22025-09-02 08:20:21 -05002011 l_fruPath = jsonUtility::getFruPathFromJson(m_parsedJson, i_dbusObjPath,
2012 l_errCode);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302013
2014 if (l_fruPath.empty())
2015 {
Rekha Aparna0578dd22025-09-02 08:20:21 -05002016 if (l_errCode)
2017 {
2018 logging::logMessage(
2019 "Failed to get FRU path for [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05302020 std::string(i_dbusObjPath) +
2021 "], error : " + commonUtility::getErrCodeMsg(l_errCode) +
Rekha Aparna0578dd22025-09-02 08:20:21 -05002022 " Aborting single FRU VPD collection.");
2023 return;
2024 }
2025
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302026 logging::logMessage(
2027 "D-bus object path not present in JSON. Single FRU VPD collection is not performed for " +
2028 std::string(i_dbusObjPath));
2029 return;
2030 }
2031
2032 // Check if host is up and running
2033 if (dbusUtility::isHostRunning())
2034 {
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05002035 uint16_t l_errCode = 0;
2036 bool isFruReplaceableAtRuntime =
2037 jsonUtility::isFruReplaceableAtRuntime(m_parsedJson, l_fruPath,
2038 l_errCode);
2039
2040 if (l_errCode)
2041 {
2042 logging::logMessage(
2043 "Failed to check if FRU is replaceable at runtime for FRU : [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05302044 std::string(i_dbusObjPath) +
2045 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05002046 return;
2047 }
2048
2049 if (!isFruReplaceableAtRuntime)
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302050 {
2051 logging::logMessage(
2052 "Given FRU is not replaceable at host runtime. Single FRU VPD collection is not performed for " +
2053 std::string(i_dbusObjPath));
2054 return;
2055 }
2056 }
2057 else if (dbusUtility::isBMCReady())
2058 {
Rekha Aparna40845612025-09-01 19:58:56 -05002059 uint16_t l_errCode = 0;
2060 bool isFruReplaceableAtStandby =
2061 jsonUtility::isFruReplaceableAtStandby(m_parsedJson, l_fruPath,
2062 l_errCode);
2063
2064 if (l_errCode)
2065 {
2066 logging::logMessage(
2067 "Error while checking if FRU is replaceable at standby for FRU [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05302068 std::string(i_dbusObjPath) +
2069 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna40845612025-09-01 19:58:56 -05002070 }
2071
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05002072 l_errCode = 0;
2073 bool isFruReplaceableAtRuntime =
2074 jsonUtility::isFruReplaceableAtRuntime(m_parsedJson, l_fruPath,
2075 l_errCode);
2076
2077 if (l_errCode)
2078 {
2079 logging::logMessage(
2080 "Failed to check if FRU is replaceable at runtime for FRU : [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05302081 std::string(i_dbusObjPath) +
2082 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05002083 return;
2084 }
2085
2086 if (!isFruReplaceableAtStandby && (!isFruReplaceableAtRuntime))
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302087 {
2088 logging::logMessage(
2089 "Given FRU is neither replaceable at standby nor replaceable at runtime. Single FRU VPD collection is not performed for " +
2090 std::string(i_dbusObjPath));
2091 return;
2092 }
2093 }
2094
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002095 // Set collection Status as InProgress. Since it's an intermediate state
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302096 // D-bus set-property call is good enough to update the status.
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002097 const std::string& l_collStatusProp = "Status";
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302098
Anupama B R4c65fcd2025-09-01 08:09:00 -05002099 setCollectionStatusProperty(l_fruPath,
2100 constants::vpdCollectionInProgress);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302101
2102 // Parse VPD
2103 types::VPDMapVariant l_parsedVpd = parseVpdFile(l_fruPath);
2104
2105 // If l_parsedVpd is pointing to std::monostate
2106 if (l_parsedVpd.index() == 0)
2107 {
2108 throw std::runtime_error(
2109 "VPD parsing failed for " + std::string(i_dbusObjPath));
2110 }
2111
2112 // Get D-bus object map from worker class
2113 types::ObjectMap l_dbusObjectMap;
2114 populateDbus(l_parsedVpd, l_dbusObjectMap, l_fruPath);
2115
2116 if (l_dbusObjectMap.empty())
2117 {
2118 throw std::runtime_error(
2119 "Failed to create D-bus object map. Single FRU VPD collection failed for " +
2120 std::string(i_dbusObjPath));
2121 }
2122
2123 // Call PIM's Notify method
2124 if (!dbusUtility::callPIM(move(l_dbusObjectMap)))
2125 {
2126 throw std::runtime_error(
2127 "Notify PIM failed. Single FRU VPD collection failed for " +
2128 std::string(i_dbusObjPath));
2129 }
Anupama B R4c65fcd2025-09-01 08:09:00 -05002130 setCollectionStatusProperty(l_fruPath,
2131 constants::vpdCollectionCompleted);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302132 }
2133 catch (const std::exception& l_error)
2134 {
Anupama B R48f297b2025-08-13 04:29:06 -05002135 setCollectionStatusProperty(l_fruPath, constants::vpdCollectionFailed);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302136 // TODO: Log PEL
2137 logging::logMessage(std::string(l_error.what()));
2138 }
2139}
Anupama B R24691d22025-05-21 08:14:15 -05002140
2141void Worker::setCollectionStatusProperty(
2142 const std::string& i_vpdPath, const std::string& i_value) const noexcept
2143{
2144 try
2145 {
2146 if (i_vpdPath.empty())
2147 {
2148 throw std::runtime_error(
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002149 "Given path is empty. Can't set collection Status property");
Anupama B R24691d22025-05-21 08:14:15 -05002150 }
2151
Anupama B R4c65fcd2025-09-01 08:09:00 -05002152 types::PropertyMap l_timeStampMap;
2153 if (i_value == constants::vpdCollectionCompleted ||
2154 i_value == constants::vpdCollectionFailed)
2155 {
2156 l_timeStampMap.emplace(
2157 "CompletedTime",
2158 types::DbusVariantType{
2159 commonUtility::getCurrentTimeSinceEpoch()});
2160 }
2161 else if (i_value == constants::vpdCollectionInProgress)
2162 {
2163 l_timeStampMap.emplace(
2164 "StartTime", types::DbusVariantType{
2165 commonUtility::getCurrentTimeSinceEpoch()});
2166 }
2167 else if (i_value == constants::vpdCollectionNotStarted)
2168 {
2169 l_timeStampMap.emplace("StartTime", 0);
2170 l_timeStampMap.emplace("CompletedTime", 0);
2171 }
2172
Anupama B R24691d22025-05-21 08:14:15 -05002173 types::ObjectMap l_objectInterfaceMap;
2174
2175 if (m_parsedJson["frus"].contains(i_vpdPath))
2176 {
2177 for (const auto& l_Fru : m_parsedJson["frus"][i_vpdPath])
2178 {
2179 sdbusplus::message::object_path l_fruObjectPath(
2180 l_Fru["inventoryPath"]);
2181
2182 types::PropertyMap l_propertyValueMap;
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002183 l_propertyValueMap.emplace("Status", i_value);
Anupama B R4c65fcd2025-09-01 08:09:00 -05002184 l_propertyValueMap.insert(l_timeStampMap.begin(),
2185 l_timeStampMap.end());
Anupama B R24691d22025-05-21 08:14:15 -05002186
Rekha Aparnad3662222025-10-14 10:33:17 -05002187 uint16_t l_errCode = 0;
Anupama B R24691d22025-05-21 08:14:15 -05002188 types::InterfaceMap l_interfaces;
2189 vpdSpecificUtility::insertOrMerge(
2190 l_interfaces, constants::vpdCollectionInterface,
Rekha Aparnad3662222025-10-14 10:33:17 -05002191 move(l_propertyValueMap), l_errCode);
2192
2193 if (l_errCode)
2194 {
2195 logging::logMessage(
2196 "Failed to insert value into map, error : " +
2197 commonUtility::getErrCodeMsg(l_errCode));
2198 }
Anupama B R24691d22025-05-21 08:14:15 -05002199
2200 l_objectInterfaceMap.emplace(std::move(l_fruObjectPath),
2201 std::move(l_interfaces));
2202 }
2203 }
2204 else
2205 {
2206 // consider it as an inventory path.
2207 if (i_vpdPath.find(constants::pimPath) != constants::VALUE_0)
2208 {
2209 throw std::runtime_error(
2210 "Invalid inventory path: " + i_vpdPath +
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002211 ". Can't set collection Status property");
Anupama B R24691d22025-05-21 08:14:15 -05002212 }
2213
2214 types::PropertyMap l_propertyValueMap;
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002215 l_propertyValueMap.emplace("Status", i_value);
Anupama B R4c65fcd2025-09-01 08:09:00 -05002216 l_propertyValueMap.insert(l_timeStampMap.begin(),
2217 l_timeStampMap.end());
Anupama B R24691d22025-05-21 08:14:15 -05002218
Rekha Aparnad3662222025-10-14 10:33:17 -05002219 uint16_t l_errCode = 0;
Anupama B R24691d22025-05-21 08:14:15 -05002220 types::InterfaceMap l_interfaces;
Rekha Aparnad3662222025-10-14 10:33:17 -05002221 vpdSpecificUtility::insertOrMerge(
2222 l_interfaces, constants::vpdCollectionInterface,
2223 move(l_propertyValueMap), l_errCode);
2224
2225 if (l_errCode)
2226 {
2227 logging::logMessage(
2228 "Failed to insert value into map, error : " +
2229 commonUtility::getErrCodeMsg(l_errCode));
2230 }
Anupama B R24691d22025-05-21 08:14:15 -05002231
2232 l_objectInterfaceMap.emplace(i_vpdPath, std::move(l_interfaces));
2233 }
2234
2235 // Notify PIM
2236 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
2237 {
2238 throw DbusException(
2239 std::string(__FUNCTION__) +
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002240 "Call to PIM failed while setting collection Status property for path " +
Anupama B R24691d22025-05-21 08:14:15 -05002241 i_vpdPath);
2242 }
2243 }
2244 catch (const std::exception& l_ex)
2245 {
2246 EventLogger::createSyncPel(
2247 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
2248 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
2249 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
2250 }
2251}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05002252} // namespace vpd