blob: 520fc203fb048bbb7a35cae8d73114fe6c2d7aa1 [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
Souvik Roy31548842025-10-22 07:03:12 +000029Worker::Worker(std::string pathToConfigJson, uint8_t i_maxThreadCount,
30 types::VpdCollectionMode i_vpdCollectionMode) :
31 m_configJsonPath(pathToConfigJson), m_semaphore(i_maxThreadCount),
32 m_vpdCollectionMode(i_vpdCollectionMode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050033{
34 // Implies the processing is based on some config JSON
35 if (!m_configJsonPath.empty())
36 {
37 // Check if symlink is already there to confirm fresh boot/factory
38 // reset.
39 if (std::filesystem::exists(INVENTORY_JSON_SYM_LINK))
40 {
41 logging::logMessage("Sym Link already present");
42 m_configJsonPath = INVENTORY_JSON_SYM_LINK;
43 m_isSymlinkPresent = true;
44 }
45
46 try
47 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -050048 uint16_t l_errCode = 0;
49 m_parsedJson =
50 jsonUtility::getParsedJson(m_configJsonPath, l_errCode);
51
52 if (l_errCode)
53 {
54 throw std::runtime_error(
55 "JSON parsing failed for file [ " + m_configJsonPath +
Rekha Aparnac6159a22025-10-09 12:20:20 +053056 " ], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaca9a0862025-08-29 04:08:33 -050057 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050058
59 // check for mandatory fields at this point itself.
60 if (!m_parsedJson.contains("frus"))
61 {
62 throw std::runtime_error("Mandatory tag(s) missing from JSON");
63 }
64 }
65 catch (const std::exception& ex)
66 {
67 throw(JsonException(ex.what(), m_configJsonPath));
68 }
69 }
70 else
71 {
72 logging::logMessage("Processing in not based on any config JSON");
73 }
74}
75
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050076static std::string readFitConfigValue()
77{
78 std::vector<std::string> output =
79 commonUtility::executeCmd("/sbin/fw_printenv");
80 std::string fitConfigValue;
81
82 for (const auto& entry : output)
83 {
84 auto pos = entry.find("=");
85 auto key = entry.substr(0, pos);
86 if (key != "fitconfig")
87 {
88 continue;
89 }
90
91 if (pos + 1 < entry.size())
92 {
93 fitConfigValue = entry.substr(pos + 1);
94 }
95 }
96
97 return fitConfigValue;
98}
99
100bool Worker::isSystemVPDOnDBus() const
101{
102 const std::string& mboardPath =
103 m_parsedJson["frus"][SYSTEM_VPD_FILE_PATH].at(0).value(
104 "inventoryPath", "");
105
106 if (mboardPath.empty())
107 {
108 throw JsonException("System vpd file path missing in JSON",
109 INVENTORY_JSON_SYM_LINK);
110 }
111
Anupama B R68a70432025-09-25 02:09:37 -0500112 std::vector<std::string> interfaces = {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500113 "xyz.openbmc_project.Inventory.Item.Board.Motherboard"};
114
115 const types::MapperGetObject& objectMap =
116 dbusUtility::getObjectMap(mboardPath, interfaces);
117
118 if (objectMap.empty())
119 {
120 return false;
121 }
122 return true;
123}
124
125std::string Worker::getIMValue(const types::IPZVpdMap& parsedVpd) const
126{
127 if (parsedVpd.empty())
128 {
129 throw std::runtime_error("Empty VPD map. Can't Extract IM value");
130 }
131
132 const auto& itrToVSBP = parsedVpd.find("VSBP");
133 if (itrToVSBP == parsedVpd.end())
134 {
135 throw DataException("VSBP record missing.");
136 }
137
138 const auto& itrToIM = (itrToVSBP->second).find("IM");
139 if (itrToIM == (itrToVSBP->second).end())
140 {
141 throw DataException("IM keyword missing.");
142 }
143
144 types::BinaryVector imVal;
145 std::copy(itrToIM->second.begin(), itrToIM->second.end(),
146 back_inserter(imVal));
147
148 std::ostringstream imData;
149 for (auto& aByte : imVal)
150 {
151 imData << std::setw(2) << std::setfill('0') << std::hex
152 << static_cast<int>(aByte);
153 }
154
155 return imData.str();
156}
157
158std::string Worker::getHWVersion(const types::IPZVpdMap& parsedVpd) const
159{
160 if (parsedVpd.empty())
161 {
162 throw std::runtime_error("Empty VPD map. Can't Extract HW value");
163 }
164
165 const auto& itrToVINI = parsedVpd.find("VINI");
166 if (itrToVINI == parsedVpd.end())
167 {
168 throw DataException("VINI record missing.");
169 }
170
171 const auto& itrToHW = (itrToVINI->second).find("HW");
172 if (itrToHW == (itrToVINI->second).end())
173 {
174 throw DataException("HW keyword missing.");
175 }
176
177 types::BinaryVector hwVal;
178 std::copy(itrToHW->second.begin(), itrToHW->second.end(),
179 back_inserter(hwVal));
180
181 // The planar pass only comes from the LSB of the HW keyword,
182 // where as the MSB is used for other purposes such as signifying clock
183 // termination.
184 hwVal[0] = 0x00;
185
186 std::ostringstream hwString;
187 for (auto& aByte : hwVal)
188 {
189 hwString << std::setw(2) << std::setfill('0') << std::hex
190 << static_cast<int>(aByte);
191 }
192
193 return hwString.str();
194}
195
196void Worker::fillVPDMap(const std::string& vpdFilePath,
197 types::VPDMapVariant& vpdMap)
198{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500199 if (vpdFilePath.empty())
200 {
201 throw std::runtime_error("Invalid file path passed to fillVPDMap API.");
202 }
203
204 if (!std::filesystem::exists(vpdFilePath))
205 {
206 throw std::runtime_error("Can't Find physical file");
207 }
208
Sunny Srivastava043955d2025-01-21 18:04:49 +0530209 std::shared_ptr<Parser> vpdParser =
210 std::make_shared<Parser>(vpdFilePath, m_parsedJson);
211 vpdMap = vpdParser->parse();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500212}
213
214void Worker::getSystemJson(std::string& systemJson,
215 const types::VPDMapVariant& parsedVpdMap)
216{
217 if (auto pVal = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
218 {
219 std::string hwKWdValue = getHWVersion(*pVal);
220 if (hwKWdValue.empty())
221 {
222 throw DataException("HW value fetched is empty.");
223 }
224
225 const std::string& imKwdValue = getIMValue(*pVal);
226 if (imKwdValue.empty())
227 {
228 throw DataException("IM value fetched is empty.");
229 }
230
231 auto itrToIM = config::systemType.find(imKwdValue);
232 if (itrToIM == config::systemType.end())
233 {
234 throw DataException("IM keyword does not map to any system type");
235 }
236
237 const types::HWVerList hwVersionList = itrToIM->second.second;
238 if (!hwVersionList.empty())
239 {
240 transform(hwKWdValue.begin(), hwKWdValue.end(), hwKWdValue.begin(),
241 ::toupper);
242
243 auto itrToHW =
244 std::find_if(hwVersionList.begin(), hwVersionList.end(),
245 [&hwKWdValue](const auto& aPair) {
246 return aPair.first == hwKWdValue;
247 });
248
249 if (itrToHW != hwVersionList.end())
250 {
251 if (!(*itrToHW).second.empty())
252 {
253 systemJson += (*itrToIM).first + "_" + (*itrToHW).second +
254 ".json";
255 }
256 else
257 {
258 systemJson += (*itrToIM).first + ".json";
259 }
260 return;
261 }
262 }
263 systemJson += itrToIM->second.first + ".json";
264 return;
265 }
266
Sunny Srivastava043955d2025-01-21 18:04:49 +0530267 throw DataException(
268 "Invalid VPD type returned from Parser. Can't get system JSON.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500269}
270
271static void setEnvAndReboot(const std::string& key, const std::string& value)
272{
273 // set env and reboot and break.
274 commonUtility::executeCmd("/sbin/fw_setenv", key, value);
275 logging::logMessage("Rebooting BMC to pick up new device tree");
276
277 // make dbus call to reboot
278 auto bus = sdbusplus::bus::new_default_system();
279 auto method = bus.new_method_call(
280 "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
281 "org.freedesktop.systemd1.Manager", "Reboot");
282 bus.call_noreply(method);
283}
284
285void Worker::setJsonSymbolicLink(const std::string& i_systemJson)
286{
287 std::error_code l_ec;
288 l_ec.clear();
Sunny Srivastavaadff7882025-03-13 11:41:05 +0530289
290 // Check if symlink file path exists and if the JSON at this location is a
291 // symlink.
292 if (m_isSymlinkPresent &&
293 std::filesystem::is_symlink(INVENTORY_JSON_SYM_LINK, l_ec))
294 { // Don't care about exception in "is_symlink". Will continue with creation
295 // of symlink.
296
297 const auto& l_symlinkFilePth =
298 std::filesystem::read_symlink(INVENTORY_JSON_SYM_LINK, l_ec);
299
300 if (l_ec)
301 {
302 logging::logMessage(
303 "Can't read existing symlink. Error =" + l_ec.message() +
304 "Trying removal of symlink and creation of new symlink.");
305 }
306
307 // If currently set JSON is the required one. No further processing
308 // required.
309 if (i_systemJson == l_symlinkFilePth)
310 {
311 // Correct symlink already set.
312 return;
313 }
314
315 if (!std::filesystem::remove(INVENTORY_JSON_SYM_LINK, l_ec))
316 {
317 // No point going further. If removal fails for existing symlink,
318 // create will anyways throw.
319 throw std::runtime_error(
320 "Removal of symlink failed with Error = " + l_ec.message() +
321 ". Can't proceed with create_symlink.");
322 }
323 }
324
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500325 if (!std::filesystem::exists(VPD_SYMLIMK_PATH, l_ec))
326 {
327 if (l_ec)
328 {
329 throw std::runtime_error(
330 "File system call to exist failed with error = " +
331 l_ec.message());
332 }
333
334 // implies it is a fresh boot/factory reset.
335 // Create the directory for hosting the symlink
336 if (!std::filesystem::create_directories(VPD_SYMLIMK_PATH, l_ec))
337 {
338 if (l_ec)
339 {
340 throw std::runtime_error(
341 "File system call to create directory failed with error = " +
342 l_ec.message());
343 }
344 }
345 }
346
347 // create a new symlink based on the system
348 std::filesystem::create_symlink(i_systemJson, INVENTORY_JSON_SYM_LINK,
349 l_ec);
350
351 if (l_ec)
352 {
353 throw std::runtime_error(
354 "create_symlink system call failed with error: " + l_ec.message());
355 }
356
357 // If the flow is at this point implies the symlink was not present there.
358 // Considering this as factory reset.
359 m_isFactoryResetDone = true;
360}
361
362void Worker::setDeviceTreeAndJson()
363{
Anupama B R4c65fcd2025-09-01 08:09:00 -0500364 setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
365 constants::vpdCollectionInProgress);
366
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500367 // JSON is madatory for processing of this API.
368 if (m_parsedJson.empty())
369 {
Sunny Srivastava043955d2025-01-21 18:04:49 +0530370 throw JsonException("System config JSON is empty", m_configJsonPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500371 }
372
373 types::VPDMapVariant parsedVpdMap;
374 fillVPDMap(SYSTEM_VPD_FILE_PATH, parsedVpdMap);
375
376 // Implies it is default JSON.
377 std::string systemJson{JSON_ABSOLUTE_PATH_PREFIX};
378
379 // ToDo: Need to check if INVENTORY_JSON_SYM_LINK pointing to correct system
380 // This is required to support movement from rainier to Blue Ridge on the
381 // fly.
382
Sunny Srivastavaadff7882025-03-13 11:41:05 +0530383 getSystemJson(systemJson, parsedVpdMap);
384
385 if (!systemJson.compare(JSON_ABSOLUTE_PATH_PREFIX))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500386 {
Sunny Srivastava043955d2025-01-21 18:04:49 +0530387 throw DataException(
388 "No system JSON found corresponding to IM read from VPD.");
Sunny Srivastavaadff7882025-03-13 11:41:05 +0530389 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500390
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500391 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500392
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500393 // re-parse the JSON once appropriate JSON has been selected.
394 m_parsedJson = jsonUtility::getParsedJson(systemJson, l_errCode);
395
396 if (l_errCode)
Sunny Srivastavaadff7882025-03-13 11:41:05 +0530397 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500398 throw(JsonException(
399 "JSON parsing failed for file [ " + systemJson +
Rekha Aparnac6159a22025-10-09 12:20:20 +0530400 " ], error : " + commonUtility::getErrCodeMsg(l_errCode),
Rekha Aparnaca9a0862025-08-29 04:08:33 -0500401 systemJson));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500402 }
403
404 std::string devTreeFromJson;
405 if (m_parsedJson.contains("devTree"))
406 {
407 devTreeFromJson = m_parsedJson["devTree"];
408
409 if (devTreeFromJson.empty())
410 {
Sunny Srivastava043955d2025-01-21 18:04:49 +0530411 EventLogger::createSyncPel(
412 types::ErrorType::JsonFailure, types::SeverityType::Error,
413 __FILE__, __FUNCTION__, 0,
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500414 "Mandatory value for device tree missing from JSON[" +
Sunny Srivastava043955d2025-01-21 18:04:49 +0530415 systemJson + "]",
416 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500417 }
418 }
419
420 auto fitConfigVal = readFitConfigValue();
421
422 if (devTreeFromJson.empty() ||
423 fitConfigVal.find(devTreeFromJson) != std::string::npos)
424 { // Skipping setting device tree as either devtree info is missing from
425 // Json or it is rightly set.
426
Sunny Srivastavaadff7882025-03-13 11:41:05 +0530427 setJsonSymbolicLink(systemJson);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500428
Rekha Aparna196e3082025-09-08 20:40:35 -0500429 if (isSystemVPDOnDBus())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500430 {
Rekha Aparna196e3082025-09-08 20:40:35 -0500431 uint16_t l_errCode = 0;
432 if (jsonUtility::isBackupAndRestoreRequired(m_parsedJson,
433 l_errCode))
434 {
435 performBackupAndRestore(parsedVpdMap);
436 }
437 else if (l_errCode)
438 {
439 logging::logMessage(
440 "Failed to check if backup and restore required. Reason : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +0530441 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna196e3082025-09-08 20:40:35 -0500442 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500443 }
444
445 // proceed to publish system VPD.
446 publishSystemVPD(parsedVpdMap);
Anupama B R4c65fcd2025-09-01 08:09:00 -0500447 setCollectionStatusProperty(SYSTEM_VPD_FILE_PATH,
448 constants::vpdCollectionCompleted);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500449 return;
450 }
451
452 setEnvAndReboot("fitconfig", devTreeFromJson);
453 exit(EXIT_SUCCESS);
454}
455
456void Worker::populateIPZVPDpropertyMap(
457 types::InterfaceMap& interfacePropMap,
458 const types::IPZKwdValueMap& keyordValueMap,
459 const std::string& interfaceName)
460{
461 types::PropertyMap propertyValueMap;
462 for (const auto& kwdVal : keyordValueMap)
463 {
464 auto kwd = kwdVal.first;
465
466 if (kwd[0] == '#')
467 {
468 kwd = std::string("PD_") + kwd[1];
469 }
470 else if (isdigit(kwd[0]))
471 {
472 kwd = std::string("N_") + kwd;
473 }
474
475 types::BinaryVector value(kwdVal.second.begin(), kwdVal.second.end());
476 propertyValueMap.emplace(move(kwd), move(value));
477 }
478
479 if (!propertyValueMap.empty())
480 {
481 interfacePropMap.emplace(interfaceName, propertyValueMap);
482 }
483}
484
485void Worker::populateKwdVPDpropertyMap(const types::KeywordVpdMap& keyordVPDMap,
486 types::InterfaceMap& interfaceMap)
487{
488 for (const auto& kwdValMap : keyordVPDMap)
489 {
490 types::PropertyMap propertyValueMap;
491 auto kwd = kwdValMap.first;
492
493 if (kwd[0] == '#')
494 {
495 kwd = std::string("PD_") + kwd[1];
496 }
497 else if (isdigit(kwd[0]))
498 {
499 kwd = std::string("N_") + kwd;
500 }
501
502 if (auto keywordValue = get_if<types::BinaryVector>(&kwdValMap.second))
503 {
504 types::BinaryVector value((*keywordValue).begin(),
505 (*keywordValue).end());
506 propertyValueMap.emplace(move(kwd), move(value));
507 }
508 else if (auto keywordValue = get_if<std::string>(&kwdValMap.second))
509 {
510 types::BinaryVector value((*keywordValue).begin(),
511 (*keywordValue).end());
512 propertyValueMap.emplace(move(kwd), move(value));
513 }
514 else if (auto keywordValue = get_if<size_t>(&kwdValMap.second))
515 {
516 if (kwd == "MemorySizeInKB")
517 {
518 types::PropertyMap memProp;
519 memProp.emplace(move(kwd), ((*keywordValue)));
520 interfaceMap.emplace("xyz.openbmc_project.Inventory.Item.Dimm",
521 move(memProp));
522 continue;
523 }
524 else
525 {
526 logging::logMessage(
527 "Unknown Keyword =" + kwd + " found in keyword VPD map");
528 continue;
529 }
530 }
531 else
532 {
533 logging::logMessage(
534 "Unknown variant type found in keyword VPD map.");
535 continue;
536 }
537
538 if (!propertyValueMap.empty())
539 {
Rekha Aparnad3662222025-10-14 10:33:17 -0500540 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500541 vpdSpecificUtility::insertOrMerge(
Rekha Aparnad3662222025-10-14 10:33:17 -0500542 interfaceMap, constants::kwdVpdInf, move(propertyValueMap),
543 l_errCode);
544
545 if (l_errCode)
546 {
547 logging::logMessage(
548 "Failed to insert value into map, error : " +
549 commonUtility::getErrCodeMsg(l_errCode));
550 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500551 }
552 }
553}
554
555void Worker::populateInterfaces(const nlohmann::json& interfaceJson,
556 types::InterfaceMap& interfaceMap,
557 const types::VPDMapVariant& parsedVpdMap)
558{
559 for (const auto& interfacesPropPair : interfaceJson.items())
560 {
561 const std::string& interface = interfacesPropPair.key();
562 types::PropertyMap propertyMap;
Rekha Aparna6256db92025-10-17 09:58:49 -0500563 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500564
565 for (const auto& propValuePair : interfacesPropPair.value().items())
566 {
567 const std::string property = propValuePair.key();
568
569 if (propValuePair.value().is_boolean())
570 {
571 propertyMap.emplace(property,
572 propValuePair.value().get<bool>());
573 }
574 else if (propValuePair.value().is_string())
575 {
576 if (property.compare("LocationCode") == 0 &&
577 interface.compare("com.ibm.ipzvpd.Location") == 0)
578 {
579 std::string value =
580 vpdSpecificUtility::getExpandedLocationCode(
581 propValuePair.value().get<std::string>(),
Rekha Aparna6256db92025-10-17 09:58:49 -0500582 parsedVpdMap, l_errCode);
583
584 if (l_errCode)
585 {
586 logging::logMessage(
587 "Failed to get expanded location code for location code - " +
588 propValuePair.value().get<std::string>() +
589 " ,error : " +
590 commonUtility::getErrCodeMsg(l_errCode));
591
592 l_errCode = 0;
593 }
594
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500595 propertyMap.emplace(property, value);
596
597 auto l_locCodeProperty = propertyMap;
598 vpdSpecificUtility::insertOrMerge(
599 interfaceMap,
600 std::string(constants::xyzLocationCodeInf),
Rekha Aparnad3662222025-10-14 10:33:17 -0500601 move(l_locCodeProperty), l_errCode);
602
603 if (l_errCode)
604 {
605 logging::logMessage(
606 "Failed to insert value into map, error : " +
607 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna6256db92025-10-17 09:58:49 -0500608
609 l_errCode = 0;
Rekha Aparnad3662222025-10-14 10:33:17 -0500610 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500611 }
612 else
613 {
614 propertyMap.emplace(
615 property, propValuePair.value().get<std::string>());
616 }
617 }
618 else if (propValuePair.value().is_array())
619 {
620 try
621 {
622 propertyMap.emplace(
623 property,
624 propValuePair.value().get<types::BinaryVector>());
625 }
626 catch (const nlohmann::detail::type_error& e)
627 {
628 std::cerr << "Type exception: " << e.what() << "\n";
629 }
630 }
631 else if (propValuePair.value().is_number())
632 {
633 // For now assume the value is a size_t. In the future it would
634 // be nice to come up with a way to get the type from the JSON.
635 propertyMap.emplace(property,
636 propValuePair.value().get<size_t>());
637 }
638 else if (propValuePair.value().is_object())
639 {
640 const std::string& record =
641 propValuePair.value().value("recordName", "");
642 const std::string& keyword =
643 propValuePair.value().value("keywordName", "");
644 const std::string& encoding =
645 propValuePair.value().value("encoding", "");
646
647 if (auto ipzVpdMap =
648 std::get_if<types::IPZVpdMap>(&parsedVpdMap))
649 {
650 if (!record.empty() && !keyword.empty() &&
651 (*ipzVpdMap).count(record) &&
652 (*ipzVpdMap).at(record).count(keyword))
653 {
654 auto encoded = vpdSpecificUtility::encodeKeyword(
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500655 ((*ipzVpdMap).at(record).at(keyword)), encoding,
656 l_errCode);
657
658 if (l_errCode)
659 {
660 logging::logMessage(
661 std::string(
662 "Failed to get encoded keyword value for : ") +
663 keyword + std::string(", error : ") +
664 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna6256db92025-10-17 09:58:49 -0500665
666 l_errCode = 0;
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500667 }
668
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500669 propertyMap.emplace(property, encoded);
670 }
671 }
672 else if (auto kwdVpdMap =
673 std::get_if<types::KeywordVpdMap>(&parsedVpdMap))
674 {
675 if (!keyword.empty() && (*kwdVpdMap).count(keyword))
676 {
677 if (auto kwValue = std::get_if<types::BinaryVector>(
678 &(*kwdVpdMap).at(keyword)))
679 {
680 auto encodedValue =
681 vpdSpecificUtility::encodeKeyword(
682 std::string((*kwValue).begin(),
683 (*kwValue).end()),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500684 encoding, l_errCode);
685
686 if (l_errCode)
687 {
688 logging::logMessage(
689 std::string(
690 "Failed to get encoded keyword value for : ") +
691 keyword + std::string(", error : ") +
692 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna6256db92025-10-17 09:58:49 -0500693
694 l_errCode = 0;
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500695 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500696
697 propertyMap.emplace(property, encodedValue);
698 }
699 else if (auto kwValue = std::get_if<std::string>(
700 &(*kwdVpdMap).at(keyword)))
701 {
702 auto encodedValue =
703 vpdSpecificUtility::encodeKeyword(
704 std::string((*kwValue).begin(),
705 (*kwValue).end()),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500706 encoding, l_errCode);
707
708 if (l_errCode)
709 {
710 logging::logMessage(
711 "Failed to get encoded keyword value for : " +
712 keyword + ", error : " +
713 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna6256db92025-10-17 09:58:49 -0500714
715 l_errCode = 0;
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500716 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500717
718 propertyMap.emplace(property, encodedValue);
719 }
720 else if (auto uintValue = std::get_if<size_t>(
721 &(*kwdVpdMap).at(keyword)))
722 {
723 propertyMap.emplace(property, *uintValue);
724 }
725 else
726 {
727 logging::logMessage(
728 "Unknown keyword found, Keywrod = " + keyword);
729 }
730 }
731 }
732 }
733 }
734 vpdSpecificUtility::insertOrMerge(interfaceMap, interface,
Rekha Aparnad3662222025-10-14 10:33:17 -0500735 move(propertyMap), l_errCode);
736
737 if (l_errCode)
738 {
739 logging::logMessage("Failed to insert value into map, error : " +
740 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna6256db92025-10-17 09:58:49 -0500741
742 l_errCode = 0;
Rekha Aparnad3662222025-10-14 10:33:17 -0500743 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500744 }
745}
746
747bool Worker::isCPUIOGoodOnly(const std::string& i_pgKeyword)
748{
749 const unsigned char l_io[] = {
750 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF,
751 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF};
752
753 // EQ0 index (in PG keyword) starts at 97 (with offset starting from 0).
754 // Each EQ carries 3 bytes of data. Totally there are 8 EQs. If all EQs'
755 // value equals 0xE7F9FF, then the cpu has no good cores and its treated as
756 // IO.
757 if (memcmp(l_io, i_pgKeyword.data() + constants::INDEX_OF_EQ0_IN_PG,
758 constants::SIZE_OF_8EQ_IN_PG) == 0)
759 {
760 return true;
761 }
762
763 // The CPU is not an IO
764 return false;
765}
766
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500767void Worker::processEmbeddedAndSynthesizedFrus(const nlohmann::json& singleFru,
768 types::InterfaceMap& interfaces)
769{
770 // embedded property(true or false) says whether the subfru is embedded
771 // into the parent fru (or) not. VPD sets Present property only for
772 // embedded frus. If the subfru is not an embedded FRU, the subfru may
773 // or may not be physically present. Those non embedded frus will always
774 // have Present=false irrespective of its physical presence or absence.
775 // Eg: nvme drive in nvme slot is not an embedded FRU. So don't set
776 // Present to true for such sub frus.
777 // Eg: ethernet port is embedded into bmc card. So set Present to true
778 // for such sub frus. Also donot populate present property for embedded
779 // subfru which is synthesized. Currently there is no subfru which are
780 // both embedded and synthesized. But still the case is handled here.
781
782 // Check if its required to handle presence for this FRU.
783 if (singleFru.value("handlePresence", true))
784 {
Rekha Aparnad3662222025-10-14 10:33:17 -0500785 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500786 types::PropertyMap presProp;
787 presProp.emplace("Present", true);
Rekha Aparnad3662222025-10-14 10:33:17 -0500788 vpdSpecificUtility::insertOrMerge(interfaces,
789 "xyz.openbmc_project.Inventory.Item",
790 move(presProp), l_errCode);
791
792 if (l_errCode)
793 {
794 logging::logMessage("Failed to insert value into map, error : " +
795 commonUtility::getErrCodeMsg(l_errCode));
796 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500797 }
798}
799
800void Worker::processExtraInterfaces(const nlohmann::json& singleFru,
801 types::InterfaceMap& interfaces,
802 const types::VPDMapVariant& parsedVpdMap)
803{
804 populateInterfaces(singleFru["extraInterfaces"], interfaces, parsedVpdMap);
805 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
806 {
807 if (singleFru["extraInterfaces"].contains(
808 "xyz.openbmc_project.Inventory.Item.Cpu"))
809 {
810 auto itrToRec = (*ipzVpdMap).find("CP00");
811 if (itrToRec == (*ipzVpdMap).end())
812 {
813 return;
814 }
815
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500816 uint16_t l_errCode = 0;
817 const std::string pgKeywordValue{vpdSpecificUtility::getKwVal(
818 itrToRec->second, "PG", l_errCode)};
Souvik Roya55fcca2025-02-19 01:33:58 -0600819
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500820 if (!pgKeywordValue.empty())
821 {
822 if (isCPUIOGoodOnly(pgKeywordValue))
823 {
824 interfaces["xyz.openbmc_project.Inventory.Item"]
825 ["PrettyName"] = "IO Module";
826 }
827 }
Souvik Roya55fcca2025-02-19 01:33:58 -0600828 else
829 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500830 throw DataException(
831 std::string(__FUNCTION__) +
832 "Failed to get value for keyword PG, error : " +
833 commonUtility::getErrCodeMsg(l_errCode));
Souvik Roya55fcca2025-02-19 01:33:58 -0600834 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500835 }
836 }
837}
838
839void Worker::processCopyRecordFlag(const nlohmann::json& singleFru,
840 const types::VPDMapVariant& parsedVpdMap,
841 types::InterfaceMap& interfaces)
842{
843 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
844 {
845 for (const auto& record : singleFru["copyRecords"])
846 {
847 const std::string& recordName = record;
848 if ((*ipzVpdMap).find(recordName) != (*ipzVpdMap).end())
849 {
850 populateIPZVPDpropertyMap(interfaces,
851 (*ipzVpdMap).at(recordName),
852 constants::ipzVpdInf + recordName);
853 }
854 }
855 }
856}
857
858void Worker::processInheritFlag(const types::VPDMapVariant& parsedVpdMap,
859 types::InterfaceMap& interfaces)
860{
861 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
862 {
863 for (const auto& [recordName, kwdValueMap] : *ipzVpdMap)
864 {
865 populateIPZVPDpropertyMap(interfaces, kwdValueMap,
866 constants::ipzVpdInf + recordName);
867 }
868 }
869 else if (auto kwdVpdMap = std::get_if<types::KeywordVpdMap>(&parsedVpdMap))
870 {
871 populateKwdVPDpropertyMap(*kwdVpdMap, interfaces);
872 }
873
874 if (m_parsedJson.contains("commonInterfaces"))
875 {
876 populateInterfaces(m_parsedJson["commonInterfaces"], interfaces,
877 parsedVpdMap);
878 }
879}
880
881bool Worker::processFruWithCCIN(const nlohmann::json& singleFru,
882 const types::VPDMapVariant& parsedVpdMap)
883{
884 if (auto ipzVPDMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
885 {
886 auto itrToRec = (*ipzVPDMap).find("VINI");
887 if (itrToRec == (*ipzVPDMap).end())
888 {
889 return false;
890 }
891
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500892 uint16_t l_errCode = 0;
Souvik Roya55fcca2025-02-19 01:33:58 -0600893 std::string ccinFromVpd{
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500894 vpdSpecificUtility::getKwVal(itrToRec->second, "CC", l_errCode)};
Souvik Roya55fcca2025-02-19 01:33:58 -0600895
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500896 if (ccinFromVpd.empty())
897 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500898 logging::logMessage("Failed to get CCIN kwd value, error : " +
899 commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500900 return false;
901 }
902
903 transform(ccinFromVpd.begin(), ccinFromVpd.end(), ccinFromVpd.begin(),
904 ::toupper);
905
906 std::vector<std::string> ccinList;
907 for (std::string ccin : singleFru["ccin"])
908 {
909 transform(ccin.begin(), ccin.end(), ccin.begin(), ::toupper);
910 ccinList.push_back(ccin);
911 }
912
913 if (ccinList.empty())
914 {
915 return false;
916 }
917
918 if (find(ccinList.begin(), ccinList.end(), ccinFromVpd) ==
919 ccinList.end())
920 {
921 return false;
922 }
923 }
924 return true;
925}
926
927void Worker::processFunctionalProperty(const std::string& i_inventoryObjPath,
928 types::InterfaceMap& io_interfaces)
929{
930 if (!dbusUtility::isChassisPowerOn())
931 {
Anupama B R68a70432025-09-25 02:09:37 -0500932 std::vector<std::string> l_operationalStatusInf = {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500933 constants::operationalStatusInf};
934
935 auto mapperObjectMap = dbusUtility::getObjectMap(
936 i_inventoryObjPath, l_operationalStatusInf);
937
938 // If the object has been found. Check if it is under PIM.
939 if (mapperObjectMap.size() != 0)
940 {
941 for (const auto& [l_serviceName, l_interfaceLsit] : mapperObjectMap)
942 {
943 if (l_serviceName == constants::pimServiceName)
944 {
945 // The object is already under PIM. No need to process
946 // again. Retain the old value.
947 return;
948 }
949 }
950 }
951
952 // Implies value is not there in D-Bus. Populate it with default
953 // value "true".
Rekha Aparnad3662222025-10-14 10:33:17 -0500954 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500955 types::PropertyMap l_functionalProp;
956 l_functionalProp.emplace("Functional", true);
957 vpdSpecificUtility::insertOrMerge(io_interfaces,
958 constants::operationalStatusInf,
Rekha Aparnad3662222025-10-14 10:33:17 -0500959 move(l_functionalProp), l_errCode);
960
961 if (l_errCode)
962 {
963 logging::logMessage(
964 "Failed to insert interface into map, error : " +
965 commonUtility::getErrCodeMsg(l_errCode));
966 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500967 }
968
969 // if chassis is power on. Functional property should be there on D-Bus.
970 // Don't process.
971 return;
972}
973
974void Worker::processEnabledProperty(const std::string& i_inventoryObjPath,
975 types::InterfaceMap& io_interfaces)
976{
977 if (!dbusUtility::isChassisPowerOn())
978 {
Anupama B R68a70432025-09-25 02:09:37 -0500979 std::vector<std::string> l_enableInf = {constants::enableInf};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500980
981 auto mapperObjectMap =
982 dbusUtility::getObjectMap(i_inventoryObjPath, l_enableInf);
983
984 // If the object has been found. Check if it is under PIM.
985 if (mapperObjectMap.size() != 0)
986 {
987 for (const auto& [l_serviceName, l_interfaceLsit] : mapperObjectMap)
988 {
989 if (l_serviceName == constants::pimServiceName)
990 {
991 // The object is already under PIM. No need to process
992 // again. Retain the old value.
993 return;
994 }
995 }
996 }
997
998 // Implies value is not there in D-Bus. Populate it with default
999 // value "true".
Rekha Aparnad3662222025-10-14 10:33:17 -05001000 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001001 types::PropertyMap l_enabledProp;
1002 l_enabledProp.emplace("Enabled", true);
1003 vpdSpecificUtility::insertOrMerge(io_interfaces, constants::enableInf,
Rekha Aparnad3662222025-10-14 10:33:17 -05001004 move(l_enabledProp), l_errCode);
1005
1006 if (l_errCode)
1007 {
1008 logging::logMessage(
1009 "Failed to insert interface into map, error : " +
1010 commonUtility::getErrCodeMsg(l_errCode));
1011 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001012 }
1013
1014 // if chassis is power on. Enabled property should be there on D-Bus.
1015 // Don't process.
1016 return;
1017}
1018
1019void Worker::populateDbus(const types::VPDMapVariant& parsedVpdMap,
1020 types::ObjectMap& objectInterfaceMap,
1021 const std::string& vpdFilePath)
1022{
1023 if (vpdFilePath.empty())
1024 {
1025 throw std::runtime_error(
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301026 std::string(__FUNCTION__) +
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001027 "Invalid parameter passed to populateDbus API.");
1028 }
1029
1030 // JSON config is mandatory for processing of "if". Add "else" for any
1031 // processing without config JSON.
1032 if (!m_parsedJson.empty())
1033 {
1034 types::InterfaceMap interfaces;
1035
1036 for (const auto& aFru : m_parsedJson["frus"][vpdFilePath])
1037 {
1038 const auto& inventoryPath = aFru["inventoryPath"];
1039 sdbusplus::message::object_path fruObjectPath(inventoryPath);
1040 if (aFru.contains("ccin"))
1041 {
1042 if (!processFruWithCCIN(aFru, parsedVpdMap))
1043 {
1044 continue;
1045 }
1046 }
1047
1048 if (aFru.value("inherit", true))
1049 {
1050 processInheritFlag(parsedVpdMap, interfaces);
1051 }
1052
1053 // If specific record needs to be copied.
1054 if (aFru.contains("copyRecords"))
1055 {
1056 processCopyRecordFlag(aFru, parsedVpdMap, interfaces);
1057 }
1058
1059 if (aFru.contains("extraInterfaces"))
1060 {
1061 // Process extra interfaces w.r.t a FRU.
1062 processExtraInterfaces(aFru, interfaces, parsedVpdMap);
1063 }
1064
1065 // Process FRUS which are embedded in the parent FRU and whose VPD
1066 // will be synthesized.
1067 if ((aFru.value("embedded", true)) &&
1068 (!aFru.value("synthesized", false)))
1069 {
1070 processEmbeddedAndSynthesizedFrus(aFru, interfaces);
1071 }
1072
1073 processFunctionalProperty(inventoryPath, interfaces);
1074 processEnabledProperty(inventoryPath, interfaces);
1075
1076 objectInterfaceMap.emplace(std::move(fruObjectPath),
1077 std::move(interfaces));
1078 }
1079 }
1080}
1081
Patrick Williams43fedab2025-02-03 14:28:05 -05001082std::string Worker::createAssetTagString(
1083 const types::VPDMapVariant& i_parsedVpdMap)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001084{
1085 std::string l_assetTag;
1086
1087 // system VPD will be in IPZ format.
1088 if (auto l_parsedVpdMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
1089 {
1090 auto l_itrToVsys = (*l_parsedVpdMap).find(constants::recVSYS);
1091 if (l_itrToVsys != (*l_parsedVpdMap).end())
1092 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001093 uint16_t l_errCode = 0;
Souvik Roya55fcca2025-02-19 01:33:58 -06001094 const std::string l_tmKwdValue{vpdSpecificUtility::getKwVal(
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001095 l_itrToVsys->second, constants::kwdTM, l_errCode)};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001096
Souvik Roya55fcca2025-02-19 01:33:58 -06001097 if (l_tmKwdValue.empty())
1098 {
1099 throw std::runtime_error(
1100 std::string("Failed to get value for keyword [") +
1101 constants::kwdTM +
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001102 std::string("] while creating Asset tag. Error : " +
1103 commonUtility::getErrCodeMsg(l_errCode)));
Souvik Roya55fcca2025-02-19 01:33:58 -06001104 }
1105
1106 const std::string l_seKwdValue{vpdSpecificUtility::getKwVal(
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001107 l_itrToVsys->second, constants::kwdSE, l_errCode)};
Souvik Roya55fcca2025-02-19 01:33:58 -06001108
1109 if (l_seKwdValue.empty())
1110 {
1111 throw std::runtime_error(
1112 std::string("Failed to get value for keyword [") +
1113 constants::kwdSE +
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001114 std::string("] while creating Asset tag. Error : " +
1115 commonUtility::getErrCodeMsg(l_errCode)));
Souvik Roya55fcca2025-02-19 01:33:58 -06001116 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001117
1118 l_assetTag = std::string{"Server-"} + l_tmKwdValue +
1119 std::string{"-"} + l_seKwdValue;
1120 }
1121 else
1122 {
1123 throw std::runtime_error(
1124 "VSYS record not found in parsed VPD map to create Asset tag.");
1125 }
1126 }
1127 else
1128 {
1129 throw std::runtime_error(
1130 "Invalid VPD type recieved to create Asset tag.");
1131 }
1132
1133 return l_assetTag;
1134}
1135
1136void Worker::publishSystemVPD(const types::VPDMapVariant& parsedVpdMap)
1137{
1138 types::ObjectMap objectInterfaceMap;
1139
1140 if (std::get_if<types::IPZVpdMap>(&parsedVpdMap))
1141 {
1142 populateDbus(parsedVpdMap, objectInterfaceMap, SYSTEM_VPD_FILE_PATH);
1143
1144 try
1145 {
1146 if (m_isFactoryResetDone)
1147 {
1148 const auto& l_assetTag = createAssetTagString(parsedVpdMap);
1149
1150 auto l_itrToSystemPath = objectInterfaceMap.find(
1151 sdbusplus::message::object_path(constants::systemInvPath));
1152 if (l_itrToSystemPath == objectInterfaceMap.end())
1153 {
1154 throw std::runtime_error(
Sunny Srivastava043955d2025-01-21 18:04:49 +05301155 "Asset tag update failed. System Path not found in object map.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001156 }
1157
1158 types::PropertyMap l_assetTagProperty;
1159 l_assetTagProperty.emplace("AssetTag", l_assetTag);
1160
1161 (l_itrToSystemPath->second)
1162 .emplace(constants::assetTagInf,
1163 std::move(l_assetTagProperty));
1164 }
1165 }
1166 catch (const std::exception& l_ex)
1167 {
1168 EventLogger::createSyncPel(
Sunny Srivastava043955d2025-01-21 18:04:49 +05301169 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
1170 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001171 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
1172 }
1173
1174 // Notify PIM
1175 if (!dbusUtility::callPIM(move(objectInterfaceMap)))
1176 {
1177 throw std::runtime_error("Call to PIM failed for system VPD");
1178 }
1179 }
1180 else
1181 {
1182 throw DataException("Invalid format of parsed VPD map.");
1183 }
1184}
1185
1186bool Worker::processPreAction(const std::string& i_vpdFilePath,
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001187 const std::string& i_flagToProcess,
1188 uint16_t& i_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001189{
1190 if (i_vpdFilePath.empty() || i_flagToProcess.empty())
1191 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001192 i_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001193 return false;
1194 }
1195
1196 if ((!jsonUtility::executeBaseAction(m_parsedJson, "preAction",
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001197 i_vpdFilePath, i_flagToProcess,
1198 i_errCode)) &&
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001199 (i_flagToProcess.compare("collection") == constants::STR_CMP_SUCCESS))
1200 {
1201 // TODO: Need a way to delete inventory object from Dbus and persisted
1202 // data section in case any FRU is not present or there is any
1203 // problem in collecting it. Once it has been deleted, it can be
1204 // re-created in the flow of priming the inventory. This needs to be
1205 // done either here or in the exception section of "parseAndPublishVPD"
1206 // API. Any failure in the process of collecting FRU will land up in the
1207 // excpetion of "parseAndPublishVPD".
1208
1209 // If the FRU is not there, clear the VINI/CCIN data.
1210 // Enity manager probes for this keyword to look for this
1211 // FRU, now if the data is persistent on BMC and FRU is
1212 // removed this can lead to ambiguity. Hence clearing this
1213 // Keyword if FRU is absent.
1214 const auto& inventoryPath =
1215 m_parsedJson["frus"][i_vpdFilePath].at(0).value("inventoryPath",
1216 "");
1217
1218 if (!inventoryPath.empty())
1219 {
1220 types::ObjectMap l_pimObjMap{
1221 {inventoryPath,
1222 {{constants::kwdVpdInf,
1223 {{constants::kwdCCIN, types::BinaryVector{}}}}}}};
1224
1225 if (!dbusUtility::callPIM(std::move(l_pimObjMap)))
1226 {
1227 logging::logMessage(
1228 "Call to PIM failed for file " + i_vpdFilePath);
1229 }
1230 }
1231 else
1232 {
1233 logging::logMessage(
1234 "Inventory path is empty in Json for file " + i_vpdFilePath);
1235 }
1236
1237 return false;
1238 }
1239 return true;
1240}
1241
1242bool Worker::processPostAction(
1243 const std::string& i_vpdFruPath, const std::string& i_flagToProcess,
1244 const std::optional<types::VPDMapVariant> i_parsedVpd)
1245{
1246 if (i_vpdFruPath.empty() || i_flagToProcess.empty())
1247 {
1248 logging::logMessage(
1249 "Invalid input parameter. Abort processing post action");
1250 return false;
1251 }
1252
1253 // Check if post action tag is to be triggered in the flow of collection
1254 // based on some CCIN value?
1255 if (m_parsedJson["frus"][i_vpdFruPath]
1256 .at(0)["postAction"][i_flagToProcess]
1257 .contains("ccin"))
1258 {
1259 if (!i_parsedVpd.has_value())
1260 {
1261 logging::logMessage("Empty VPD Map");
1262 return false;
1263 }
1264
1265 // CCIN match is required to process post action for this FRU as it
1266 // contains the flag.
1267 if (!vpdSpecificUtility::findCcinInVpd(
1268 m_parsedJson["frus"][i_vpdFruPath].at(
1269 0)["postAction"]["collection"],
1270 i_parsedVpd.value()))
1271 {
1272 // If CCIN is not found, implies post action processing is not
1273 // required for this FRU. Let the flow continue.
1274 return true;
1275 }
1276 }
1277
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001278 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001279 if (!jsonUtility::executeBaseAction(m_parsedJson, "postAction",
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001280 i_vpdFruPath, i_flagToProcess,
1281 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001282 {
1283 logging::logMessage(
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001284 "Execution of post action failed for path: " + i_vpdFruPath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301285 " . Reason: " + commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001286
1287 // If post action was required and failed only in that case return
1288 // false. In all other case post action is considered passed.
1289 return false;
1290 }
1291
1292 return true;
1293}
1294
1295types::VPDMapVariant Worker::parseVpdFile(const std::string& i_vpdFilePath)
1296{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001297 try
1298 {
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001299 uint16_t l_errCode = 0;
1300
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301301 if (i_vpdFilePath.empty())
1302 {
1303 throw std::runtime_error(
1304 std::string(__FUNCTION__) +
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301305 " Empty VPD file path passed. Abort processing");
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301306 }
1307
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301308 bool isPreActionRequired = false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001309 if (jsonUtility::isActionRequired(m_parsedJson, i_vpdFilePath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001310 "preAction", "collection", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001311 {
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001312 l_errCode = 0;
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301313 isPreActionRequired = true;
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001314 if (!processPreAction(i_vpdFilePath, "collection", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001315 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001316 if (l_errCode == error_code::DEVICE_NOT_PRESENT)
1317 {
1318 logging::logMessage(
Rekha Aparnac6159a22025-10-09 12:20:20 +05301319 commonUtility::getErrCodeMsg(l_errCode) +
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001320 i_vpdFilePath);
1321 // Presence pin has been read successfully and has been read
1322 // as false, so this is not a failure case, hence returning
1323 // empty variant so that pre action is not marked as failed.
1324 return types::VPDMapVariant{};
1325 }
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301326 throw std::runtime_error(
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001327 std::string(__FUNCTION__) +
1328 " Pre-Action failed with error: " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301329 commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001330 }
1331 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001332 else if (l_errCode)
1333 {
1334 logging::logMessage(
1335 "Failed to check if pre action required for FRU [" +
1336 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301337 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001338 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001339
1340 if (!std::filesystem::exists(i_vpdFilePath))
1341 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301342 if (isPreActionRequired)
1343 {
1344 throw std::runtime_error(
1345 std::string(__FUNCTION__) + " Could not find file path " +
1346 i_vpdFilePath + "Skipping parser trigger for the EEPROM");
1347 }
1348 return types::VPDMapVariant{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001349 }
1350
1351 std::shared_ptr<Parser> vpdParser =
1352 std::make_shared<Parser>(i_vpdFilePath, m_parsedJson);
1353
1354 types::VPDMapVariant l_parsedVpd = vpdParser->parse();
1355
1356 // Before returning, as collection is over, check if FRU qualifies for
1357 // any post action in the flow of collection.
1358 // Note: Don't change the order, post action needs to be processed only
1359 // after collection for FRU is successfully done.
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001360 l_errCode = 0;
1361
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001362 if (jsonUtility::isActionRequired(m_parsedJson, i_vpdFilePath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001363 "postAction", "collection",
1364 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001365 {
1366 if (!processPostAction(i_vpdFilePath, "collection", l_parsedVpd))
1367 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301368 // Post action was required but failed while executing.
1369 // Behaviour can be undefined.
1370 EventLogger::createSyncPel(
1371 types::ErrorType::InternalFailure,
1372 types::SeverityType::Warning, __FILE__, __FUNCTION__, 0,
1373 std::string("Required post action failed for path [" +
1374 i_vpdFilePath + "]"),
1375 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001376 }
1377 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001378 else if (l_errCode)
1379 {
1380 logging::logMessage(
1381 "Error while checking if post action required for FRU [" +
1382 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301383 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001384 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001385
1386 return l_parsedVpd;
1387 }
1388 catch (std::exception& l_ex)
1389 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001390 uint16_t l_errCode = 0;
Souvik Roy37c6bef2025-07-17 00:55:59 -05001391 std::string l_exMsg{
1392 std::string(__FUNCTION__) + " : VPD parsing failed for " +
1393 i_vpdFilePath + " due to error: " + l_ex.what()};
1394
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001395 // If post fail action is required, execute it.
1396 if (jsonUtility::isActionRequired(m_parsedJson, i_vpdFilePath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001397 "postFailAction", "collection",
1398 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001399 {
1400 if (!jsonUtility::executePostFailAction(m_parsedJson, i_vpdFilePath,
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001401 "collection", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001402 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001403 l_exMsg += ". Post fail action also failed. Error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301404 commonUtility::getErrCodeMsg(l_errCode) +
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001405 " Aborting collection for this FRU.";
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001406 }
1407 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001408 else if (l_errCode)
1409 {
1410 l_exMsg +=
1411 ". Failed to check if post fail action required, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301412 commonUtility::getErrCodeMsg(l_errCode);
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001413 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001414
Souvik Roy37c6bef2025-07-17 00:55:59 -05001415 if (typeid(l_ex) == typeid(DataException))
1416 {
1417 throw DataException(l_exMsg);
1418 }
1419 else if (typeid(l_ex) == typeid(EccException))
1420 {
1421 throw EccException(l_exMsg);
1422 }
1423 throw std::runtime_error(l_exMsg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001424 }
1425}
1426
Patrick Williams43fedab2025-02-03 14:28:05 -05001427std::tuple<bool, std::string> Worker::parseAndPublishVPD(
1428 const std::string& i_vpdFilePath)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001429{
Priyanga Ramasamy1aad7832024-12-12 22:13:52 -06001430 std::string l_inventoryPath{};
1431
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001432 try
1433 {
1434 m_semaphore.acquire();
1435
1436 // Thread launched.
1437 m_mutex.lock();
1438 m_activeCollectionThreadCount++;
1439 m_mutex.unlock();
1440
Anupama B R4c65fcd2025-09-01 08:09:00 -05001441 setCollectionStatusProperty(i_vpdFilePath,
1442 constants::vpdCollectionInProgress);
Priyanga Ramasamy1aad7832024-12-12 22:13:52 -06001443
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001444 const types::VPDMapVariant& parsedVpdMap = parseVpdFile(i_vpdFilePath);
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301445 if (!std::holds_alternative<std::monostate>(parsedVpdMap))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001446 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301447 types::ObjectMap objectInterfaceMap;
1448 populateDbus(parsedVpdMap, objectInterfaceMap, i_vpdFilePath);
1449
1450 // Notify PIM
1451 if (!dbusUtility::callPIM(move(objectInterfaceMap)))
1452 {
1453 throw std::runtime_error(
1454 std::string(__FUNCTION__) +
1455 "Call to PIM failed while publishing VPD.");
1456 }
1457 }
1458 else
1459 {
1460 logging::logMessage("Empty parsedVpdMap recieved for path [" +
1461 i_vpdFilePath + "]. Check PEL for reason.");
Anupama B R4c65fcd2025-09-01 08:09:00 -05001462
1463 // As empty parsedVpdMap recieved for some reason, but still
1464 // considered VPD collection is completed. Hence FRU collection
1465 // Status will be set as completed.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001466 }
1467 }
1468 catch (const std::exception& ex)
1469 {
Anupama B R24691d22025-05-21 08:14:15 -05001470 setCollectionStatusProperty(i_vpdFilePath,
Anupama B R5cd1b2d2025-08-05 04:57:40 -05001471 constants::vpdCollectionFailed);
Priyanga Ramasamy1aad7832024-12-12 22:13:52 -06001472
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001473 // handle all the exceptions internally. Return only true/false
1474 // based on status of execution.
1475 if (typeid(ex) == std::type_index(typeid(DataException)))
1476 {
Rekha Aparna017567a2025-08-13 02:07:06 -05001477 uint16_t l_errCode = 0;
Sunny Srivastava78c91072025-02-05 14:09:50 +05301478 // In case of pass1 planar, VPD can be corrupted on PCIe cards. Skip
1479 // logging error for these cases.
Rekha Aparna715eaff2025-10-23 02:06:50 -05001480 if (vpdSpecificUtility::isPass1Planar(l_errCode))
Sunny Srivastava78c91072025-02-05 14:09:50 +05301481 {
Rekha Aparna017567a2025-08-13 02:07:06 -05001482 std::string l_invPath =
1483 jsonUtility::getInventoryObjPathFromJson(
1484 m_parsedJson, i_vpdFilePath, l_errCode);
1485
1486 if (l_errCode != 0)
1487 {
1488 logging::logMessage(
1489 "Failed to get inventory object path from JSON for FRU [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301490 i_vpdFilePath +
1491 "], error: " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna017567a2025-08-13 02:07:06 -05001492 }
1493
RekhaAparna011ef21002025-02-18 23:47:36 -06001494 const std::string& l_invPathLeafValue =
Rekha Aparna017567a2025-08-13 02:07:06 -05001495 sdbusplus::message::object_path(l_invPath).filename();
Sunny Srivastava78c91072025-02-05 14:09:50 +05301496
RekhaAparna011ef21002025-02-18 23:47:36 -06001497 if ((l_invPathLeafValue.find("pcie_card", 0) !=
1498 std::string::npos))
Sunny Srivastava78c91072025-02-05 14:09:50 +05301499 {
1500 // skip logging any PEL for PCIe cards on pass 1 planar.
1501 return std::make_tuple(false, i_vpdFilePath);
1502 }
1503 }
Rekha Aparna715eaff2025-10-23 02:06:50 -05001504 else if (l_errCode)
1505 {
1506 logging::logMessage(
1507 "Failed to check if system is Pass 1 Planar, error : " +
1508 commonUtility::getErrCodeMsg(l_errCode));
1509 }
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301510 }
Sunny Srivastava78c91072025-02-05 14:09:50 +05301511
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301512 EventLogger::createSyncPel(
Souvik Roy37c6bef2025-07-17 00:55:59 -05001513 EventLogger::getErrorType(ex),
1514 (typeid(ex) == typeid(DataException)) ||
1515 (typeid(ex) == typeid(EccException))
1516 ? types::SeverityType::Warning
1517 : types::SeverityType::Informational,
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301518 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(ex),
1519 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001520
1521 // TODO: Figure out a way to clear data in case of any failure at
1522 // runtime.
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301523
1524 // set present property to false for any error case. In future this will
1525 // be replaced by presence logic.
Souvik Roy6a9553c2025-02-07 01:16:32 -06001526 // Update Present property for this FRU only if we handle Present
1527 // property for the FRU.
1528 if (isPresentPropertyHandlingRequired(
1529 m_parsedJson["frus"][i_vpdFilePath].at(0)))
1530 {
1531 setPresentProperty(i_vpdFilePath, false);
1532 }
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301533
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001534 m_semaphore.release();
1535 return std::make_tuple(false, i_vpdFilePath);
1536 }
Anupama B R4c65fcd2025-09-01 08:09:00 -05001537
1538 setCollectionStatusProperty(i_vpdFilePath,
1539 constants::vpdCollectionCompleted);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001540 m_semaphore.release();
1541 return std::make_tuple(true, i_vpdFilePath);
1542}
1543
Sunny Srivastava61611752025-02-04 00:29:33 -06001544bool Worker::skipPathForCollection(const std::string& i_vpdFilePath)
1545{
1546 if (i_vpdFilePath.empty())
1547 {
1548 return true;
1549 }
1550
1551 // skip processing of system VPD again as it has been already collected.
1552 if (i_vpdFilePath == SYSTEM_VPD_FILE_PATH)
1553 {
1554 return true;
1555 }
1556
1557 if (dbusUtility::isChassisPowerOn())
1558 {
1559 // If chassis is powered on, skip collecting FRUs which are
1560 // powerOffOnly.
Rekha Aparna52041882025-09-01 20:48:07 -05001561
1562 uint16_t l_errCode = 0;
1563 if (jsonUtility::isFruPowerOffOnly(m_parsedJson, i_vpdFilePath,
1564 l_errCode))
Sunny Srivastava61611752025-02-04 00:29:33 -06001565 {
1566 return true;
1567 }
Rekha Aparna52041882025-09-01 20:48:07 -05001568 else if (l_errCode)
1569 {
1570 logging::logMessage(
1571 "Failed to check if FRU is power off only for FRU [" +
1572 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301573 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna52041882025-09-01 20:48:07 -05001574 }
Sunny Srivastava61611752025-02-04 00:29:33 -06001575
Rekha Aparna52041882025-09-01 20:48:07 -05001576 l_errCode = 0;
Rekha Aparna017567a2025-08-13 02:07:06 -05001577 std::string l_invPath = jsonUtility::getInventoryObjPathFromJson(
1578 m_parsedJson, i_vpdFilePath, l_errCode);
1579
1580 if (l_errCode)
1581 {
1582 logging::logMessage(
1583 "Failed to get inventory path from JSON for FRU [" +
1584 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301585 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna017567a2025-08-13 02:07:06 -05001586
1587 return false;
1588 }
1589
Sunny Srivastava61611752025-02-04 00:29:33 -06001590 const std::string& l_invPathLeafValue =
Rekha Aparna017567a2025-08-13 02:07:06 -05001591 sdbusplus::message::object_path(l_invPath).filename();
Sunny Srivastava61611752025-02-04 00:29:33 -06001592
1593 if ((l_invPathLeafValue.find("pcie_card", 0) != std::string::npos))
1594 {
1595 return true;
1596 }
1597 }
1598
1599 return false;
1600}
1601
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001602void Worker::collectFrusFromJson()
1603{
1604 // A parsed JSON file should be present to pick FRUs EEPROM paths
1605 if (m_parsedJson.empty())
1606 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301607 throw JsonException(
1608 std::string(__FUNCTION__) +
1609 ": Config JSON is mandatory for processing of FRUs through this API.",
1610 m_configJsonPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001611 }
1612
1613 const nlohmann::json& listOfFrus =
1614 m_parsedJson["frus"].get_ref<const nlohmann::json::object_t&>();
1615
1616 for (const auto& itemFRUS : listOfFrus.items())
1617 {
1618 const std::string& vpdFilePath = itemFRUS.key();
1619
Sunny Srivastava61611752025-02-04 00:29:33 -06001620 if (skipPathForCollection(vpdFilePath))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001621 {
1622 continue;
1623 }
1624
Souvik Roy1f4c8f82025-01-23 00:37:43 -06001625 try
1626 {
1627 std::thread{[vpdFilePath, this]() {
1628 const auto& l_parseResult = parseAndPublishVPD(vpdFilePath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001629
Souvik Roy1f4c8f82025-01-23 00:37:43 -06001630 m_mutex.lock();
1631 m_activeCollectionThreadCount--;
1632 m_mutex.unlock();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001633
Souvik Roy1f4c8f82025-01-23 00:37:43 -06001634 if (!m_activeCollectionThreadCount)
1635 {
1636 m_isAllFruCollected = true;
1637 }
1638 }}.detach();
1639 }
1640 catch (const std::exception& l_ex)
1641 {
1642 // add vpdFilePath(EEPROM path) to failed list
1643 m_failedEepromPaths.push_front(vpdFilePath);
1644 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001645 }
1646}
1647
1648// ToDo: Move the API under IBM_SYSTEM
1649void Worker::performBackupAndRestore(types::VPDMapVariant& io_srcVpdMap)
1650{
1651 try
1652 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001653 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001654 std::string l_backupAndRestoreCfgFilePath =
1655 m_parsedJson.value("backupRestoreConfigPath", "");
1656
1657 nlohmann::json l_backupAndRestoreCfgJsonObj =
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001658 jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath,
1659 l_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001660
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001661 if (l_errCode)
RekhaAparna011ef21002025-02-18 23:47:36 -06001662 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001663 throw JsonException(
1664 "JSON parsing failed for file [ " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301665 l_backupAndRestoreCfgFilePath +
1666 " ], error : " + commonUtility::getErrCodeMsg(l_errCode),
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001667 l_backupAndRestoreCfgFilePath);
RekhaAparna011ef21002025-02-18 23:47:36 -06001668 }
1669
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001670 // check if either of "source" or "destination" has inventory path.
1671 // this indicates that this sytem has System VPD on hardware
1672 // and other copy on D-Bus (BMC cache).
1673 if (!l_backupAndRestoreCfgJsonObj.empty() &&
1674 ((l_backupAndRestoreCfgJsonObj.contains("source") &&
1675 l_backupAndRestoreCfgJsonObj["source"].contains(
1676 "inventoryPath")) ||
1677 (l_backupAndRestoreCfgJsonObj.contains("destination") &&
1678 l_backupAndRestoreCfgJsonObj["destination"].contains(
1679 "inventoryPath"))))
1680 {
1681 BackupAndRestore l_backupAndRestoreObj(m_parsedJson);
1682 auto [l_srcVpdVariant,
1683 l_dstVpdVariant] = l_backupAndRestoreObj.backupAndRestore();
1684
1685 // ToDo: Revisit is this check is required or not.
1686 if (auto l_srcVpdMap =
1687 std::get_if<types::IPZVpdMap>(&l_srcVpdVariant);
1688 l_srcVpdMap && !(*l_srcVpdMap).empty())
1689 {
1690 io_srcVpdMap = std::move(l_srcVpdVariant);
1691 }
1692 }
1693 }
1694 catch (const std::exception& l_ex)
1695 {
1696 EventLogger::createSyncPel(
Sunny Srivastava043955d2025-01-21 18:04:49 +05301697 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
Sunny Srivastava15a189a2025-02-26 16:53:19 +05301698 __FILE__, __FUNCTION__, 0,
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001699 std::string(
1700 "Exception caught while backup and restore VPD keyword's.") +
Sunny Srivastava15a189a2025-02-26 16:53:19 +05301701 EventLogger::getErrorMsg(l_ex),
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001702 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
1703 }
1704}
1705
1706void Worker::deleteFruVpd(const std::string& i_dbusObjPath)
1707{
1708 if (i_dbusObjPath.empty())
1709 {
1710 throw std::runtime_error("Given DBus object path is empty.");
1711 }
1712
Rekha Aparna0578dd22025-09-02 08:20:21 -05001713 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001714 const std::string& l_fruPath =
Rekha Aparna0578dd22025-09-02 08:20:21 -05001715 jsonUtility::getFruPathFromJson(m_parsedJson, i_dbusObjPath, l_errCode);
1716
1717 if (l_errCode)
1718 {
1719 logging::logMessage(
1720 "Failed to get FRU path for inventory path [" + i_dbusObjPath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301721 "], error : " + commonUtility::getErrCodeMsg(l_errCode) +
Rekha Aparna0578dd22025-09-02 08:20:21 -05001722 " Aborting FRU VPD deletion.");
1723 return;
1724 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001725
1726 try
1727 {
1728 auto l_presentPropValue = dbusUtility::readDbusProperty(
1729 constants::pimServiceName, i_dbusObjPath,
1730 constants::inventoryItemInf, "Present");
1731
1732 if (auto l_value = std::get_if<bool>(&l_presentPropValue))
1733 {
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001734 uint16_t l_errCode = 0;
Souvik Roye9120152025-07-02 08:24:38 -05001735 // check if FRU's Present property is handled by vpd-manager
1736 const auto& l_isFruPresenceHandled =
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001737 jsonUtility::isFruPresenceHandled(m_parsedJson, l_fruPath,
1738 l_errCode);
1739
1740 if (l_errCode)
1741 {
1742 throw std::runtime_error(
1743 "Failed to check if FRU's presence is handled, reason: " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301744 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001745 }
Souvik Roye9120152025-07-02 08:24:38 -05001746
1747 if (!(*l_value) && l_isFruPresenceHandled)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001748 {
1749 throw std::runtime_error("Given FRU is not present");
1750 }
Souvik Roye9120152025-07-02 08:24:38 -05001751 else if (*l_value && !l_isFruPresenceHandled)
1752 {
1753 throw std::runtime_error(
1754 "Given FRU is present and its presence is not handled by vpd-manager.");
1755 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001756 else
1757 {
1758 if (jsonUtility::isActionRequired(m_parsedJson, l_fruPath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001759 "preAction", "deletion",
1760 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001761 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001762 if (!processPreAction(l_fruPath, "deletion", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001763 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001764 std::string l_msg = "Pre action failed";
1765 if (l_errCode)
1766 {
Rekha Aparnac6159a22025-10-09 12:20:20 +05301767 l_msg += " Reason: " +
1768 commonUtility::getErrCodeMsg(l_errCode);
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001769 }
1770 throw std::runtime_error(l_msg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001771 }
1772 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001773 else if (l_errCode)
1774 {
1775 logging::logMessage(
1776 "Failed to check if pre action required for FRU [" +
1777 l_fruPath + "], error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301778 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001779 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001780
1781 std::vector<std::string> l_interfaceList{
1782 constants::operationalStatusInf};
1783
1784 types::MapperGetSubTree l_subTreeMap =
1785 dbusUtility::getObjectSubTree(i_dbusObjPath, 0,
1786 l_interfaceList);
1787
1788 types::ObjectMap l_objectMap;
1789
1790 // Updates VPD specific interfaces property value under PIM for
1791 // sub FRUs.
1792 for (const auto& [l_objectPath, l_serviceInterfaceMap] :
1793 l_subTreeMap)
1794 {
Rekha Aparna2c04eeb2025-10-22 22:15:07 -05001795 l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001796 types::InterfaceMap l_interfaceMap;
Rekha Aparna2c04eeb2025-10-22 22:15:07 -05001797 vpdSpecificUtility::resetDataUnderPIM(
1798 l_objectPath, l_interfaceMap, l_errCode);
1799
1800 if (l_errCode)
1801 {
1802 throw std::runtime_error(
1803 "Failed to reset data under PIM for sub FRU [" +
1804 l_objectPath + "], error : " +
1805 commonUtility::getErrCodeMsg(l_errCode));
1806 }
1807
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001808 l_objectMap.emplace(l_objectPath,
1809 std::move(l_interfaceMap));
1810 }
1811
Rekha Aparna2c04eeb2025-10-22 22:15:07 -05001812 l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001813 types::InterfaceMap l_interfaceMap;
Rekha Aparna2c04eeb2025-10-22 22:15:07 -05001814 vpdSpecificUtility::resetDataUnderPIM(
1815 i_dbusObjPath, l_interfaceMap, l_errCode);
1816
1817 if (l_errCode)
1818 {
1819 throw std::runtime_error(
1820 "Failed to reset data under PIM, error : " +
1821 commonUtility::getErrCodeMsg(l_errCode));
1822 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001823
1824 l_objectMap.emplace(i_dbusObjPath, std::move(l_interfaceMap));
1825
1826 if (!dbusUtility::callPIM(std::move(l_objectMap)))
1827 {
1828 throw std::runtime_error("Call to PIM failed.");
1829 }
1830
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001831 l_errCode = 0;
1832
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001833 if (jsonUtility::isActionRequired(m_parsedJson, l_fruPath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001834 "postAction", "deletion",
1835 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001836 {
1837 if (!processPostAction(l_fruPath, "deletion"))
1838 {
1839 throw std::runtime_error("Post action failed");
1840 }
1841 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001842 else if (l_errCode)
1843 {
1844 logging::logMessage(
1845 "Failed to check if post action required during deletion for FRU [" +
1846 l_fruPath + "], error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301847 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001848 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001849 }
1850 }
1851 else
1852 {
1853 logging::logMessage(
1854 "Can't process delete VPD for FRU [" + i_dbusObjPath +
1855 "] as unable to read present property");
1856 return;
1857 }
1858
1859 logging::logMessage(
1860 "Successfully completed deletion of FRU VPD for " + i_dbusObjPath);
1861 }
1862 catch (const std::exception& l_ex)
1863 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001864 uint16_t l_errCode = 0;
1865 std::string l_errMsg =
1866 "Failed to delete VPD for FRU : " + i_dbusObjPath +
1867 " error: " + std::string(l_ex.what());
1868
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001869 if (jsonUtility::isActionRequired(m_parsedJson, l_fruPath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001870 "postFailAction", "deletion",
1871 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001872 {
1873 if (!jsonUtility::executePostFailAction(m_parsedJson, l_fruPath,
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001874 "deletion", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001875 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001876 l_errMsg += ". Post fail action also failed, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301877 commonUtility::getErrCodeMsg(l_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001878 }
1879 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001880 else if (l_errCode)
1881 {
1882 l_errMsg +=
1883 ". Failed to check if post fail action required, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301884 commonUtility::getErrCodeMsg(l_errCode);
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001885 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001886
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001887 logging::logMessage(l_errMsg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001888 }
1889}
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301890
1891void Worker::setPresentProperty(const std::string& i_vpdPath,
1892 const bool& i_value)
1893{
1894 try
1895 {
1896 if (i_vpdPath.empty())
1897 {
1898 throw std::runtime_error(
1899 "Path is empty. Can't set present property");
1900 }
1901
1902 types::ObjectMap l_objectInterfaceMap;
1903
1904 // If the given path is EEPROM path.
1905 if (m_parsedJson["frus"].contains(i_vpdPath))
1906 {
1907 for (const auto& l_Fru : m_parsedJson["frus"][i_vpdPath])
1908 {
1909 sdbusplus::message::object_path l_fruObjectPath(
1910 l_Fru["inventoryPath"]);
1911
1912 types::PropertyMap l_propertyValueMap;
1913 l_propertyValueMap.emplace("Present", i_value);
1914
Rekha Aparnad3662222025-10-14 10:33:17 -05001915 uint16_t l_errCode = 0;
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301916 types::InterfaceMap l_interfaces;
Rekha Aparnad3662222025-10-14 10:33:17 -05001917 vpdSpecificUtility::insertOrMerge(
1918 l_interfaces, constants::inventoryItemInf,
1919 move(l_propertyValueMap), l_errCode);
1920
1921 if (l_errCode)
1922 {
1923 logging::logMessage(
1924 "Failed to insert value into map, error : " +
1925 commonUtility::getErrCodeMsg(l_errCode));
1926 }
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301927
1928 l_objectInterfaceMap.emplace(std::move(l_fruObjectPath),
1929 std::move(l_interfaces));
1930 }
1931 }
1932 else
1933 {
1934 // consider it as an inventory path.
1935 if (i_vpdPath.find(constants::pimPath) != constants::VALUE_0)
1936 {
1937 throw std::runtime_error(
1938 "Invalid inventory path: " + i_vpdPath);
1939 }
1940
1941 types::PropertyMap l_propertyValueMap;
1942 l_propertyValueMap.emplace("Present", i_value);
1943
Rekha Aparnad3662222025-10-14 10:33:17 -05001944 uint16_t l_errCode = 0;
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301945 types::InterfaceMap l_interfaces;
Rekha Aparnad3662222025-10-14 10:33:17 -05001946 vpdSpecificUtility::insertOrMerge(
1947 l_interfaces, constants::inventoryItemInf,
1948 move(l_propertyValueMap), l_errCode);
1949
1950 if (l_errCode)
1951 {
1952 logging::logMessage(
1953 "Failed to insert value into map, error : " +
1954 commonUtility::getErrCodeMsg(l_errCode));
1955 }
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301956
1957 l_objectInterfaceMap.emplace(i_vpdPath, std::move(l_interfaces));
1958 }
1959
1960 // Notify PIM
1961 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
1962 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301963 throw DbusException(
1964 std::string(__FUNCTION__) +
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301965 "Call to PIM failed while setting present property for path " +
1966 i_vpdPath);
1967 }
1968 }
1969 catch (const std::exception& l_ex)
1970 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301971 EventLogger::createSyncPel(
1972 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
1973 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
1974 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301975 }
1976}
1977
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301978void Worker::performVpdRecollection()
1979{
1980 try
1981 {
1982 // Check if system config JSON is present
1983 if (m_parsedJson.empty())
1984 {
1985 throw std::runtime_error(
1986 "System config json object is empty, can't process recollection.");
1987 }
1988
Rekha Aparna88d53302025-09-01 18:16:55 -05001989 uint16_t l_errCode = 0;
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301990 const auto& l_frusReplaceableAtStandby =
Rekha Aparna88d53302025-09-01 18:16:55 -05001991 jsonUtility::getListOfFrusReplaceableAtStandby(m_parsedJson,
1992 l_errCode);
1993
1994 if (l_errCode)
1995 {
1996 logging::logMessage(
1997 "Failed to get list of FRUs replaceable at runtime, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301998 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna88d53302025-09-01 18:16:55 -05001999 return;
2000 }
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302001
2002 for (const auto& l_fruInventoryPath : l_frusReplaceableAtStandby)
2003 {
2004 // ToDo: Add some logic/trace to know the flow to
2005 // collectSingleFruVpd has been directed via
2006 // performVpdRecollection.
2007 collectSingleFruVpd(l_fruInventoryPath);
2008 }
2009 return;
2010 }
2011
2012 catch (const std::exception& l_ex)
2013 {
2014 // TODO Log PEL
2015 logging::logMessage(
2016 "VPD recollection failed with error: " + std::string(l_ex.what()));
2017 }
2018}
2019
2020void Worker::collectSingleFruVpd(
2021 const sdbusplus::message::object_path& i_dbusObjPath)
2022{
Anupama B R48f297b2025-08-13 04:29:06 -05002023 std::string l_fruPath{};
Rekha Aparna0578dd22025-09-02 08:20:21 -05002024 uint16_t l_errCode = 0;
2025
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302026 try
2027 {
2028 // Check if system config JSON is present
2029 if (m_parsedJson.empty())
2030 {
2031 logging::logMessage(
2032 "System config JSON object not present. Single FRU VPD collection is not performed for " +
2033 std::string(i_dbusObjPath));
2034 return;
2035 }
2036
2037 // Get FRU path for the given D-bus object path from JSON
Rekha Aparna0578dd22025-09-02 08:20:21 -05002038 l_fruPath = jsonUtility::getFruPathFromJson(m_parsedJson, i_dbusObjPath,
2039 l_errCode);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302040
2041 if (l_fruPath.empty())
2042 {
Rekha Aparna0578dd22025-09-02 08:20:21 -05002043 if (l_errCode)
2044 {
2045 logging::logMessage(
2046 "Failed to get FRU path for [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05302047 std::string(i_dbusObjPath) +
2048 "], error : " + commonUtility::getErrCodeMsg(l_errCode) +
Rekha Aparna0578dd22025-09-02 08:20:21 -05002049 " Aborting single FRU VPD collection.");
2050 return;
2051 }
2052
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302053 logging::logMessage(
2054 "D-bus object path not present in JSON. Single FRU VPD collection is not performed for " +
2055 std::string(i_dbusObjPath));
2056 return;
2057 }
2058
2059 // Check if host is up and running
2060 if (dbusUtility::isHostRunning())
2061 {
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05002062 uint16_t l_errCode = 0;
2063 bool isFruReplaceableAtRuntime =
2064 jsonUtility::isFruReplaceableAtRuntime(m_parsedJson, l_fruPath,
2065 l_errCode);
2066
2067 if (l_errCode)
2068 {
2069 logging::logMessage(
2070 "Failed to check if FRU is replaceable at runtime for FRU : [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05302071 std::string(i_dbusObjPath) +
2072 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05002073 return;
2074 }
2075
2076 if (!isFruReplaceableAtRuntime)
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302077 {
2078 logging::logMessage(
2079 "Given FRU is not replaceable at host runtime. Single FRU VPD collection is not performed for " +
2080 std::string(i_dbusObjPath));
2081 return;
2082 }
2083 }
2084 else if (dbusUtility::isBMCReady())
2085 {
Rekha Aparna40845612025-09-01 19:58:56 -05002086 uint16_t l_errCode = 0;
2087 bool isFruReplaceableAtStandby =
2088 jsonUtility::isFruReplaceableAtStandby(m_parsedJson, l_fruPath,
2089 l_errCode);
2090
2091 if (l_errCode)
2092 {
2093 logging::logMessage(
2094 "Error while checking if FRU is replaceable at standby for FRU [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05302095 std::string(i_dbusObjPath) +
2096 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna40845612025-09-01 19:58:56 -05002097 }
2098
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05002099 l_errCode = 0;
2100 bool isFruReplaceableAtRuntime =
2101 jsonUtility::isFruReplaceableAtRuntime(m_parsedJson, l_fruPath,
2102 l_errCode);
2103
2104 if (l_errCode)
2105 {
2106 logging::logMessage(
2107 "Failed to check if FRU is replaceable at runtime for FRU : [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05302108 std::string(i_dbusObjPath) +
2109 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05002110 return;
2111 }
2112
2113 if (!isFruReplaceableAtStandby && (!isFruReplaceableAtRuntime))
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302114 {
2115 logging::logMessage(
2116 "Given FRU is neither replaceable at standby nor replaceable at runtime. Single FRU VPD collection is not performed for " +
2117 std::string(i_dbusObjPath));
2118 return;
2119 }
2120 }
2121
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002122 // Set collection Status as InProgress. Since it's an intermediate state
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302123 // D-bus set-property call is good enough to update the status.
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002124 const std::string& l_collStatusProp = "Status";
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302125
Anupama B R4c65fcd2025-09-01 08:09:00 -05002126 setCollectionStatusProperty(l_fruPath,
2127 constants::vpdCollectionInProgress);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302128
2129 // Parse VPD
2130 types::VPDMapVariant l_parsedVpd = parseVpdFile(l_fruPath);
2131
2132 // If l_parsedVpd is pointing to std::monostate
2133 if (l_parsedVpd.index() == 0)
2134 {
2135 throw std::runtime_error(
2136 "VPD parsing failed for " + std::string(i_dbusObjPath));
2137 }
2138
2139 // Get D-bus object map from worker class
2140 types::ObjectMap l_dbusObjectMap;
2141 populateDbus(l_parsedVpd, l_dbusObjectMap, l_fruPath);
2142
2143 if (l_dbusObjectMap.empty())
2144 {
2145 throw std::runtime_error(
2146 "Failed to create D-bus object map. Single FRU VPD collection failed for " +
2147 std::string(i_dbusObjPath));
2148 }
2149
2150 // Call PIM's Notify method
2151 if (!dbusUtility::callPIM(move(l_dbusObjectMap)))
2152 {
2153 throw std::runtime_error(
2154 "Notify PIM failed. Single FRU VPD collection failed for " +
2155 std::string(i_dbusObjPath));
2156 }
Anupama B R4c65fcd2025-09-01 08:09:00 -05002157 setCollectionStatusProperty(l_fruPath,
2158 constants::vpdCollectionCompleted);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302159 }
2160 catch (const std::exception& l_error)
2161 {
Anupama B R48f297b2025-08-13 04:29:06 -05002162 setCollectionStatusProperty(l_fruPath, constants::vpdCollectionFailed);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302163 // TODO: Log PEL
2164 logging::logMessage(std::string(l_error.what()));
2165 }
2166}
Anupama B R24691d22025-05-21 08:14:15 -05002167
2168void Worker::setCollectionStatusProperty(
2169 const std::string& i_vpdPath, const std::string& i_value) const noexcept
2170{
2171 try
2172 {
2173 if (i_vpdPath.empty())
2174 {
2175 throw std::runtime_error(
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002176 "Given path is empty. Can't set collection Status property");
Anupama B R24691d22025-05-21 08:14:15 -05002177 }
2178
Anupama B R4c65fcd2025-09-01 08:09:00 -05002179 types::PropertyMap l_timeStampMap;
2180 if (i_value == constants::vpdCollectionCompleted ||
2181 i_value == constants::vpdCollectionFailed)
2182 {
2183 l_timeStampMap.emplace(
2184 "CompletedTime",
2185 types::DbusVariantType{
2186 commonUtility::getCurrentTimeSinceEpoch()});
2187 }
2188 else if (i_value == constants::vpdCollectionInProgress)
2189 {
2190 l_timeStampMap.emplace(
2191 "StartTime", types::DbusVariantType{
2192 commonUtility::getCurrentTimeSinceEpoch()});
2193 }
2194 else if (i_value == constants::vpdCollectionNotStarted)
2195 {
2196 l_timeStampMap.emplace("StartTime", 0);
2197 l_timeStampMap.emplace("CompletedTime", 0);
2198 }
2199
Anupama B R24691d22025-05-21 08:14:15 -05002200 types::ObjectMap l_objectInterfaceMap;
2201
2202 if (m_parsedJson["frus"].contains(i_vpdPath))
2203 {
2204 for (const auto& l_Fru : m_parsedJson["frus"][i_vpdPath])
2205 {
2206 sdbusplus::message::object_path l_fruObjectPath(
2207 l_Fru["inventoryPath"]);
2208
2209 types::PropertyMap l_propertyValueMap;
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002210 l_propertyValueMap.emplace("Status", i_value);
Anupama B R4c65fcd2025-09-01 08:09:00 -05002211 l_propertyValueMap.insert(l_timeStampMap.begin(),
2212 l_timeStampMap.end());
Anupama B R24691d22025-05-21 08:14:15 -05002213
Rekha Aparnad3662222025-10-14 10:33:17 -05002214 uint16_t l_errCode = 0;
Anupama B R24691d22025-05-21 08:14:15 -05002215 types::InterfaceMap l_interfaces;
2216 vpdSpecificUtility::insertOrMerge(
2217 l_interfaces, constants::vpdCollectionInterface,
Rekha Aparnad3662222025-10-14 10:33:17 -05002218 move(l_propertyValueMap), l_errCode);
2219
2220 if (l_errCode)
2221 {
2222 logging::logMessage(
2223 "Failed to insert value into map, error : " +
2224 commonUtility::getErrCodeMsg(l_errCode));
2225 }
Anupama B R24691d22025-05-21 08:14:15 -05002226
2227 l_objectInterfaceMap.emplace(std::move(l_fruObjectPath),
2228 std::move(l_interfaces));
2229 }
2230 }
2231 else
2232 {
2233 // consider it as an inventory path.
2234 if (i_vpdPath.find(constants::pimPath) != constants::VALUE_0)
2235 {
2236 throw std::runtime_error(
2237 "Invalid inventory path: " + i_vpdPath +
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002238 ". Can't set collection Status property");
Anupama B R24691d22025-05-21 08:14:15 -05002239 }
2240
2241 types::PropertyMap l_propertyValueMap;
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002242 l_propertyValueMap.emplace("Status", i_value);
Anupama B R4c65fcd2025-09-01 08:09:00 -05002243 l_propertyValueMap.insert(l_timeStampMap.begin(),
2244 l_timeStampMap.end());
Anupama B R24691d22025-05-21 08:14:15 -05002245
Rekha Aparnad3662222025-10-14 10:33:17 -05002246 uint16_t l_errCode = 0;
Anupama B R24691d22025-05-21 08:14:15 -05002247 types::InterfaceMap l_interfaces;
Rekha Aparnad3662222025-10-14 10:33:17 -05002248 vpdSpecificUtility::insertOrMerge(
2249 l_interfaces, constants::vpdCollectionInterface,
2250 move(l_propertyValueMap), l_errCode);
2251
2252 if (l_errCode)
2253 {
2254 logging::logMessage(
2255 "Failed to insert value into map, error : " +
2256 commonUtility::getErrCodeMsg(l_errCode));
2257 }
Anupama B R24691d22025-05-21 08:14:15 -05002258
2259 l_objectInterfaceMap.emplace(i_vpdPath, std::move(l_interfaces));
2260 }
2261
2262 // Notify PIM
2263 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
2264 {
2265 throw DbusException(
2266 std::string(__FUNCTION__) +
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002267 "Call to PIM failed while setting collection Status property for path " +
Anupama B R24691d22025-05-21 08:14:15 -05002268 i_vpdPath);
2269 }
2270 }
2271 catch (const std::exception& l_ex)
2272 {
2273 EventLogger::createSyncPel(
2274 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
2275 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
2276 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
2277 }
2278}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05002279} // namespace vpd