blob: a7127758b59100e0e57adf83d240c8ee97e9c344 [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));
Rekha Aparna6256db92025-10-17 09:58:49 -0500591 }
592
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500593 propertyMap.emplace(property, value);
594
595 auto l_locCodeProperty = propertyMap;
596 vpdSpecificUtility::insertOrMerge(
597 interfaceMap,
598 std::string(constants::xyzLocationCodeInf),
Rekha Aparnad3662222025-10-14 10:33:17 -0500599 move(l_locCodeProperty), l_errCode);
600
601 if (l_errCode)
602 {
603 logging::logMessage(
604 "Failed to insert value into map, error : " +
605 commonUtility::getErrCodeMsg(l_errCode));
606 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500607 }
608 else
609 {
610 propertyMap.emplace(
611 property, propValuePair.value().get<std::string>());
612 }
613 }
614 else if (propValuePair.value().is_array())
615 {
616 try
617 {
618 propertyMap.emplace(
619 property,
620 propValuePair.value().get<types::BinaryVector>());
621 }
622 catch (const nlohmann::detail::type_error& e)
623 {
624 std::cerr << "Type exception: " << e.what() << "\n";
625 }
626 }
627 else if (propValuePair.value().is_number())
628 {
629 // For now assume the value is a size_t. In the future it would
630 // be nice to come up with a way to get the type from the JSON.
631 propertyMap.emplace(property,
632 propValuePair.value().get<size_t>());
633 }
634 else if (propValuePair.value().is_object())
635 {
636 const std::string& record =
637 propValuePair.value().value("recordName", "");
638 const std::string& keyword =
639 propValuePair.value().value("keywordName", "");
640 const std::string& encoding =
641 propValuePair.value().value("encoding", "");
642
643 if (auto ipzVpdMap =
644 std::get_if<types::IPZVpdMap>(&parsedVpdMap))
645 {
646 if (!record.empty() && !keyword.empty() &&
647 (*ipzVpdMap).count(record) &&
648 (*ipzVpdMap).at(record).count(keyword))
649 {
650 auto encoded = vpdSpecificUtility::encodeKeyword(
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500651 ((*ipzVpdMap).at(record).at(keyword)), encoding,
652 l_errCode);
653
654 if (l_errCode)
655 {
656 logging::logMessage(
657 std::string(
658 "Failed to get encoded keyword value for : ") +
659 keyword + std::string(", error : ") +
660 commonUtility::getErrCodeMsg(l_errCode));
661 }
662
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500663 propertyMap.emplace(property, encoded);
664 }
665 }
666 else if (auto kwdVpdMap =
667 std::get_if<types::KeywordVpdMap>(&parsedVpdMap))
668 {
669 if (!keyword.empty() && (*kwdVpdMap).count(keyword))
670 {
671 if (auto kwValue = std::get_if<types::BinaryVector>(
672 &(*kwdVpdMap).at(keyword)))
673 {
674 auto encodedValue =
675 vpdSpecificUtility::encodeKeyword(
676 std::string((*kwValue).begin(),
677 (*kwValue).end()),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500678 encoding, l_errCode);
679
680 if (l_errCode)
681 {
682 logging::logMessage(
683 std::string(
684 "Failed to get encoded keyword value for : ") +
685 keyword + std::string(", error : ") +
686 commonUtility::getErrCodeMsg(l_errCode));
687 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500688
689 propertyMap.emplace(property, encodedValue);
690 }
691 else if (auto kwValue = std::get_if<std::string>(
692 &(*kwdVpdMap).at(keyword)))
693 {
694 auto encodedValue =
695 vpdSpecificUtility::encodeKeyword(
696 std::string((*kwValue).begin(),
697 (*kwValue).end()),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500698 encoding, l_errCode);
699
700 if (l_errCode)
701 {
702 logging::logMessage(
703 "Failed to get encoded keyword value for : " +
704 keyword + ", error : " +
705 commonUtility::getErrCodeMsg(l_errCode));
706 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500707
708 propertyMap.emplace(property, encodedValue);
709 }
710 else if (auto uintValue = std::get_if<size_t>(
711 &(*kwdVpdMap).at(keyword)))
712 {
713 propertyMap.emplace(property, *uintValue);
714 }
715 else
716 {
717 logging::logMessage(
718 "Unknown keyword found, Keywrod = " + keyword);
719 }
720 }
721 }
722 }
723 }
724 vpdSpecificUtility::insertOrMerge(interfaceMap, interface,
Rekha Aparnad3662222025-10-14 10:33:17 -0500725 move(propertyMap), l_errCode);
726
727 if (l_errCode)
728 {
729 logging::logMessage("Failed to insert value into map, error : " +
730 commonUtility::getErrCodeMsg(l_errCode));
731 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500732 }
733}
734
735bool Worker::isCPUIOGoodOnly(const std::string& i_pgKeyword)
736{
737 const unsigned char l_io[] = {
738 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF,
739 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF};
740
741 // EQ0 index (in PG keyword) starts at 97 (with offset starting from 0).
742 // Each EQ carries 3 bytes of data. Totally there are 8 EQs. If all EQs'
743 // value equals 0xE7F9FF, then the cpu has no good cores and its treated as
744 // IO.
745 if (memcmp(l_io, i_pgKeyword.data() + constants::INDEX_OF_EQ0_IN_PG,
746 constants::SIZE_OF_8EQ_IN_PG) == 0)
747 {
748 return true;
749 }
750
751 // The CPU is not an IO
752 return false;
753}
754
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500755void Worker::processEmbeddedAndSynthesizedFrus(const nlohmann::json& singleFru,
756 types::InterfaceMap& interfaces)
757{
758 // embedded property(true or false) says whether the subfru is embedded
759 // into the parent fru (or) not. VPD sets Present property only for
760 // embedded frus. If the subfru is not an embedded FRU, the subfru may
761 // or may not be physically present. Those non embedded frus will always
762 // have Present=false irrespective of its physical presence or absence.
763 // Eg: nvme drive in nvme slot is not an embedded FRU. So don't set
764 // Present to true for such sub frus.
765 // Eg: ethernet port is embedded into bmc card. So set Present to true
766 // for such sub frus. Also donot populate present property for embedded
767 // subfru which is synthesized. Currently there is no subfru which are
768 // both embedded and synthesized. But still the case is handled here.
769
770 // Check if its required to handle presence for this FRU.
771 if (singleFru.value("handlePresence", true))
772 {
Rekha Aparnad3662222025-10-14 10:33:17 -0500773 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500774 types::PropertyMap presProp;
775 presProp.emplace("Present", true);
Rekha Aparnad3662222025-10-14 10:33:17 -0500776 vpdSpecificUtility::insertOrMerge(interfaces,
777 "xyz.openbmc_project.Inventory.Item",
778 move(presProp), l_errCode);
779
780 if (l_errCode)
781 {
782 logging::logMessage("Failed to insert value into map, error : " +
783 commonUtility::getErrCodeMsg(l_errCode));
784 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500785 }
786}
787
788void Worker::processExtraInterfaces(const nlohmann::json& singleFru,
789 types::InterfaceMap& interfaces,
790 const types::VPDMapVariant& parsedVpdMap)
791{
792 populateInterfaces(singleFru["extraInterfaces"], interfaces, parsedVpdMap);
793 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
794 {
795 if (singleFru["extraInterfaces"].contains(
796 "xyz.openbmc_project.Inventory.Item.Cpu"))
797 {
798 auto itrToRec = (*ipzVpdMap).find("CP00");
799 if (itrToRec == (*ipzVpdMap).end())
800 {
801 return;
802 }
803
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500804 uint16_t l_errCode = 0;
805 const std::string pgKeywordValue{vpdSpecificUtility::getKwVal(
806 itrToRec->second, "PG", l_errCode)};
Souvik Roya55fcca2025-02-19 01:33:58 -0600807
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500808 if (!pgKeywordValue.empty())
809 {
810 if (isCPUIOGoodOnly(pgKeywordValue))
811 {
812 interfaces["xyz.openbmc_project.Inventory.Item"]
813 ["PrettyName"] = "IO Module";
814 }
815 }
Souvik Roya55fcca2025-02-19 01:33:58 -0600816 else
817 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500818 throw DataException(
819 std::string(__FUNCTION__) +
820 "Failed to get value for keyword PG, error : " +
821 commonUtility::getErrCodeMsg(l_errCode));
Souvik Roya55fcca2025-02-19 01:33:58 -0600822 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500823 }
824 }
825}
826
827void Worker::processCopyRecordFlag(const nlohmann::json& singleFru,
828 const types::VPDMapVariant& parsedVpdMap,
829 types::InterfaceMap& interfaces)
830{
831 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
832 {
833 for (const auto& record : singleFru["copyRecords"])
834 {
835 const std::string& recordName = record;
836 if ((*ipzVpdMap).find(recordName) != (*ipzVpdMap).end())
837 {
838 populateIPZVPDpropertyMap(interfaces,
839 (*ipzVpdMap).at(recordName),
840 constants::ipzVpdInf + recordName);
841 }
842 }
843 }
844}
845
846void Worker::processInheritFlag(const types::VPDMapVariant& parsedVpdMap,
847 types::InterfaceMap& interfaces)
848{
849 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
850 {
851 for (const auto& [recordName, kwdValueMap] : *ipzVpdMap)
852 {
853 populateIPZVPDpropertyMap(interfaces, kwdValueMap,
854 constants::ipzVpdInf + recordName);
855 }
856 }
857 else if (auto kwdVpdMap = std::get_if<types::KeywordVpdMap>(&parsedVpdMap))
858 {
859 populateKwdVPDpropertyMap(*kwdVpdMap, interfaces);
860 }
861
862 if (m_parsedJson.contains("commonInterfaces"))
863 {
864 populateInterfaces(m_parsedJson["commonInterfaces"], interfaces,
865 parsedVpdMap);
866 }
867}
868
869bool Worker::processFruWithCCIN(const nlohmann::json& singleFru,
870 const types::VPDMapVariant& parsedVpdMap)
871{
872 if (auto ipzVPDMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
873 {
874 auto itrToRec = (*ipzVPDMap).find("VINI");
875 if (itrToRec == (*ipzVPDMap).end())
876 {
877 return false;
878 }
879
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500880 uint16_t l_errCode = 0;
Souvik Roya55fcca2025-02-19 01:33:58 -0600881 std::string ccinFromVpd{
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500882 vpdSpecificUtility::getKwVal(itrToRec->second, "CC", l_errCode)};
Souvik Roya55fcca2025-02-19 01:33:58 -0600883
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500884 if (ccinFromVpd.empty())
885 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500886 logging::logMessage("Failed to get CCIN kwd value, error : " +
887 commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500888 return false;
889 }
890
891 transform(ccinFromVpd.begin(), ccinFromVpd.end(), ccinFromVpd.begin(),
892 ::toupper);
893
894 std::vector<std::string> ccinList;
895 for (std::string ccin : singleFru["ccin"])
896 {
897 transform(ccin.begin(), ccin.end(), ccin.begin(), ::toupper);
898 ccinList.push_back(ccin);
899 }
900
901 if (ccinList.empty())
902 {
903 return false;
904 }
905
906 if (find(ccinList.begin(), ccinList.end(), ccinFromVpd) ==
907 ccinList.end())
908 {
909 return false;
910 }
911 }
912 return true;
913}
914
915void Worker::processFunctionalProperty(const std::string& i_inventoryObjPath,
916 types::InterfaceMap& io_interfaces)
917{
918 if (!dbusUtility::isChassisPowerOn())
919 {
Anupama B R68a70432025-09-25 02:09:37 -0500920 std::vector<std::string> l_operationalStatusInf = {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500921 constants::operationalStatusInf};
922
923 auto mapperObjectMap = dbusUtility::getObjectMap(
924 i_inventoryObjPath, l_operationalStatusInf);
925
926 // If the object has been found. Check if it is under PIM.
927 if (mapperObjectMap.size() != 0)
928 {
929 for (const auto& [l_serviceName, l_interfaceLsit] : mapperObjectMap)
930 {
931 if (l_serviceName == constants::pimServiceName)
932 {
933 // The object is already under PIM. No need to process
934 // again. Retain the old value.
935 return;
936 }
937 }
938 }
939
940 // Implies value is not there in D-Bus. Populate it with default
941 // value "true".
Rekha Aparnad3662222025-10-14 10:33:17 -0500942 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500943 types::PropertyMap l_functionalProp;
944 l_functionalProp.emplace("Functional", true);
945 vpdSpecificUtility::insertOrMerge(io_interfaces,
946 constants::operationalStatusInf,
Rekha Aparnad3662222025-10-14 10:33:17 -0500947 move(l_functionalProp), l_errCode);
948
949 if (l_errCode)
950 {
951 logging::logMessage(
952 "Failed to insert interface into map, error : " +
953 commonUtility::getErrCodeMsg(l_errCode));
954 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500955 }
956
957 // if chassis is power on. Functional property should be there on D-Bus.
958 // Don't process.
959 return;
960}
961
962void Worker::processEnabledProperty(const std::string& i_inventoryObjPath,
963 types::InterfaceMap& io_interfaces)
964{
965 if (!dbusUtility::isChassisPowerOn())
966 {
Anupama B R68a70432025-09-25 02:09:37 -0500967 std::vector<std::string> l_enableInf = {constants::enableInf};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500968
969 auto mapperObjectMap =
970 dbusUtility::getObjectMap(i_inventoryObjPath, l_enableInf);
971
972 // If the object has been found. Check if it is under PIM.
973 if (mapperObjectMap.size() != 0)
974 {
975 for (const auto& [l_serviceName, l_interfaceLsit] : mapperObjectMap)
976 {
977 if (l_serviceName == constants::pimServiceName)
978 {
979 // The object is already under PIM. No need to process
980 // again. Retain the old value.
981 return;
982 }
983 }
984 }
985
986 // Implies value is not there in D-Bus. Populate it with default
987 // value "true".
Rekha Aparnad3662222025-10-14 10:33:17 -0500988 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500989 types::PropertyMap l_enabledProp;
990 l_enabledProp.emplace("Enabled", true);
991 vpdSpecificUtility::insertOrMerge(io_interfaces, constants::enableInf,
Rekha Aparnad3662222025-10-14 10:33:17 -0500992 move(l_enabledProp), l_errCode);
993
994 if (l_errCode)
995 {
996 logging::logMessage(
997 "Failed to insert interface into map, error : " +
998 commonUtility::getErrCodeMsg(l_errCode));
999 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001000 }
1001
1002 // if chassis is power on. Enabled property should be there on D-Bus.
1003 // Don't process.
1004 return;
1005}
1006
1007void Worker::populateDbus(const types::VPDMapVariant& parsedVpdMap,
1008 types::ObjectMap& objectInterfaceMap,
1009 const std::string& vpdFilePath)
1010{
1011 if (vpdFilePath.empty())
1012 {
1013 throw std::runtime_error(
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301014 std::string(__FUNCTION__) +
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001015 "Invalid parameter passed to populateDbus API.");
1016 }
1017
1018 // JSON config is mandatory for processing of "if". Add "else" for any
1019 // processing without config JSON.
1020 if (!m_parsedJson.empty())
1021 {
1022 types::InterfaceMap interfaces;
1023
1024 for (const auto& aFru : m_parsedJson["frus"][vpdFilePath])
1025 {
1026 const auto& inventoryPath = aFru["inventoryPath"];
1027 sdbusplus::message::object_path fruObjectPath(inventoryPath);
1028 if (aFru.contains("ccin"))
1029 {
1030 if (!processFruWithCCIN(aFru, parsedVpdMap))
1031 {
1032 continue;
1033 }
1034 }
1035
1036 if (aFru.value("inherit", true))
1037 {
1038 processInheritFlag(parsedVpdMap, interfaces);
1039 }
1040
1041 // If specific record needs to be copied.
1042 if (aFru.contains("copyRecords"))
1043 {
1044 processCopyRecordFlag(aFru, parsedVpdMap, interfaces);
1045 }
1046
1047 if (aFru.contains("extraInterfaces"))
1048 {
1049 // Process extra interfaces w.r.t a FRU.
1050 processExtraInterfaces(aFru, interfaces, parsedVpdMap);
1051 }
1052
1053 // Process FRUS which are embedded in the parent FRU and whose VPD
1054 // will be synthesized.
1055 if ((aFru.value("embedded", true)) &&
1056 (!aFru.value("synthesized", false)))
1057 {
1058 processEmbeddedAndSynthesizedFrus(aFru, interfaces);
1059 }
1060
1061 processFunctionalProperty(inventoryPath, interfaces);
1062 processEnabledProperty(inventoryPath, interfaces);
1063
1064 objectInterfaceMap.emplace(std::move(fruObjectPath),
1065 std::move(interfaces));
1066 }
1067 }
1068}
1069
Patrick Williams43fedab2025-02-03 14:28:05 -05001070std::string Worker::createAssetTagString(
1071 const types::VPDMapVariant& i_parsedVpdMap)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001072{
1073 std::string l_assetTag;
1074
1075 // system VPD will be in IPZ format.
1076 if (auto l_parsedVpdMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
1077 {
1078 auto l_itrToVsys = (*l_parsedVpdMap).find(constants::recVSYS);
1079 if (l_itrToVsys != (*l_parsedVpdMap).end())
1080 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001081 uint16_t l_errCode = 0;
Souvik Roya55fcca2025-02-19 01:33:58 -06001082 const std::string l_tmKwdValue{vpdSpecificUtility::getKwVal(
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001083 l_itrToVsys->second, constants::kwdTM, l_errCode)};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001084
Souvik Roya55fcca2025-02-19 01:33:58 -06001085 if (l_tmKwdValue.empty())
1086 {
1087 throw std::runtime_error(
1088 std::string("Failed to get value for keyword [") +
1089 constants::kwdTM +
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001090 std::string("] while creating Asset tag. Error : " +
1091 commonUtility::getErrCodeMsg(l_errCode)));
Souvik Roya55fcca2025-02-19 01:33:58 -06001092 }
1093
1094 const std::string l_seKwdValue{vpdSpecificUtility::getKwVal(
Rekha Aparna7d9a7062025-10-07 04:14:42 -05001095 l_itrToVsys->second, constants::kwdSE, l_errCode)};
Souvik Roya55fcca2025-02-19 01:33:58 -06001096
1097 if (l_seKwdValue.empty())
1098 {
1099 throw std::runtime_error(
1100 std::string("Failed to get value for keyword [") +
1101 constants::kwdSE +
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 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001105
1106 l_assetTag = std::string{"Server-"} + l_tmKwdValue +
1107 std::string{"-"} + l_seKwdValue;
1108 }
1109 else
1110 {
1111 throw std::runtime_error(
1112 "VSYS record not found in parsed VPD map to create Asset tag.");
1113 }
1114 }
1115 else
1116 {
1117 throw std::runtime_error(
1118 "Invalid VPD type recieved to create Asset tag.");
1119 }
1120
1121 return l_assetTag;
1122}
1123
1124void Worker::publishSystemVPD(const types::VPDMapVariant& parsedVpdMap)
1125{
1126 types::ObjectMap objectInterfaceMap;
1127
1128 if (std::get_if<types::IPZVpdMap>(&parsedVpdMap))
1129 {
1130 populateDbus(parsedVpdMap, objectInterfaceMap, SYSTEM_VPD_FILE_PATH);
1131
1132 try
1133 {
1134 if (m_isFactoryResetDone)
1135 {
1136 const auto& l_assetTag = createAssetTagString(parsedVpdMap);
1137
1138 auto l_itrToSystemPath = objectInterfaceMap.find(
1139 sdbusplus::message::object_path(constants::systemInvPath));
1140 if (l_itrToSystemPath == objectInterfaceMap.end())
1141 {
1142 throw std::runtime_error(
Sunny Srivastava043955d2025-01-21 18:04:49 +05301143 "Asset tag update failed. System Path not found in object map.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001144 }
1145
1146 types::PropertyMap l_assetTagProperty;
1147 l_assetTagProperty.emplace("AssetTag", l_assetTag);
1148
1149 (l_itrToSystemPath->second)
1150 .emplace(constants::assetTagInf,
1151 std::move(l_assetTagProperty));
1152 }
1153 }
1154 catch (const std::exception& l_ex)
1155 {
1156 EventLogger::createSyncPel(
Sunny Srivastava043955d2025-01-21 18:04:49 +05301157 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
1158 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001159 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
1160 }
1161
1162 // Notify PIM
1163 if (!dbusUtility::callPIM(move(objectInterfaceMap)))
1164 {
1165 throw std::runtime_error("Call to PIM failed for system VPD");
1166 }
1167 }
1168 else
1169 {
1170 throw DataException("Invalid format of parsed VPD map.");
1171 }
1172}
1173
1174bool Worker::processPreAction(const std::string& i_vpdFilePath,
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001175 const std::string& i_flagToProcess,
1176 uint16_t& i_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001177{
Sunny Srivastavab5fab802025-11-05 21:42:26 +05301178 i_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001179 if (i_vpdFilePath.empty() || i_flagToProcess.empty())
1180 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001181 i_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001182 return false;
1183 }
1184
1185 if ((!jsonUtility::executeBaseAction(m_parsedJson, "preAction",
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001186 i_vpdFilePath, i_flagToProcess,
1187 i_errCode)) &&
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001188 (i_flagToProcess.compare("collection") == constants::STR_CMP_SUCCESS))
1189 {
1190 // TODO: Need a way to delete inventory object from Dbus and persisted
1191 // data section in case any FRU is not present or there is any
1192 // problem in collecting it. Once it has been deleted, it can be
1193 // re-created in the flow of priming the inventory. This needs to be
1194 // done either here or in the exception section of "parseAndPublishVPD"
1195 // API. Any failure in the process of collecting FRU will land up in the
1196 // excpetion of "parseAndPublishVPD".
1197
1198 // If the FRU is not there, clear the VINI/CCIN data.
1199 // Enity manager probes for this keyword to look for this
1200 // FRU, now if the data is persistent on BMC and FRU is
1201 // removed this can lead to ambiguity. Hence clearing this
1202 // Keyword if FRU is absent.
1203 const auto& inventoryPath =
1204 m_parsedJson["frus"][i_vpdFilePath].at(0).value("inventoryPath",
1205 "");
1206
1207 if (!inventoryPath.empty())
1208 {
1209 types::ObjectMap l_pimObjMap{
1210 {inventoryPath,
1211 {{constants::kwdVpdInf,
1212 {{constants::kwdCCIN, types::BinaryVector{}}}}}}};
1213
1214 if (!dbusUtility::callPIM(std::move(l_pimObjMap)))
1215 {
1216 logging::logMessage(
1217 "Call to PIM failed for file " + i_vpdFilePath);
1218 }
1219 }
1220 else
1221 {
1222 logging::logMessage(
1223 "Inventory path is empty in Json for file " + i_vpdFilePath);
1224 }
1225
1226 return false;
1227 }
1228 return true;
1229}
1230
1231bool Worker::processPostAction(
1232 const std::string& i_vpdFruPath, const std::string& i_flagToProcess,
1233 const std::optional<types::VPDMapVariant> i_parsedVpd)
1234{
1235 if (i_vpdFruPath.empty() || i_flagToProcess.empty())
1236 {
1237 logging::logMessage(
1238 "Invalid input parameter. Abort processing post action");
1239 return false;
1240 }
1241
1242 // Check if post action tag is to be triggered in the flow of collection
1243 // based on some CCIN value?
Rekha Aparna1d8ec012025-10-22 12:37:01 -05001244 uint16_t l_errCode = 0;
1245
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001246 if (m_parsedJson["frus"][i_vpdFruPath]
1247 .at(0)["postAction"][i_flagToProcess]
1248 .contains("ccin"))
1249 {
1250 if (!i_parsedVpd.has_value())
1251 {
1252 logging::logMessage("Empty VPD Map");
1253 return false;
1254 }
1255
1256 // CCIN match is required to process post action for this FRU as it
1257 // contains the flag.
1258 if (!vpdSpecificUtility::findCcinInVpd(
1259 m_parsedJson["frus"][i_vpdFruPath].at(
1260 0)["postAction"]["collection"],
Rekha Aparna1d8ec012025-10-22 12:37:01 -05001261 i_parsedVpd.value(), l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001262 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -05001263 if (l_errCode)
1264 {
1265 // ToDo - Check if PEL is required in case of RECORD_NOT_FOUND
1266 // and KEYWORD_NOT_FOUND error codes.
1267 logging::logMessage("Failed to find CCIN in VPD, error : " +
1268 commonUtility::getErrCodeMsg(l_errCode));
1269 }
1270
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001271 // If CCIN is not found, implies post action processing is not
1272 // required for this FRU. Let the flow continue.
1273 return true;
1274 }
1275 }
1276
1277 if (!jsonUtility::executeBaseAction(m_parsedJson, "postAction",
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001278 i_vpdFruPath, i_flagToProcess,
1279 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001280 {
1281 logging::logMessage(
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001282 "Execution of post action failed for path: " + i_vpdFruPath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301283 " . Reason: " + commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001284
1285 // If post action was required and failed only in that case return
1286 // false. In all other case post action is considered passed.
1287 return false;
1288 }
1289
1290 return true;
1291}
1292
1293types::VPDMapVariant Worker::parseVpdFile(const std::string& i_vpdFilePath)
1294{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001295 try
1296 {
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001297 uint16_t l_errCode = 0;
1298
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301299 if (i_vpdFilePath.empty())
1300 {
1301 throw std::runtime_error(
1302 std::string(__FUNCTION__) +
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301303 " Empty VPD file path passed. Abort processing");
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301304 }
1305
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301306 bool isPreActionRequired = false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001307 if (jsonUtility::isActionRequired(m_parsedJson, i_vpdFilePath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001308 "preAction", "collection", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001309 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301310 isPreActionRequired = true;
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001311 if (!processPreAction(i_vpdFilePath, "collection", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001312 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001313 if (l_errCode == error_code::DEVICE_NOT_PRESENT)
1314 {
1315 logging::logMessage(
Rekha Aparnac6159a22025-10-09 12:20:20 +05301316 commonUtility::getErrCodeMsg(l_errCode) +
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001317 i_vpdFilePath);
1318 // Presence pin has been read successfully and has been read
1319 // as false, so this is not a failure case, hence returning
1320 // empty variant so that pre action is not marked as failed.
1321 return types::VPDMapVariant{};
1322 }
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301323 throw std::runtime_error(
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001324 std::string(__FUNCTION__) +
1325 " Pre-Action failed with error: " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301326 commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001327 }
1328 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001329 else if (l_errCode)
1330 {
1331 logging::logMessage(
1332 "Failed to check if pre action required for FRU [" +
1333 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301334 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001335 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001336
1337 if (!std::filesystem::exists(i_vpdFilePath))
1338 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301339 if (isPreActionRequired)
1340 {
1341 throw std::runtime_error(
1342 std::string(__FUNCTION__) + " Could not find file path " +
1343 i_vpdFilePath + "Skipping parser trigger for the EEPROM");
1344 }
1345 return types::VPDMapVariant{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001346 }
1347
1348 std::shared_ptr<Parser> vpdParser =
1349 std::make_shared<Parser>(i_vpdFilePath, m_parsedJson);
1350
1351 types::VPDMapVariant l_parsedVpd = vpdParser->parse();
1352
1353 // Before returning, as collection is over, check if FRU qualifies for
1354 // any post action in the flow of collection.
1355 // Note: Don't change the order, post action needs to be processed only
1356 // after collection for FRU is successfully done.
1357 if (jsonUtility::isActionRequired(m_parsedJson, i_vpdFilePath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001358 "postAction", "collection",
1359 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001360 {
1361 if (!processPostAction(i_vpdFilePath, "collection", l_parsedVpd))
1362 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301363 // Post action was required but failed while executing.
1364 // Behaviour can be undefined.
1365 EventLogger::createSyncPel(
1366 types::ErrorType::InternalFailure,
1367 types::SeverityType::Warning, __FILE__, __FUNCTION__, 0,
1368 std::string("Required post action failed for path [" +
1369 i_vpdFilePath + "]"),
1370 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001371 }
1372 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001373 else if (l_errCode)
1374 {
1375 logging::logMessage(
1376 "Error while checking if post action required for FRU [" +
1377 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301378 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001379 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001380
1381 return l_parsedVpd;
1382 }
1383 catch (std::exception& l_ex)
1384 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001385 uint16_t l_errCode = 0;
Souvik Roy37c6bef2025-07-17 00:55:59 -05001386 std::string l_exMsg{
1387 std::string(__FUNCTION__) + " : VPD parsing failed for " +
1388 i_vpdFilePath + " due to error: " + l_ex.what()};
1389
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001390 // If post fail action is required, execute it.
1391 if (jsonUtility::isActionRequired(m_parsedJson, i_vpdFilePath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001392 "postFailAction", "collection",
1393 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001394 {
1395 if (!jsonUtility::executePostFailAction(m_parsedJson, i_vpdFilePath,
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001396 "collection", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001397 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001398 l_exMsg += ". Post fail action also failed. Error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301399 commonUtility::getErrCodeMsg(l_errCode) +
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001400 " Aborting collection for this FRU.";
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001401 }
1402 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001403 else if (l_errCode)
1404 {
1405 l_exMsg +=
1406 ". Failed to check if post fail action required, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301407 commonUtility::getErrCodeMsg(l_errCode);
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001408 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001409
Souvik Roy37c6bef2025-07-17 00:55:59 -05001410 if (typeid(l_ex) == typeid(DataException))
1411 {
1412 throw DataException(l_exMsg);
1413 }
1414 else if (typeid(l_ex) == typeid(EccException))
1415 {
1416 throw EccException(l_exMsg);
1417 }
1418 throw std::runtime_error(l_exMsg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001419 }
1420}
1421
Patrick Williams43fedab2025-02-03 14:28:05 -05001422std::tuple<bool, std::string> Worker::parseAndPublishVPD(
1423 const std::string& i_vpdFilePath)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001424{
Priyanga Ramasamy1aad7832024-12-12 22:13:52 -06001425 std::string l_inventoryPath{};
1426
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001427 try
1428 {
1429 m_semaphore.acquire();
1430
1431 // Thread launched.
1432 m_mutex.lock();
1433 m_activeCollectionThreadCount++;
1434 m_mutex.unlock();
1435
Anupama B R4c65fcd2025-09-01 08:09:00 -05001436 setCollectionStatusProperty(i_vpdFilePath,
1437 constants::vpdCollectionInProgress);
Priyanga Ramasamy1aad7832024-12-12 22:13:52 -06001438
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001439 const types::VPDMapVariant& parsedVpdMap = parseVpdFile(i_vpdFilePath);
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301440 if (!std::holds_alternative<std::monostate>(parsedVpdMap))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001441 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301442 types::ObjectMap objectInterfaceMap;
1443 populateDbus(parsedVpdMap, objectInterfaceMap, i_vpdFilePath);
1444
1445 // Notify PIM
1446 if (!dbusUtility::callPIM(move(objectInterfaceMap)))
1447 {
1448 throw std::runtime_error(
1449 std::string(__FUNCTION__) +
1450 "Call to PIM failed while publishing VPD.");
1451 }
1452 }
1453 else
1454 {
1455 logging::logMessage("Empty parsedVpdMap recieved for path [" +
1456 i_vpdFilePath + "]. Check PEL for reason.");
Anupama B R4c65fcd2025-09-01 08:09:00 -05001457
1458 // As empty parsedVpdMap recieved for some reason, but still
1459 // considered VPD collection is completed. Hence FRU collection
1460 // Status will be set as completed.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001461 }
1462 }
1463 catch (const std::exception& ex)
1464 {
Anupama B R24691d22025-05-21 08:14:15 -05001465 setCollectionStatusProperty(i_vpdFilePath,
Anupama B R5cd1b2d2025-08-05 04:57:40 -05001466 constants::vpdCollectionFailed);
Priyanga Ramasamy1aad7832024-12-12 22:13:52 -06001467
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001468 // handle all the exceptions internally. Return only true/false
1469 // based on status of execution.
1470 if (typeid(ex) == std::type_index(typeid(DataException)))
1471 {
Rekha Aparna017567a2025-08-13 02:07:06 -05001472 uint16_t l_errCode = 0;
Sunny Srivastava78c91072025-02-05 14:09:50 +05301473 // In case of pass1 planar, VPD can be corrupted on PCIe cards. Skip
1474 // logging error for these cases.
Rekha Aparna715eaff2025-10-23 02:06:50 -05001475 if (vpdSpecificUtility::isPass1Planar(l_errCode))
Sunny Srivastava78c91072025-02-05 14:09:50 +05301476 {
Rekha Aparna017567a2025-08-13 02:07:06 -05001477 std::string l_invPath =
1478 jsonUtility::getInventoryObjPathFromJson(
1479 m_parsedJson, i_vpdFilePath, l_errCode);
1480
1481 if (l_errCode != 0)
1482 {
1483 logging::logMessage(
1484 "Failed to get inventory object path from JSON for FRU [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301485 i_vpdFilePath +
1486 "], error: " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna017567a2025-08-13 02:07:06 -05001487 }
1488
RekhaAparna011ef21002025-02-18 23:47:36 -06001489 const std::string& l_invPathLeafValue =
Rekha Aparna017567a2025-08-13 02:07:06 -05001490 sdbusplus::message::object_path(l_invPath).filename();
Sunny Srivastava78c91072025-02-05 14:09:50 +05301491
RekhaAparna011ef21002025-02-18 23:47:36 -06001492 if ((l_invPathLeafValue.find("pcie_card", 0) !=
1493 std::string::npos))
Sunny Srivastava78c91072025-02-05 14:09:50 +05301494 {
1495 // skip logging any PEL for PCIe cards on pass 1 planar.
1496 return std::make_tuple(false, i_vpdFilePath);
1497 }
1498 }
Rekha Aparna715eaff2025-10-23 02:06:50 -05001499 else if (l_errCode)
1500 {
1501 logging::logMessage(
1502 "Failed to check if system is Pass 1 Planar, error : " +
1503 commonUtility::getErrCodeMsg(l_errCode));
1504 }
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301505 }
Sunny Srivastava78c91072025-02-05 14:09:50 +05301506
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301507 EventLogger::createSyncPel(
Souvik Roy37c6bef2025-07-17 00:55:59 -05001508 EventLogger::getErrorType(ex),
1509 (typeid(ex) == typeid(DataException)) ||
1510 (typeid(ex) == typeid(EccException))
1511 ? types::SeverityType::Warning
1512 : types::SeverityType::Informational,
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301513 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(ex),
1514 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001515
1516 // TODO: Figure out a way to clear data in case of any failure at
1517 // runtime.
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301518
1519 // set present property to false for any error case. In future this will
1520 // be replaced by presence logic.
Souvik Roy6a9553c2025-02-07 01:16:32 -06001521 // Update Present property for this FRU only if we handle Present
1522 // property for the FRU.
1523 if (isPresentPropertyHandlingRequired(
1524 m_parsedJson["frus"][i_vpdFilePath].at(0)))
1525 {
1526 setPresentProperty(i_vpdFilePath, false);
1527 }
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301528
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001529 m_semaphore.release();
1530 return std::make_tuple(false, i_vpdFilePath);
1531 }
Anupama B R4c65fcd2025-09-01 08:09:00 -05001532
1533 setCollectionStatusProperty(i_vpdFilePath,
1534 constants::vpdCollectionCompleted);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001535 m_semaphore.release();
1536 return std::make_tuple(true, i_vpdFilePath);
1537}
1538
Sunny Srivastava61611752025-02-04 00:29:33 -06001539bool Worker::skipPathForCollection(const std::string& i_vpdFilePath)
1540{
1541 if (i_vpdFilePath.empty())
1542 {
1543 return true;
1544 }
1545
1546 // skip processing of system VPD again as it has been already collected.
1547 if (i_vpdFilePath == SYSTEM_VPD_FILE_PATH)
1548 {
1549 return true;
1550 }
1551
1552 if (dbusUtility::isChassisPowerOn())
1553 {
1554 // If chassis is powered on, skip collecting FRUs which are
1555 // powerOffOnly.
Rekha Aparna52041882025-09-01 20:48:07 -05001556
1557 uint16_t l_errCode = 0;
1558 if (jsonUtility::isFruPowerOffOnly(m_parsedJson, i_vpdFilePath,
1559 l_errCode))
Sunny Srivastava61611752025-02-04 00:29:33 -06001560 {
1561 return true;
1562 }
Rekha Aparna52041882025-09-01 20:48:07 -05001563 else if (l_errCode)
1564 {
1565 logging::logMessage(
1566 "Failed to check if FRU is power off only for FRU [" +
1567 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301568 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna52041882025-09-01 20:48:07 -05001569 }
Sunny Srivastava61611752025-02-04 00:29:33 -06001570
Rekha Aparna017567a2025-08-13 02:07:06 -05001571 std::string l_invPath = jsonUtility::getInventoryObjPathFromJson(
1572 m_parsedJson, i_vpdFilePath, l_errCode);
1573
1574 if (l_errCode)
1575 {
1576 logging::logMessage(
1577 "Failed to get inventory path from JSON for FRU [" +
1578 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301579 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna017567a2025-08-13 02:07:06 -05001580
1581 return false;
1582 }
1583
Sunny Srivastava61611752025-02-04 00:29:33 -06001584 const std::string& l_invPathLeafValue =
Rekha Aparna017567a2025-08-13 02:07:06 -05001585 sdbusplus::message::object_path(l_invPath).filename();
Sunny Srivastava61611752025-02-04 00:29:33 -06001586
1587 if ((l_invPathLeafValue.find("pcie_card", 0) != std::string::npos))
1588 {
1589 return true;
1590 }
1591 }
1592
1593 return false;
1594}
1595
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001596void Worker::collectFrusFromJson()
1597{
1598 // A parsed JSON file should be present to pick FRUs EEPROM paths
1599 if (m_parsedJson.empty())
1600 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301601 throw JsonException(
1602 std::string(__FUNCTION__) +
1603 ": Config JSON is mandatory for processing of FRUs through this API.",
1604 m_configJsonPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001605 }
1606
1607 const nlohmann::json& listOfFrus =
1608 m_parsedJson["frus"].get_ref<const nlohmann::json::object_t&>();
1609
1610 for (const auto& itemFRUS : listOfFrus.items())
1611 {
1612 const std::string& vpdFilePath = itemFRUS.key();
1613
Sunny Srivastava61611752025-02-04 00:29:33 -06001614 if (skipPathForCollection(vpdFilePath))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001615 {
1616 continue;
1617 }
1618
Souvik Roy1f4c8f82025-01-23 00:37:43 -06001619 try
1620 {
1621 std::thread{[vpdFilePath, this]() {
1622 const auto& l_parseResult = parseAndPublishVPD(vpdFilePath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001623
Souvik Roy1f4c8f82025-01-23 00:37:43 -06001624 m_mutex.lock();
1625 m_activeCollectionThreadCount--;
1626 m_mutex.unlock();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001627
Souvik Roy1f4c8f82025-01-23 00:37:43 -06001628 if (!m_activeCollectionThreadCount)
1629 {
1630 m_isAllFruCollected = true;
1631 }
1632 }}.detach();
1633 }
1634 catch (const std::exception& l_ex)
1635 {
1636 // add vpdFilePath(EEPROM path) to failed list
1637 m_failedEepromPaths.push_front(vpdFilePath);
1638 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001639 }
1640}
1641
1642// ToDo: Move the API under IBM_SYSTEM
1643void Worker::performBackupAndRestore(types::VPDMapVariant& io_srcVpdMap)
1644{
1645 try
1646 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001647 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001648 std::string l_backupAndRestoreCfgFilePath =
1649 m_parsedJson.value("backupRestoreConfigPath", "");
1650
1651 nlohmann::json l_backupAndRestoreCfgJsonObj =
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001652 jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath,
1653 l_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001654
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001655 if (l_errCode)
RekhaAparna011ef21002025-02-18 23:47:36 -06001656 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001657 throw JsonException(
1658 "JSON parsing failed for file [ " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301659 l_backupAndRestoreCfgFilePath +
1660 " ], error : " + commonUtility::getErrCodeMsg(l_errCode),
Rekha Aparnaca9a0862025-08-29 04:08:33 -05001661 l_backupAndRestoreCfgFilePath);
RekhaAparna011ef21002025-02-18 23:47:36 -06001662 }
1663
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001664 // check if either of "source" or "destination" has inventory path.
1665 // this indicates that this sytem has System VPD on hardware
1666 // and other copy on D-Bus (BMC cache).
1667 if (!l_backupAndRestoreCfgJsonObj.empty() &&
1668 ((l_backupAndRestoreCfgJsonObj.contains("source") &&
1669 l_backupAndRestoreCfgJsonObj["source"].contains(
1670 "inventoryPath")) ||
1671 (l_backupAndRestoreCfgJsonObj.contains("destination") &&
1672 l_backupAndRestoreCfgJsonObj["destination"].contains(
1673 "inventoryPath"))))
1674 {
1675 BackupAndRestore l_backupAndRestoreObj(m_parsedJson);
1676 auto [l_srcVpdVariant,
1677 l_dstVpdVariant] = l_backupAndRestoreObj.backupAndRestore();
1678
1679 // ToDo: Revisit is this check is required or not.
1680 if (auto l_srcVpdMap =
1681 std::get_if<types::IPZVpdMap>(&l_srcVpdVariant);
1682 l_srcVpdMap && !(*l_srcVpdMap).empty())
1683 {
1684 io_srcVpdMap = std::move(l_srcVpdVariant);
1685 }
1686 }
1687 }
1688 catch (const std::exception& l_ex)
1689 {
1690 EventLogger::createSyncPel(
Sunny Srivastava043955d2025-01-21 18:04:49 +05301691 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
Sunny Srivastava15a189a2025-02-26 16:53:19 +05301692 __FILE__, __FUNCTION__, 0,
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001693 std::string(
1694 "Exception caught while backup and restore VPD keyword's.") +
Sunny Srivastava15a189a2025-02-26 16:53:19 +05301695 EventLogger::getErrorMsg(l_ex),
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001696 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
1697 }
1698}
1699
1700void Worker::deleteFruVpd(const std::string& i_dbusObjPath)
1701{
1702 if (i_dbusObjPath.empty())
1703 {
1704 throw std::runtime_error("Given DBus object path is empty.");
1705 }
1706
Rekha Aparna0578dd22025-09-02 08:20:21 -05001707 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001708 const std::string& l_fruPath =
Rekha Aparna0578dd22025-09-02 08:20:21 -05001709 jsonUtility::getFruPathFromJson(m_parsedJson, i_dbusObjPath, l_errCode);
1710
1711 if (l_errCode)
1712 {
1713 logging::logMessage(
1714 "Failed to get FRU path for inventory path [" + i_dbusObjPath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301715 "], error : " + commonUtility::getErrCodeMsg(l_errCode) +
Rekha Aparna0578dd22025-09-02 08:20:21 -05001716 " Aborting FRU VPD deletion.");
1717 return;
1718 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001719
1720 try
1721 {
1722 auto l_presentPropValue = dbusUtility::readDbusProperty(
1723 constants::pimServiceName, i_dbusObjPath,
1724 constants::inventoryItemInf, "Present");
1725
1726 if (auto l_value = std::get_if<bool>(&l_presentPropValue))
1727 {
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001728 uint16_t l_errCode = 0;
Souvik Roye9120152025-07-02 08:24:38 -05001729 // check if FRU's Present property is handled by vpd-manager
1730 const auto& l_isFruPresenceHandled =
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001731 jsonUtility::isFruPresenceHandled(m_parsedJson, l_fruPath,
1732 l_errCode);
1733
1734 if (l_errCode)
1735 {
1736 throw std::runtime_error(
1737 "Failed to check if FRU's presence is handled, reason: " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301738 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001739 }
Souvik Roye9120152025-07-02 08:24:38 -05001740
1741 if (!(*l_value) && l_isFruPresenceHandled)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001742 {
1743 throw std::runtime_error("Given FRU is not present");
1744 }
Souvik Roye9120152025-07-02 08:24:38 -05001745 else if (*l_value && !l_isFruPresenceHandled)
1746 {
1747 throw std::runtime_error(
1748 "Given FRU is present and its presence is not handled by vpd-manager.");
1749 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001750 else
1751 {
1752 if (jsonUtility::isActionRequired(m_parsedJson, l_fruPath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001753 "preAction", "deletion",
1754 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001755 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001756 if (!processPreAction(l_fruPath, "deletion", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001757 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001758 std::string l_msg = "Pre action failed";
1759 if (l_errCode)
1760 {
Rekha Aparnac6159a22025-10-09 12:20:20 +05301761 l_msg += " Reason: " +
1762 commonUtility::getErrCodeMsg(l_errCode);
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001763 }
1764 throw std::runtime_error(l_msg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001765 }
1766 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001767 else if (l_errCode)
1768 {
1769 logging::logMessage(
1770 "Failed to check if pre action required for FRU [" +
1771 l_fruPath + "], error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301772 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001773 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001774
1775 std::vector<std::string> l_interfaceList{
1776 constants::operationalStatusInf};
1777
1778 types::MapperGetSubTree l_subTreeMap =
1779 dbusUtility::getObjectSubTree(i_dbusObjPath, 0,
1780 l_interfaceList);
1781
1782 types::ObjectMap l_objectMap;
1783
1784 // Updates VPD specific interfaces property value under PIM for
1785 // sub FRUs.
1786 for (const auto& [l_objectPath, l_serviceInterfaceMap] :
1787 l_subTreeMap)
1788 {
1789 types::InterfaceMap l_interfaceMap;
Rekha Aparna2c04eeb2025-10-22 22:15:07 -05001790 vpdSpecificUtility::resetDataUnderPIM(
1791 l_objectPath, l_interfaceMap, l_errCode);
1792
1793 if (l_errCode)
1794 {
1795 throw std::runtime_error(
1796 "Failed to reset data under PIM for sub FRU [" +
1797 l_objectPath + "], error : " +
1798 commonUtility::getErrCodeMsg(l_errCode));
1799 }
1800
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001801 l_objectMap.emplace(l_objectPath,
1802 std::move(l_interfaceMap));
1803 }
1804
1805 types::InterfaceMap l_interfaceMap;
Rekha Aparna2c04eeb2025-10-22 22:15:07 -05001806 vpdSpecificUtility::resetDataUnderPIM(
1807 i_dbusObjPath, l_interfaceMap, l_errCode);
1808
1809 if (l_errCode)
1810 {
1811 throw std::runtime_error(
1812 "Failed to reset data under PIM, error : " +
1813 commonUtility::getErrCodeMsg(l_errCode));
1814 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001815
1816 l_objectMap.emplace(i_dbusObjPath, std::move(l_interfaceMap));
1817
1818 if (!dbusUtility::callPIM(std::move(l_objectMap)))
1819 {
1820 throw std::runtime_error("Call to PIM failed.");
1821 }
1822
1823 if (jsonUtility::isActionRequired(m_parsedJson, l_fruPath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001824 "postAction", "deletion",
1825 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001826 {
1827 if (!processPostAction(l_fruPath, "deletion"))
1828 {
1829 throw std::runtime_error("Post action failed");
1830 }
1831 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001832 else if (l_errCode)
1833 {
1834 logging::logMessage(
1835 "Failed to check if post action required during deletion for FRU [" +
1836 l_fruPath + "], error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301837 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001838 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001839 }
1840 }
1841 else
1842 {
1843 logging::logMessage(
1844 "Can't process delete VPD for FRU [" + i_dbusObjPath +
1845 "] as unable to read present property");
1846 return;
1847 }
1848
1849 logging::logMessage(
1850 "Successfully completed deletion of FRU VPD for " + i_dbusObjPath);
1851 }
1852 catch (const std::exception& l_ex)
1853 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001854 uint16_t l_errCode = 0;
1855 std::string l_errMsg =
1856 "Failed to delete VPD for FRU : " + i_dbusObjPath +
1857 " error: " + std::string(l_ex.what());
1858
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001859 if (jsonUtility::isActionRequired(m_parsedJson, l_fruPath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001860 "postFailAction", "deletion",
1861 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001862 {
1863 if (!jsonUtility::executePostFailAction(m_parsedJson, l_fruPath,
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001864 "deletion", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001865 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001866 l_errMsg += ". Post fail action also failed, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301867 commonUtility::getErrCodeMsg(l_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001868 }
1869 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001870 else if (l_errCode)
1871 {
1872 l_errMsg +=
1873 ". Failed to check if post fail action required, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301874 commonUtility::getErrCodeMsg(l_errCode);
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001875 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001876
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001877 logging::logMessage(l_errMsg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001878 }
1879}
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301880
1881void Worker::setPresentProperty(const std::string& i_vpdPath,
1882 const bool& i_value)
1883{
1884 try
1885 {
1886 if (i_vpdPath.empty())
1887 {
1888 throw std::runtime_error(
1889 "Path is empty. Can't set present property");
1890 }
1891
1892 types::ObjectMap l_objectInterfaceMap;
1893
1894 // If the given path is EEPROM path.
1895 if (m_parsedJson["frus"].contains(i_vpdPath))
1896 {
1897 for (const auto& l_Fru : m_parsedJson["frus"][i_vpdPath])
1898 {
1899 sdbusplus::message::object_path l_fruObjectPath(
1900 l_Fru["inventoryPath"]);
1901
1902 types::PropertyMap l_propertyValueMap;
1903 l_propertyValueMap.emplace("Present", i_value);
1904
Rekha Aparnad3662222025-10-14 10:33:17 -05001905 uint16_t l_errCode = 0;
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301906 types::InterfaceMap l_interfaces;
Rekha Aparnad3662222025-10-14 10:33:17 -05001907 vpdSpecificUtility::insertOrMerge(
1908 l_interfaces, constants::inventoryItemInf,
1909 move(l_propertyValueMap), l_errCode);
1910
1911 if (l_errCode)
1912 {
1913 logging::logMessage(
1914 "Failed to insert value into map, error : " +
1915 commonUtility::getErrCodeMsg(l_errCode));
1916 }
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301917
1918 l_objectInterfaceMap.emplace(std::move(l_fruObjectPath),
1919 std::move(l_interfaces));
1920 }
1921 }
1922 else
1923 {
1924 // consider it as an inventory path.
1925 if (i_vpdPath.find(constants::pimPath) != constants::VALUE_0)
1926 {
1927 throw std::runtime_error(
1928 "Invalid inventory path: " + i_vpdPath);
1929 }
1930
1931 types::PropertyMap l_propertyValueMap;
1932 l_propertyValueMap.emplace("Present", i_value);
1933
Rekha Aparnad3662222025-10-14 10:33:17 -05001934 uint16_t l_errCode = 0;
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301935 types::InterfaceMap l_interfaces;
Rekha Aparnad3662222025-10-14 10:33:17 -05001936 vpdSpecificUtility::insertOrMerge(
1937 l_interfaces, constants::inventoryItemInf,
1938 move(l_propertyValueMap), l_errCode);
1939
1940 if (l_errCode)
1941 {
1942 logging::logMessage(
1943 "Failed to insert value into map, error : " +
1944 commonUtility::getErrCodeMsg(l_errCode));
1945 }
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301946
1947 l_objectInterfaceMap.emplace(i_vpdPath, std::move(l_interfaces));
1948 }
1949
1950 // Notify PIM
1951 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
1952 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301953 throw DbusException(
1954 std::string(__FUNCTION__) +
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301955 "Call to PIM failed while setting present property for path " +
1956 i_vpdPath);
1957 }
1958 }
1959 catch (const std::exception& l_ex)
1960 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301961 EventLogger::createSyncPel(
1962 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
1963 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
1964 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301965 }
1966}
1967
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301968void Worker::performVpdRecollection()
1969{
1970 try
1971 {
1972 // Check if system config JSON is present
1973 if (m_parsedJson.empty())
1974 {
1975 throw std::runtime_error(
1976 "System config json object is empty, can't process recollection.");
1977 }
1978
Rekha Aparna88d53302025-09-01 18:16:55 -05001979 uint16_t l_errCode = 0;
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301980 const auto& l_frusReplaceableAtStandby =
Rekha Aparna88d53302025-09-01 18:16:55 -05001981 jsonUtility::getListOfFrusReplaceableAtStandby(m_parsedJson,
1982 l_errCode);
1983
1984 if (l_errCode)
1985 {
1986 logging::logMessage(
1987 "Failed to get list of FRUs replaceable at runtime, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301988 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna88d53302025-09-01 18:16:55 -05001989 return;
1990 }
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301991
1992 for (const auto& l_fruInventoryPath : l_frusReplaceableAtStandby)
1993 {
1994 // ToDo: Add some logic/trace to know the flow to
1995 // collectSingleFruVpd has been directed via
1996 // performVpdRecollection.
1997 collectSingleFruVpd(l_fruInventoryPath);
1998 }
1999 return;
2000 }
2001
2002 catch (const std::exception& l_ex)
2003 {
2004 // TODO Log PEL
2005 logging::logMessage(
2006 "VPD recollection failed with error: " + std::string(l_ex.what()));
2007 }
2008}
2009
2010void Worker::collectSingleFruVpd(
2011 const sdbusplus::message::object_path& i_dbusObjPath)
2012{
Anupama B R48f297b2025-08-13 04:29:06 -05002013 std::string l_fruPath{};
Rekha Aparna0578dd22025-09-02 08:20:21 -05002014 uint16_t l_errCode = 0;
2015
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302016 try
2017 {
2018 // Check if system config JSON is present
2019 if (m_parsedJson.empty())
2020 {
2021 logging::logMessage(
2022 "System config JSON object not present. Single FRU VPD collection is not performed for " +
2023 std::string(i_dbusObjPath));
2024 return;
2025 }
2026
2027 // Get FRU path for the given D-bus object path from JSON
Rekha Aparna0578dd22025-09-02 08:20:21 -05002028 l_fruPath = jsonUtility::getFruPathFromJson(m_parsedJson, i_dbusObjPath,
2029 l_errCode);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302030
2031 if (l_fruPath.empty())
2032 {
Rekha Aparna0578dd22025-09-02 08:20:21 -05002033 if (l_errCode)
2034 {
2035 logging::logMessage(
2036 "Failed to get FRU path for [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05302037 std::string(i_dbusObjPath) +
2038 "], error : " + commonUtility::getErrCodeMsg(l_errCode) +
Rekha Aparna0578dd22025-09-02 08:20:21 -05002039 " Aborting single FRU VPD collection.");
2040 return;
2041 }
2042
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302043 logging::logMessage(
2044 "D-bus object path not present in JSON. Single FRU VPD collection is not performed for " +
2045 std::string(i_dbusObjPath));
2046 return;
2047 }
2048
2049 // Check if host is up and running
2050 if (dbusUtility::isHostRunning())
2051 {
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05002052 uint16_t l_errCode = 0;
2053 bool isFruReplaceableAtRuntime =
2054 jsonUtility::isFruReplaceableAtRuntime(m_parsedJson, l_fruPath,
2055 l_errCode);
2056
2057 if (l_errCode)
2058 {
2059 logging::logMessage(
2060 "Failed to check if FRU is replaceable at runtime for FRU : [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05302061 std::string(i_dbusObjPath) +
2062 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05002063 return;
2064 }
2065
2066 if (!isFruReplaceableAtRuntime)
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302067 {
2068 logging::logMessage(
2069 "Given FRU is not replaceable at host runtime. Single FRU VPD collection is not performed for " +
2070 std::string(i_dbusObjPath));
2071 return;
2072 }
2073 }
2074 else if (dbusUtility::isBMCReady())
2075 {
Rekha Aparna40845612025-09-01 19:58:56 -05002076 uint16_t l_errCode = 0;
2077 bool isFruReplaceableAtStandby =
2078 jsonUtility::isFruReplaceableAtStandby(m_parsedJson, l_fruPath,
2079 l_errCode);
2080
2081 if (l_errCode)
2082 {
2083 logging::logMessage(
2084 "Error while checking if FRU is replaceable at standby for FRU [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05302085 std::string(i_dbusObjPath) +
2086 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna40845612025-09-01 19:58:56 -05002087 }
2088
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05002089 bool isFruReplaceableAtRuntime =
2090 jsonUtility::isFruReplaceableAtRuntime(m_parsedJson, l_fruPath,
2091 l_errCode);
2092
2093 if (l_errCode)
2094 {
2095 logging::logMessage(
2096 "Failed to check if FRU is replaceable at runtime for FRU : [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05302097 std::string(i_dbusObjPath) +
2098 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05002099 return;
2100 }
2101
2102 if (!isFruReplaceableAtStandby && (!isFruReplaceableAtRuntime))
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302103 {
2104 logging::logMessage(
2105 "Given FRU is neither replaceable at standby nor replaceable at runtime. Single FRU VPD collection is not performed for " +
2106 std::string(i_dbusObjPath));
2107 return;
2108 }
2109 }
2110
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002111 // Set collection Status as InProgress. Since it's an intermediate state
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302112 // D-bus set-property call is good enough to update the status.
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002113 const std::string& l_collStatusProp = "Status";
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302114
Anupama B R4c65fcd2025-09-01 08:09:00 -05002115 setCollectionStatusProperty(l_fruPath,
2116 constants::vpdCollectionInProgress);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302117
2118 // Parse VPD
2119 types::VPDMapVariant l_parsedVpd = parseVpdFile(l_fruPath);
2120
2121 // If l_parsedVpd is pointing to std::monostate
2122 if (l_parsedVpd.index() == 0)
2123 {
2124 throw std::runtime_error(
2125 "VPD parsing failed for " + std::string(i_dbusObjPath));
2126 }
2127
2128 // Get D-bus object map from worker class
2129 types::ObjectMap l_dbusObjectMap;
2130 populateDbus(l_parsedVpd, l_dbusObjectMap, l_fruPath);
2131
2132 if (l_dbusObjectMap.empty())
2133 {
2134 throw std::runtime_error(
2135 "Failed to create D-bus object map. Single FRU VPD collection failed for " +
2136 std::string(i_dbusObjPath));
2137 }
2138
2139 // Call PIM's Notify method
2140 if (!dbusUtility::callPIM(move(l_dbusObjectMap)))
2141 {
2142 throw std::runtime_error(
2143 "Notify PIM failed. Single FRU VPD collection failed for " +
2144 std::string(i_dbusObjPath));
2145 }
Anupama B R4c65fcd2025-09-01 08:09:00 -05002146 setCollectionStatusProperty(l_fruPath,
2147 constants::vpdCollectionCompleted);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302148 }
2149 catch (const std::exception& l_error)
2150 {
Anupama B R48f297b2025-08-13 04:29:06 -05002151 setCollectionStatusProperty(l_fruPath, constants::vpdCollectionFailed);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05302152 // TODO: Log PEL
2153 logging::logMessage(std::string(l_error.what()));
2154 }
2155}
Anupama B R24691d22025-05-21 08:14:15 -05002156
2157void Worker::setCollectionStatusProperty(
2158 const std::string& i_vpdPath, const std::string& i_value) const noexcept
2159{
2160 try
2161 {
2162 if (i_vpdPath.empty())
2163 {
2164 throw std::runtime_error(
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002165 "Given path is empty. Can't set collection Status property");
Anupama B R24691d22025-05-21 08:14:15 -05002166 }
2167
Anupama B R4c65fcd2025-09-01 08:09:00 -05002168 types::PropertyMap l_timeStampMap;
2169 if (i_value == constants::vpdCollectionCompleted ||
2170 i_value == constants::vpdCollectionFailed)
2171 {
2172 l_timeStampMap.emplace(
2173 "CompletedTime",
2174 types::DbusVariantType{
2175 commonUtility::getCurrentTimeSinceEpoch()});
2176 }
2177 else if (i_value == constants::vpdCollectionInProgress)
2178 {
2179 l_timeStampMap.emplace(
2180 "StartTime", types::DbusVariantType{
2181 commonUtility::getCurrentTimeSinceEpoch()});
2182 }
2183 else if (i_value == constants::vpdCollectionNotStarted)
2184 {
2185 l_timeStampMap.emplace("StartTime", 0);
2186 l_timeStampMap.emplace("CompletedTime", 0);
2187 }
2188
Anupama B R24691d22025-05-21 08:14:15 -05002189 types::ObjectMap l_objectInterfaceMap;
2190
2191 if (m_parsedJson["frus"].contains(i_vpdPath))
2192 {
2193 for (const auto& l_Fru : m_parsedJson["frus"][i_vpdPath])
2194 {
2195 sdbusplus::message::object_path l_fruObjectPath(
2196 l_Fru["inventoryPath"]);
2197
2198 types::PropertyMap l_propertyValueMap;
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002199 l_propertyValueMap.emplace("Status", i_value);
Anupama B R4c65fcd2025-09-01 08:09:00 -05002200 l_propertyValueMap.insert(l_timeStampMap.begin(),
2201 l_timeStampMap.end());
Anupama B R24691d22025-05-21 08:14:15 -05002202
Rekha Aparnad3662222025-10-14 10:33:17 -05002203 uint16_t l_errCode = 0;
Anupama B R24691d22025-05-21 08:14:15 -05002204 types::InterfaceMap l_interfaces;
2205 vpdSpecificUtility::insertOrMerge(
2206 l_interfaces, constants::vpdCollectionInterface,
Rekha Aparnad3662222025-10-14 10:33:17 -05002207 move(l_propertyValueMap), l_errCode);
2208
2209 if (l_errCode)
2210 {
2211 logging::logMessage(
2212 "Failed to insert value into map, error : " +
2213 commonUtility::getErrCodeMsg(l_errCode));
2214 }
Anupama B R24691d22025-05-21 08:14:15 -05002215
2216 l_objectInterfaceMap.emplace(std::move(l_fruObjectPath),
2217 std::move(l_interfaces));
2218 }
2219 }
2220 else
2221 {
2222 // consider it as an inventory path.
2223 if (i_vpdPath.find(constants::pimPath) != constants::VALUE_0)
2224 {
2225 throw std::runtime_error(
2226 "Invalid inventory path: " + i_vpdPath +
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002227 ". Can't set collection Status property");
Anupama B R24691d22025-05-21 08:14:15 -05002228 }
2229
2230 types::PropertyMap l_propertyValueMap;
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002231 l_propertyValueMap.emplace("Status", i_value);
Anupama B R4c65fcd2025-09-01 08:09:00 -05002232 l_propertyValueMap.insert(l_timeStampMap.begin(),
2233 l_timeStampMap.end());
Anupama B R24691d22025-05-21 08:14:15 -05002234
Rekha Aparnad3662222025-10-14 10:33:17 -05002235 uint16_t l_errCode = 0;
Anupama B R24691d22025-05-21 08:14:15 -05002236 types::InterfaceMap l_interfaces;
Rekha Aparnad3662222025-10-14 10:33:17 -05002237 vpdSpecificUtility::insertOrMerge(
2238 l_interfaces, constants::vpdCollectionInterface,
2239 move(l_propertyValueMap), l_errCode);
2240
2241 if (l_errCode)
2242 {
2243 logging::logMessage(
2244 "Failed to insert value into map, error : " +
2245 commonUtility::getErrCodeMsg(l_errCode));
2246 }
Anupama B R24691d22025-05-21 08:14:15 -05002247
2248 l_objectInterfaceMap.emplace(i_vpdPath, std::move(l_interfaces));
2249 }
2250
2251 // Notify PIM
2252 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
2253 {
2254 throw DbusException(
2255 std::string(__FUNCTION__) +
Anupama B R5cd1b2d2025-08-05 04:57:40 -05002256 "Call to PIM failed while setting collection Status property for path " +
Anupama B R24691d22025-05-21 08:14:15 -05002257 i_vpdPath);
2258 }
2259 }
2260 catch (const std::exception& l_ex)
2261 {
2262 EventLogger::createSyncPel(
2263 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
2264 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
2265 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
2266 }
2267}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05002268} // namespace vpd