blob: 7f94cb77996db381b48777008fe4f62409ac42a1 [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"
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05006#include "constants.hpp"
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05007#include "exceptions.hpp"
8#include "logger.hpp"
9#include "parser.hpp"
10#include "parser_factory.hpp"
11#include "parser_interface.hpp"
12
Rekha Aparnac6159a22025-10-09 12:20:20 +053013#include <utility/common_utility.hpp>
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050014#include <utility/dbus_utility.hpp>
Rekha Aparnaa39aafa2025-11-04 00:06:12 -060015#include <utility/event_logger_utility.hpp>
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050016#include <utility/json_utility.hpp>
17#include <utility/vpd_specific_utility.hpp>
18
19#include <filesystem>
20#include <fstream>
21#include <future>
22#include <typeindex>
23#include <unordered_set>
24
25namespace vpd
26{
27
Souvik Roy31548842025-10-22 07:03:12 +000028Worker::Worker(std::string pathToConfigJson, uint8_t i_maxThreadCount,
29 types::VpdCollectionMode i_vpdCollectionMode) :
30 m_configJsonPath(pathToConfigJson), m_semaphore(i_maxThreadCount),
31 m_vpdCollectionMode(i_vpdCollectionMode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050032{
33 // Implies the processing is based on some config JSON
34 if (!m_configJsonPath.empty())
35 {
36 // Check if symlink is already there to confirm fresh boot/factory
37 // reset.
38 if (std::filesystem::exists(INVENTORY_JSON_SYM_LINK))
39 {
40 logging::logMessage("Sym Link already present");
41 m_configJsonPath = INVENTORY_JSON_SYM_LINK;
42 m_isSymlinkPresent = true;
43 }
44
45 try
46 {
Rekha Aparnaca9a0862025-08-29 04:08:33 -050047 uint16_t l_errCode = 0;
48 m_parsedJson =
49 jsonUtility::getParsedJson(m_configJsonPath, l_errCode);
50
51 if (l_errCode)
52 {
53 throw std::runtime_error(
54 "JSON parsing failed for file [ " + m_configJsonPath +
Rekha Aparnac6159a22025-10-09 12:20:20 +053055 " ], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaca9a0862025-08-29 04:08:33 -050056 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050057
58 // check for mandatory fields at this point itself.
59 if (!m_parsedJson.contains("frus"))
60 {
61 throw std::runtime_error("Mandatory tag(s) missing from JSON");
62 }
63 }
64 catch (const std::exception& ex)
65 {
66 throw(JsonException(ex.what(), m_configJsonPath));
67 }
68 }
69 else
70 {
71 logging::logMessage("Processing in not based on any config JSON");
72 }
73}
74
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050075void Worker::setJsonSymbolicLink(const std::string& i_systemJson)
76{
77 std::error_code l_ec;
78 l_ec.clear();
Sunny Srivastavaadff7882025-03-13 11:41:05 +053079
80 // Check if symlink file path exists and if the JSON at this location is a
81 // symlink.
82 if (m_isSymlinkPresent &&
83 std::filesystem::is_symlink(INVENTORY_JSON_SYM_LINK, l_ec))
84 { // Don't care about exception in "is_symlink". Will continue with creation
85 // of symlink.
86
87 const auto& l_symlinkFilePth =
88 std::filesystem::read_symlink(INVENTORY_JSON_SYM_LINK, l_ec);
89
90 if (l_ec)
91 {
92 logging::logMessage(
93 "Can't read existing symlink. Error =" + l_ec.message() +
94 "Trying removal of symlink and creation of new symlink.");
95 }
96
97 // If currently set JSON is the required one. No further processing
98 // required.
99 if (i_systemJson == l_symlinkFilePth)
100 {
101 // Correct symlink already set.
102 return;
103 }
104
105 if (!std::filesystem::remove(INVENTORY_JSON_SYM_LINK, l_ec))
106 {
107 // No point going further. If removal fails for existing symlink,
108 // create will anyways throw.
109 throw std::runtime_error(
110 "Removal of symlink failed with Error = " + l_ec.message() +
111 ". Can't proceed with create_symlink.");
112 }
113 }
114
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500115 if (!std::filesystem::exists(VPD_SYMLIMK_PATH, l_ec))
116 {
117 if (l_ec)
118 {
119 throw std::runtime_error(
120 "File system call to exist failed with error = " +
121 l_ec.message());
122 }
123
124 // implies it is a fresh boot/factory reset.
125 // Create the directory for hosting the symlink
126 if (!std::filesystem::create_directories(VPD_SYMLIMK_PATH, l_ec))
127 {
128 if (l_ec)
129 {
130 throw std::runtime_error(
131 "File system call to create directory failed with error = " +
132 l_ec.message());
133 }
134 }
135 }
136
137 // create a new symlink based on the system
138 std::filesystem::create_symlink(i_systemJson, INVENTORY_JSON_SYM_LINK,
139 l_ec);
140
141 if (l_ec)
142 {
143 throw std::runtime_error(
144 "create_symlink system call failed with error: " + l_ec.message());
145 }
146
Sunny Srivastavac607fe52025-11-18 20:52:23 +0530147 // update Worker json with the newly created symlink
148 uint16_t l_errCode = 0;
149 m_parsedJson =
150 jsonUtility::getParsedJson(INVENTORY_JSON_SYM_LINK, l_errCode);
151 if (l_errCode)
152 {
153 throw std::runtime_error(
154 "JSON parsing failed for file [ " +
155 std::string(INVENTORY_JSON_SYM_LINK) +
156 " ], error : " + commonUtility::getErrCodeMsg(l_errCode));
157 }
158
159 logging::logMessage("Worker JSON modified to: " + i_systemJson);
160
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500161 // If the flow is at this point implies the symlink was not present there.
162 // Considering this as factory reset.
163 m_isFactoryResetDone = true;
164}
165
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500166void Worker::populateIPZVPDpropertyMap(
167 types::InterfaceMap& interfacePropMap,
168 const types::IPZKwdValueMap& keyordValueMap,
169 const std::string& interfaceName)
170{
171 types::PropertyMap propertyValueMap;
172 for (const auto& kwdVal : keyordValueMap)
173 {
174 auto kwd = kwdVal.first;
175
176 if (kwd[0] == '#')
177 {
178 kwd = std::string("PD_") + kwd[1];
179 }
180 else if (isdigit(kwd[0]))
181 {
182 kwd = std::string("N_") + kwd;
183 }
184
185 types::BinaryVector value(kwdVal.second.begin(), kwdVal.second.end());
186 propertyValueMap.emplace(move(kwd), move(value));
187 }
188
189 if (!propertyValueMap.empty())
190 {
191 interfacePropMap.emplace(interfaceName, propertyValueMap);
192 }
193}
194
195void Worker::populateKwdVPDpropertyMap(const types::KeywordVpdMap& keyordVPDMap,
196 types::InterfaceMap& interfaceMap)
197{
198 for (const auto& kwdValMap : keyordVPDMap)
199 {
200 types::PropertyMap propertyValueMap;
201 auto kwd = kwdValMap.first;
202
203 if (kwd[0] == '#')
204 {
205 kwd = std::string("PD_") + kwd[1];
206 }
207 else if (isdigit(kwd[0]))
208 {
209 kwd = std::string("N_") + kwd;
210 }
211
212 if (auto keywordValue = get_if<types::BinaryVector>(&kwdValMap.second))
213 {
214 types::BinaryVector value((*keywordValue).begin(),
215 (*keywordValue).end());
216 propertyValueMap.emplace(move(kwd), move(value));
217 }
218 else if (auto keywordValue = get_if<std::string>(&kwdValMap.second))
219 {
220 types::BinaryVector value((*keywordValue).begin(),
221 (*keywordValue).end());
222 propertyValueMap.emplace(move(kwd), move(value));
223 }
224 else if (auto keywordValue = get_if<size_t>(&kwdValMap.second))
225 {
226 if (kwd == "MemorySizeInKB")
227 {
228 types::PropertyMap memProp;
229 memProp.emplace(move(kwd), ((*keywordValue)));
230 interfaceMap.emplace("xyz.openbmc_project.Inventory.Item.Dimm",
231 move(memProp));
232 continue;
233 }
234 else
235 {
236 logging::logMessage(
237 "Unknown Keyword =" + kwd + " found in keyword VPD map");
238 continue;
239 }
240 }
241 else
242 {
243 logging::logMessage(
244 "Unknown variant type found in keyword VPD map.");
245 continue;
246 }
247
248 if (!propertyValueMap.empty())
249 {
Rekha Aparnad3662222025-10-14 10:33:17 -0500250 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500251 vpdSpecificUtility::insertOrMerge(
Rekha Aparnad3662222025-10-14 10:33:17 -0500252 interfaceMap, constants::kwdVpdInf, move(propertyValueMap),
253 l_errCode);
254
255 if (l_errCode)
256 {
257 logging::logMessage(
258 "Failed to insert value into map, error : " +
259 commonUtility::getErrCodeMsg(l_errCode));
260 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500261 }
262 }
263}
264
265void Worker::populateInterfaces(const nlohmann::json& interfaceJson,
266 types::InterfaceMap& interfaceMap,
267 const types::VPDMapVariant& parsedVpdMap)
268{
269 for (const auto& interfacesPropPair : interfaceJson.items())
270 {
271 const std::string& interface = interfacesPropPair.key();
272 types::PropertyMap propertyMap;
Rekha Aparna6256db92025-10-17 09:58:49 -0500273 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500274
275 for (const auto& propValuePair : interfacesPropPair.value().items())
276 {
277 const std::string property = propValuePair.key();
278
279 if (propValuePair.value().is_boolean())
280 {
281 propertyMap.emplace(property,
282 propValuePair.value().get<bool>());
283 }
284 else if (propValuePair.value().is_string())
285 {
286 if (property.compare("LocationCode") == 0 &&
287 interface.compare("com.ibm.ipzvpd.Location") == 0)
288 {
289 std::string value =
290 vpdSpecificUtility::getExpandedLocationCode(
291 propValuePair.value().get<std::string>(),
Rekha Aparna6256db92025-10-17 09:58:49 -0500292 parsedVpdMap, l_errCode);
293
294 if (l_errCode)
295 {
296 logging::logMessage(
297 "Failed to get expanded location code for location code - " +
298 propValuePair.value().get<std::string>() +
299 " ,error : " +
300 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna6256db92025-10-17 09:58:49 -0500301 }
302
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500303 propertyMap.emplace(property, value);
304
305 auto l_locCodeProperty = propertyMap;
306 vpdSpecificUtility::insertOrMerge(
307 interfaceMap,
308 std::string(constants::xyzLocationCodeInf),
Rekha Aparnad3662222025-10-14 10:33:17 -0500309 move(l_locCodeProperty), l_errCode);
310
311 if (l_errCode)
312 {
313 logging::logMessage(
314 "Failed to insert value into map, error : " +
315 commonUtility::getErrCodeMsg(l_errCode));
316 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500317 }
318 else
319 {
320 propertyMap.emplace(
321 property, propValuePair.value().get<std::string>());
322 }
323 }
324 else if (propValuePair.value().is_array())
325 {
326 try
327 {
328 propertyMap.emplace(
329 property,
330 propValuePair.value().get<types::BinaryVector>());
331 }
332 catch (const nlohmann::detail::type_error& e)
333 {
334 std::cerr << "Type exception: " << e.what() << "\n";
335 }
336 }
337 else if (propValuePair.value().is_number())
338 {
339 // For now assume the value is a size_t. In the future it would
340 // be nice to come up with a way to get the type from the JSON.
341 propertyMap.emplace(property,
342 propValuePair.value().get<size_t>());
343 }
344 else if (propValuePair.value().is_object())
345 {
346 const std::string& record =
347 propValuePair.value().value("recordName", "");
348 const std::string& keyword =
349 propValuePair.value().value("keywordName", "");
350 const std::string& encoding =
351 propValuePair.value().value("encoding", "");
352
353 if (auto ipzVpdMap =
354 std::get_if<types::IPZVpdMap>(&parsedVpdMap))
355 {
356 if (!record.empty() && !keyword.empty() &&
357 (*ipzVpdMap).count(record) &&
358 (*ipzVpdMap).at(record).count(keyword))
359 {
360 auto encoded = vpdSpecificUtility::encodeKeyword(
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500361 ((*ipzVpdMap).at(record).at(keyword)), encoding,
362 l_errCode);
363
364 if (l_errCode)
365 {
366 logging::logMessage(
367 std::string(
368 "Failed to get encoded keyword value for : ") +
369 keyword + std::string(", error : ") +
370 commonUtility::getErrCodeMsg(l_errCode));
371 }
372
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500373 propertyMap.emplace(property, encoded);
374 }
375 }
376 else if (auto kwdVpdMap =
377 std::get_if<types::KeywordVpdMap>(&parsedVpdMap))
378 {
379 if (!keyword.empty() && (*kwdVpdMap).count(keyword))
380 {
381 if (auto kwValue = std::get_if<types::BinaryVector>(
382 &(*kwdVpdMap).at(keyword)))
383 {
384 auto encodedValue =
385 vpdSpecificUtility::encodeKeyword(
386 std::string((*kwValue).begin(),
387 (*kwValue).end()),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500388 encoding, l_errCode);
389
390 if (l_errCode)
391 {
392 logging::logMessage(
393 std::string(
394 "Failed to get encoded keyword value for : ") +
395 keyword + std::string(", error : ") +
396 commonUtility::getErrCodeMsg(l_errCode));
397 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500398
399 propertyMap.emplace(property, encodedValue);
400 }
401 else if (auto kwValue = std::get_if<std::string>(
402 &(*kwdVpdMap).at(keyword)))
403 {
404 auto encodedValue =
405 vpdSpecificUtility::encodeKeyword(
406 std::string((*kwValue).begin(),
407 (*kwValue).end()),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500408 encoding, l_errCode);
409
410 if (l_errCode)
411 {
412 logging::logMessage(
413 "Failed to get encoded keyword value for : " +
414 keyword + ", error : " +
415 commonUtility::getErrCodeMsg(l_errCode));
416 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500417
418 propertyMap.emplace(property, encodedValue);
419 }
420 else if (auto uintValue = std::get_if<size_t>(
421 &(*kwdVpdMap).at(keyword)))
422 {
423 propertyMap.emplace(property, *uintValue);
424 }
425 else
426 {
427 logging::logMessage(
428 "Unknown keyword found, Keywrod = " + keyword);
429 }
430 }
431 }
432 }
433 }
434 vpdSpecificUtility::insertOrMerge(interfaceMap, interface,
Rekha Aparnad3662222025-10-14 10:33:17 -0500435 move(propertyMap), l_errCode);
436
437 if (l_errCode)
438 {
439 logging::logMessage("Failed to insert value into map, error : " +
440 commonUtility::getErrCodeMsg(l_errCode));
441 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500442 }
443}
444
445bool Worker::isCPUIOGoodOnly(const std::string& i_pgKeyword)
446{
447 const unsigned char l_io[] = {
448 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF,
449 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF, 0xE7, 0xF9, 0xFF};
450
451 // EQ0 index (in PG keyword) starts at 97 (with offset starting from 0).
452 // Each EQ carries 3 bytes of data. Totally there are 8 EQs. If all EQs'
453 // value equals 0xE7F9FF, then the cpu has no good cores and its treated as
454 // IO.
455 if (memcmp(l_io, i_pgKeyword.data() + constants::INDEX_OF_EQ0_IN_PG,
456 constants::SIZE_OF_8EQ_IN_PG) == 0)
457 {
458 return true;
459 }
460
461 // The CPU is not an IO
462 return false;
463}
464
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500465void Worker::processEmbeddedAndSynthesizedFrus(const nlohmann::json& singleFru,
466 types::InterfaceMap& interfaces)
467{
468 // embedded property(true or false) says whether the subfru is embedded
469 // into the parent fru (or) not. VPD sets Present property only for
470 // embedded frus. If the subfru is not an embedded FRU, the subfru may
471 // or may not be physically present. Those non embedded frus will always
472 // have Present=false irrespective of its physical presence or absence.
473 // Eg: nvme drive in nvme slot is not an embedded FRU. So don't set
474 // Present to true for such sub frus.
475 // Eg: ethernet port is embedded into bmc card. So set Present to true
476 // for such sub frus. Also donot populate present property for embedded
477 // subfru which is synthesized. Currently there is no subfru which are
478 // both embedded and synthesized. But still the case is handled here.
479
480 // Check if its required to handle presence for this FRU.
481 if (singleFru.value("handlePresence", true))
482 {
Rekha Aparnad3662222025-10-14 10:33:17 -0500483 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500484 types::PropertyMap presProp;
485 presProp.emplace("Present", true);
Rekha Aparnad3662222025-10-14 10:33:17 -0500486 vpdSpecificUtility::insertOrMerge(interfaces,
487 "xyz.openbmc_project.Inventory.Item",
488 move(presProp), l_errCode);
489
490 if (l_errCode)
491 {
492 logging::logMessage("Failed to insert value into map, error : " +
493 commonUtility::getErrCodeMsg(l_errCode));
494 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500495 }
496}
497
498void Worker::processExtraInterfaces(const nlohmann::json& singleFru,
499 types::InterfaceMap& interfaces,
500 const types::VPDMapVariant& parsedVpdMap)
501{
502 populateInterfaces(singleFru["extraInterfaces"], interfaces, parsedVpdMap);
503 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
504 {
505 if (singleFru["extraInterfaces"].contains(
506 "xyz.openbmc_project.Inventory.Item.Cpu"))
507 {
508 auto itrToRec = (*ipzVpdMap).find("CP00");
509 if (itrToRec == (*ipzVpdMap).end())
510 {
511 return;
512 }
513
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500514 uint16_t l_errCode = 0;
515 const std::string pgKeywordValue{vpdSpecificUtility::getKwVal(
516 itrToRec->second, "PG", l_errCode)};
Souvik Roya55fcca2025-02-19 01:33:58 -0600517
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500518 if (!pgKeywordValue.empty())
519 {
520 if (isCPUIOGoodOnly(pgKeywordValue))
521 {
522 interfaces["xyz.openbmc_project.Inventory.Item"]
523 ["PrettyName"] = "IO Module";
524 }
525 }
Souvik Roya55fcca2025-02-19 01:33:58 -0600526 else
527 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500528 throw DataException(
529 std::string(__FUNCTION__) +
530 "Failed to get value for keyword PG, error : " +
531 commonUtility::getErrCodeMsg(l_errCode));
Souvik Roya55fcca2025-02-19 01:33:58 -0600532 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500533 }
534 }
535}
536
537void Worker::processCopyRecordFlag(const nlohmann::json& singleFru,
538 const types::VPDMapVariant& parsedVpdMap,
539 types::InterfaceMap& interfaces)
540{
541 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
542 {
543 for (const auto& record : singleFru["copyRecords"])
544 {
545 const std::string& recordName = record;
546 if ((*ipzVpdMap).find(recordName) != (*ipzVpdMap).end())
547 {
548 populateIPZVPDpropertyMap(interfaces,
549 (*ipzVpdMap).at(recordName),
550 constants::ipzVpdInf + recordName);
551 }
552 }
553 }
554}
555
556void Worker::processInheritFlag(const types::VPDMapVariant& parsedVpdMap,
557 types::InterfaceMap& interfaces)
558{
559 if (auto ipzVpdMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
560 {
561 for (const auto& [recordName, kwdValueMap] : *ipzVpdMap)
562 {
563 populateIPZVPDpropertyMap(interfaces, kwdValueMap,
564 constants::ipzVpdInf + recordName);
565 }
566 }
567 else if (auto kwdVpdMap = std::get_if<types::KeywordVpdMap>(&parsedVpdMap))
568 {
569 populateKwdVPDpropertyMap(*kwdVpdMap, interfaces);
570 }
571
572 if (m_parsedJson.contains("commonInterfaces"))
573 {
574 populateInterfaces(m_parsedJson["commonInterfaces"], interfaces,
575 parsedVpdMap);
576 }
577}
578
579bool Worker::processFruWithCCIN(const nlohmann::json& singleFru,
580 const types::VPDMapVariant& parsedVpdMap)
581{
582 if (auto ipzVPDMap = std::get_if<types::IPZVpdMap>(&parsedVpdMap))
583 {
584 auto itrToRec = (*ipzVPDMap).find("VINI");
585 if (itrToRec == (*ipzVPDMap).end())
586 {
587 return false;
588 }
589
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500590 uint16_t l_errCode = 0;
Souvik Roya55fcca2025-02-19 01:33:58 -0600591 std::string ccinFromVpd{
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500592 vpdSpecificUtility::getKwVal(itrToRec->second, "CC", l_errCode)};
Souvik Roya55fcca2025-02-19 01:33:58 -0600593
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500594 if (ccinFromVpd.empty())
595 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500596 logging::logMessage("Failed to get CCIN kwd value, error : " +
597 commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500598 return false;
599 }
600
601 transform(ccinFromVpd.begin(), ccinFromVpd.end(), ccinFromVpd.begin(),
602 ::toupper);
603
604 std::vector<std::string> ccinList;
605 for (std::string ccin : singleFru["ccin"])
606 {
607 transform(ccin.begin(), ccin.end(), ccin.begin(), ::toupper);
608 ccinList.push_back(ccin);
609 }
610
611 if (ccinList.empty())
612 {
613 return false;
614 }
615
616 if (find(ccinList.begin(), ccinList.end(), ccinFromVpd) ==
617 ccinList.end())
618 {
619 return false;
620 }
621 }
622 return true;
623}
624
625void Worker::processFunctionalProperty(const std::string& i_inventoryObjPath,
626 types::InterfaceMap& io_interfaces)
627{
628 if (!dbusUtility::isChassisPowerOn())
629 {
Anupama B R68a70432025-09-25 02:09:37 -0500630 std::vector<std::string> l_operationalStatusInf = {
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500631 constants::operationalStatusInf};
632
633 auto mapperObjectMap = dbusUtility::getObjectMap(
634 i_inventoryObjPath, l_operationalStatusInf);
635
636 // If the object has been found. Check if it is under PIM.
637 if (mapperObjectMap.size() != 0)
638 {
639 for (const auto& [l_serviceName, l_interfaceLsit] : mapperObjectMap)
640 {
641 if (l_serviceName == constants::pimServiceName)
642 {
643 // The object is already under PIM. No need to process
644 // again. Retain the old value.
645 return;
646 }
647 }
648 }
649
650 // Implies value is not there in D-Bus. Populate it with default
651 // value "true".
Rekha Aparnad3662222025-10-14 10:33:17 -0500652 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500653 types::PropertyMap l_functionalProp;
654 l_functionalProp.emplace("Functional", true);
655 vpdSpecificUtility::insertOrMerge(io_interfaces,
656 constants::operationalStatusInf,
Rekha Aparnad3662222025-10-14 10:33:17 -0500657 move(l_functionalProp), l_errCode);
658
659 if (l_errCode)
660 {
661 logging::logMessage(
662 "Failed to insert interface into map, error : " +
663 commonUtility::getErrCodeMsg(l_errCode));
664 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500665 }
666
667 // if chassis is power on. Functional property should be there on D-Bus.
668 // Don't process.
669 return;
670}
671
672void Worker::processEnabledProperty(const std::string& i_inventoryObjPath,
673 types::InterfaceMap& io_interfaces)
674{
675 if (!dbusUtility::isChassisPowerOn())
676 {
Anupama B R68a70432025-09-25 02:09:37 -0500677 std::vector<std::string> l_enableInf = {constants::enableInf};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500678
679 auto mapperObjectMap =
680 dbusUtility::getObjectMap(i_inventoryObjPath, l_enableInf);
681
682 // If the object has been found. Check if it is under PIM.
683 if (mapperObjectMap.size() != 0)
684 {
685 for (const auto& [l_serviceName, l_interfaceLsit] : mapperObjectMap)
686 {
687 if (l_serviceName == constants::pimServiceName)
688 {
689 // The object is already under PIM. No need to process
690 // again. Retain the old value.
691 return;
692 }
693 }
694 }
695
696 // Implies value is not there in D-Bus. Populate it with default
697 // value "true".
Rekha Aparnad3662222025-10-14 10:33:17 -0500698 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500699 types::PropertyMap l_enabledProp;
700 l_enabledProp.emplace("Enabled", true);
701 vpdSpecificUtility::insertOrMerge(io_interfaces, constants::enableInf,
Rekha Aparnad3662222025-10-14 10:33:17 -0500702 move(l_enabledProp), l_errCode);
703
704 if (l_errCode)
705 {
706 logging::logMessage(
707 "Failed to insert interface into map, error : " +
708 commonUtility::getErrCodeMsg(l_errCode));
709 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500710 }
711
712 // if chassis is power on. Enabled property should be there on D-Bus.
713 // Don't process.
714 return;
715}
716
717void Worker::populateDbus(const types::VPDMapVariant& parsedVpdMap,
718 types::ObjectMap& objectInterfaceMap,
719 const std::string& vpdFilePath)
720{
721 if (vpdFilePath.empty())
722 {
723 throw std::runtime_error(
Sunny Srivastava4c509c22025-03-25 12:43:40 +0530724 std::string(__FUNCTION__) +
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500725 "Invalid parameter passed to populateDbus API.");
726 }
727
728 // JSON config is mandatory for processing of "if". Add "else" for any
729 // processing without config JSON.
730 if (!m_parsedJson.empty())
731 {
732 types::InterfaceMap interfaces;
733
734 for (const auto& aFru : m_parsedJson["frus"][vpdFilePath])
735 {
736 const auto& inventoryPath = aFru["inventoryPath"];
737 sdbusplus::message::object_path fruObjectPath(inventoryPath);
738 if (aFru.contains("ccin"))
739 {
740 if (!processFruWithCCIN(aFru, parsedVpdMap))
741 {
742 continue;
743 }
744 }
745
746 if (aFru.value("inherit", true))
747 {
748 processInheritFlag(parsedVpdMap, interfaces);
749 }
750
751 // If specific record needs to be copied.
752 if (aFru.contains("copyRecords"))
753 {
754 processCopyRecordFlag(aFru, parsedVpdMap, interfaces);
755 }
756
757 if (aFru.contains("extraInterfaces"))
758 {
759 // Process extra interfaces w.r.t a FRU.
760 processExtraInterfaces(aFru, interfaces, parsedVpdMap);
761 }
762
763 // Process FRUS which are embedded in the parent FRU and whose VPD
764 // will be synthesized.
765 if ((aFru.value("embedded", true)) &&
766 (!aFru.value("synthesized", false)))
767 {
768 processEmbeddedAndSynthesizedFrus(aFru, interfaces);
769 }
770
771 processFunctionalProperty(inventoryPath, interfaces);
772 processEnabledProperty(inventoryPath, interfaces);
773
774 objectInterfaceMap.emplace(std::move(fruObjectPath),
775 std::move(interfaces));
776 }
777 }
778}
779
Patrick Williams43fedab2025-02-03 14:28:05 -0500780std::string Worker::createAssetTagString(
781 const types::VPDMapVariant& i_parsedVpdMap)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500782{
783 std::string l_assetTag;
784
785 // system VPD will be in IPZ format.
786 if (auto l_parsedVpdMap = std::get_if<types::IPZVpdMap>(&i_parsedVpdMap))
787 {
788 auto l_itrToVsys = (*l_parsedVpdMap).find(constants::recVSYS);
789 if (l_itrToVsys != (*l_parsedVpdMap).end())
790 {
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500791 uint16_t l_errCode = 0;
Souvik Roya55fcca2025-02-19 01:33:58 -0600792 const std::string l_tmKwdValue{vpdSpecificUtility::getKwVal(
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500793 l_itrToVsys->second, constants::kwdTM, l_errCode)};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500794
Souvik Roya55fcca2025-02-19 01:33:58 -0600795 if (l_tmKwdValue.empty())
796 {
797 throw std::runtime_error(
798 std::string("Failed to get value for keyword [") +
799 constants::kwdTM +
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500800 std::string("] while creating Asset tag. Error : " +
801 commonUtility::getErrCodeMsg(l_errCode)));
Souvik Roya55fcca2025-02-19 01:33:58 -0600802 }
803
804 const std::string l_seKwdValue{vpdSpecificUtility::getKwVal(
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500805 l_itrToVsys->second, constants::kwdSE, l_errCode)};
Souvik Roya55fcca2025-02-19 01:33:58 -0600806
807 if (l_seKwdValue.empty())
808 {
809 throw std::runtime_error(
810 std::string("Failed to get value for keyword [") +
811 constants::kwdSE +
Rekha Aparna7d9a7062025-10-07 04:14:42 -0500812 std::string("] while creating Asset tag. Error : " +
813 commonUtility::getErrCodeMsg(l_errCode)));
Souvik Roya55fcca2025-02-19 01:33:58 -0600814 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500815
816 l_assetTag = std::string{"Server-"} + l_tmKwdValue +
817 std::string{"-"} + l_seKwdValue;
818 }
819 else
820 {
821 throw std::runtime_error(
822 "VSYS record not found in parsed VPD map to create Asset tag.");
823 }
824 }
825 else
826 {
827 throw std::runtime_error(
828 "Invalid VPD type recieved to create Asset tag.");
829 }
830
831 return l_assetTag;
832}
833
834void Worker::publishSystemVPD(const types::VPDMapVariant& parsedVpdMap)
835{
836 types::ObjectMap objectInterfaceMap;
837
838 if (std::get_if<types::IPZVpdMap>(&parsedVpdMap))
839 {
840 populateDbus(parsedVpdMap, objectInterfaceMap, SYSTEM_VPD_FILE_PATH);
841
842 try
843 {
844 if (m_isFactoryResetDone)
845 {
846 const auto& l_assetTag = createAssetTagString(parsedVpdMap);
847
848 auto l_itrToSystemPath = objectInterfaceMap.find(
849 sdbusplus::message::object_path(constants::systemInvPath));
850 if (l_itrToSystemPath == objectInterfaceMap.end())
851 {
852 throw std::runtime_error(
Sunny Srivastava043955d2025-01-21 18:04:49 +0530853 "Asset tag update failed. System Path not found in object map.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500854 }
855
856 types::PropertyMap l_assetTagProperty;
857 l_assetTagProperty.emplace("AssetTag", l_assetTag);
858
859 (l_itrToSystemPath->second)
860 .emplace(constants::assetTagInf,
861 std::move(l_assetTagProperty));
862 }
863 }
864 catch (const std::exception& l_ex)
865 {
866 EventLogger::createSyncPel(
Sunny Srivastava043955d2025-01-21 18:04:49 +0530867 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
868 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500869 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
870 }
871
872 // Notify PIM
873 if (!dbusUtility::callPIM(move(objectInterfaceMap)))
874 {
875 throw std::runtime_error("Call to PIM failed for system VPD");
876 }
877 }
878 else
879 {
880 throw DataException("Invalid format of parsed VPD map.");
881 }
882}
883
884bool Worker::processPreAction(const std::string& i_vpdFilePath,
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500885 const std::string& i_flagToProcess,
886 uint16_t& i_errCode)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500887{
Sunny Srivastavab5fab802025-11-05 21:42:26 +0530888 i_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500889 if (i_vpdFilePath.empty() || i_flagToProcess.empty())
890 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500891 i_errCode = error_code::INVALID_INPUT_PARAMETER;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500892 return false;
893 }
894
895 if ((!jsonUtility::executeBaseAction(m_parsedJson, "preAction",
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500896 i_vpdFilePath, i_flagToProcess,
897 i_errCode)) &&
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500898 (i_flagToProcess.compare("collection") == constants::STR_CMP_SUCCESS))
899 {
900 // TODO: Need a way to delete inventory object from Dbus and persisted
901 // data section in case any FRU is not present or there is any
902 // problem in collecting it. Once it has been deleted, it can be
903 // re-created in the flow of priming the inventory. This needs to be
904 // done either here or in the exception section of "parseAndPublishVPD"
905 // API. Any failure in the process of collecting FRU will land up in the
906 // excpetion of "parseAndPublishVPD".
907
908 // If the FRU is not there, clear the VINI/CCIN data.
909 // Enity manager probes for this keyword to look for this
910 // FRU, now if the data is persistent on BMC and FRU is
911 // removed this can lead to ambiguity. Hence clearing this
912 // Keyword if FRU is absent.
913 const auto& inventoryPath =
914 m_parsedJson["frus"][i_vpdFilePath].at(0).value("inventoryPath",
915 "");
916
917 if (!inventoryPath.empty())
918 {
919 types::ObjectMap l_pimObjMap{
920 {inventoryPath,
921 {{constants::kwdVpdInf,
922 {{constants::kwdCCIN, types::BinaryVector{}}}}}}};
923
924 if (!dbusUtility::callPIM(std::move(l_pimObjMap)))
925 {
926 logging::logMessage(
927 "Call to PIM failed for file " + i_vpdFilePath);
928 }
929 }
930 else
931 {
932 logging::logMessage(
933 "Inventory path is empty in Json for file " + i_vpdFilePath);
934 }
935
936 return false;
937 }
938 return true;
939}
940
941bool Worker::processPostAction(
942 const std::string& i_vpdFruPath, const std::string& i_flagToProcess,
943 const std::optional<types::VPDMapVariant> i_parsedVpd)
944{
945 if (i_vpdFruPath.empty() || i_flagToProcess.empty())
946 {
947 logging::logMessage(
948 "Invalid input parameter. Abort processing post action");
949 return false;
950 }
951
952 // Check if post action tag is to be triggered in the flow of collection
953 // based on some CCIN value?
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500954 uint16_t l_errCode = 0;
955
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500956 if (m_parsedJson["frus"][i_vpdFruPath]
957 .at(0)["postAction"][i_flagToProcess]
958 .contains("ccin"))
959 {
960 if (!i_parsedVpd.has_value())
961 {
962 logging::logMessage("Empty VPD Map");
963 return false;
964 }
965
966 // CCIN match is required to process post action for this FRU as it
967 // contains the flag.
968 if (!vpdSpecificUtility::findCcinInVpd(
969 m_parsedJson["frus"][i_vpdFruPath].at(
970 0)["postAction"]["collection"],
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500971 i_parsedVpd.value(), l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500972 {
Rekha Aparna1d8ec012025-10-22 12:37:01 -0500973 if (l_errCode)
974 {
975 // ToDo - Check if PEL is required in case of RECORD_NOT_FOUND
976 // and KEYWORD_NOT_FOUND error codes.
977 logging::logMessage("Failed to find CCIN in VPD, error : " +
978 commonUtility::getErrCodeMsg(l_errCode));
979 }
980
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500981 // If CCIN is not found, implies post action processing is not
982 // required for this FRU. Let the flow continue.
983 return true;
984 }
985 }
986
987 if (!jsonUtility::executeBaseAction(m_parsedJson, "postAction",
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500988 i_vpdFruPath, i_flagToProcess,
989 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500990 {
991 logging::logMessage(
Sunny Srivastava4f053df2025-09-03 02:27:37 -0500992 "Execution of post action failed for path: " + i_vpdFruPath +
Rekha Aparnac6159a22025-10-09 12:20:20 +0530993 " . Reason: " + commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500994
995 // If post action was required and failed only in that case return
996 // false. In all other case post action is considered passed.
997 return false;
998 }
999
1000 return true;
1001}
1002
1003types::VPDMapVariant Worker::parseVpdFile(const std::string& i_vpdFilePath)
1004{
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001005 try
1006 {
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001007 uint16_t l_errCode = 0;
1008
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301009 if (i_vpdFilePath.empty())
1010 {
1011 throw std::runtime_error(
1012 std::string(__FUNCTION__) +
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301013 " Empty VPD file path passed. Abort processing");
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301014 }
1015
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301016 bool isPreActionRequired = false;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001017 if (jsonUtility::isActionRequired(m_parsedJson, i_vpdFilePath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001018 "preAction", "collection", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001019 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301020 isPreActionRequired = true;
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001021 if (!processPreAction(i_vpdFilePath, "collection", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001022 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001023 if (l_errCode == error_code::DEVICE_NOT_PRESENT)
1024 {
1025 logging::logMessage(
Rekha Aparnac6159a22025-10-09 12:20:20 +05301026 commonUtility::getErrCodeMsg(l_errCode) +
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001027 i_vpdFilePath);
1028 // Presence pin has been read successfully and has been read
1029 // as false, so this is not a failure case, hence returning
1030 // empty variant so that pre action is not marked as failed.
1031 return types::VPDMapVariant{};
1032 }
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301033 throw std::runtime_error(
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001034 std::string(__FUNCTION__) +
1035 " Pre-Action failed with error: " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301036 commonUtility::getErrCodeMsg(l_errCode));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001037 }
1038 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001039 else if (l_errCode)
1040 {
1041 logging::logMessage(
1042 "Failed to check if pre action required for FRU [" +
1043 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301044 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001045 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001046
1047 if (!std::filesystem::exists(i_vpdFilePath))
1048 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301049 if (isPreActionRequired)
1050 {
1051 throw std::runtime_error(
1052 std::string(__FUNCTION__) + " Could not find file path " +
1053 i_vpdFilePath + "Skipping parser trigger for the EEPROM");
1054 }
1055 return types::VPDMapVariant{};
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001056 }
1057
1058 std::shared_ptr<Parser> vpdParser =
1059 std::make_shared<Parser>(i_vpdFilePath, m_parsedJson);
1060
1061 types::VPDMapVariant l_parsedVpd = vpdParser->parse();
1062
1063 // Before returning, as collection is over, check if FRU qualifies for
1064 // any post action in the flow of collection.
1065 // Note: Don't change the order, post action needs to be processed only
1066 // after collection for FRU is successfully done.
1067 if (jsonUtility::isActionRequired(m_parsedJson, i_vpdFilePath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001068 "postAction", "collection",
1069 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001070 {
1071 if (!processPostAction(i_vpdFilePath, "collection", l_parsedVpd))
1072 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301073 // Post action was required but failed while executing.
1074 // Behaviour can be undefined.
1075 EventLogger::createSyncPel(
1076 types::ErrorType::InternalFailure,
1077 types::SeverityType::Warning, __FILE__, __FUNCTION__, 0,
1078 std::string("Required post action failed for path [" +
1079 i_vpdFilePath + "]"),
1080 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001081 }
1082 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001083 else if (l_errCode)
1084 {
1085 logging::logMessage(
1086 "Error while checking if post action required for FRU [" +
1087 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301088 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001089 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001090
1091 return l_parsedVpd;
1092 }
1093 catch (std::exception& l_ex)
1094 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001095 uint16_t l_errCode = 0;
Souvik Roy37c6bef2025-07-17 00:55:59 -05001096 std::string l_exMsg{
1097 std::string(__FUNCTION__) + " : VPD parsing failed for " +
1098 i_vpdFilePath + " due to error: " + l_ex.what()};
1099
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001100 // If post fail action is required, execute it.
1101 if (jsonUtility::isActionRequired(m_parsedJson, i_vpdFilePath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001102 "postFailAction", "collection",
1103 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001104 {
1105 if (!jsonUtility::executePostFailAction(m_parsedJson, i_vpdFilePath,
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001106 "collection", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001107 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001108 l_exMsg += ". Post fail action also failed. Error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301109 commonUtility::getErrCodeMsg(l_errCode) +
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001110 " Aborting collection for this FRU.";
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001111 }
1112 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001113 else if (l_errCode)
1114 {
1115 l_exMsg +=
1116 ". Failed to check if post fail action required, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301117 commonUtility::getErrCodeMsg(l_errCode);
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001118 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001119
Souvik Roy37c6bef2025-07-17 00:55:59 -05001120 if (typeid(l_ex) == typeid(DataException))
1121 {
1122 throw DataException(l_exMsg);
1123 }
1124 else if (typeid(l_ex) == typeid(EccException))
1125 {
1126 throw EccException(l_exMsg);
1127 }
1128 throw std::runtime_error(l_exMsg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001129 }
1130}
1131
Patrick Williams43fedab2025-02-03 14:28:05 -05001132std::tuple<bool, std::string> Worker::parseAndPublishVPD(
1133 const std::string& i_vpdFilePath)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001134{
Priyanga Ramasamy1aad7832024-12-12 22:13:52 -06001135 std::string l_inventoryPath{};
1136
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001137 try
1138 {
1139 m_semaphore.acquire();
1140
1141 // Thread launched.
1142 m_mutex.lock();
1143 m_activeCollectionThreadCount++;
1144 m_mutex.unlock();
1145
Anupama B R4c65fcd2025-09-01 08:09:00 -05001146 setCollectionStatusProperty(i_vpdFilePath,
1147 constants::vpdCollectionInProgress);
Priyanga Ramasamy1aad7832024-12-12 22:13:52 -06001148
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001149 const types::VPDMapVariant& parsedVpdMap = parseVpdFile(i_vpdFilePath);
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301150 if (!std::holds_alternative<std::monostate>(parsedVpdMap))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001151 {
Sunny Srivastava0a5fce12025-04-09 11:09:51 +05301152 types::ObjectMap objectInterfaceMap;
1153 populateDbus(parsedVpdMap, objectInterfaceMap, i_vpdFilePath);
1154
1155 // Notify PIM
1156 if (!dbusUtility::callPIM(move(objectInterfaceMap)))
1157 {
1158 throw std::runtime_error(
1159 std::string(__FUNCTION__) +
1160 "Call to PIM failed while publishing VPD.");
1161 }
1162 }
1163 else
1164 {
1165 logging::logMessage("Empty parsedVpdMap recieved for path [" +
1166 i_vpdFilePath + "]. Check PEL for reason.");
Anupama B R4c65fcd2025-09-01 08:09:00 -05001167
1168 // As empty parsedVpdMap recieved for some reason, but still
1169 // considered VPD collection is completed. Hence FRU collection
1170 // Status will be set as completed.
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001171 }
1172 }
1173 catch (const std::exception& ex)
1174 {
Anupama B R24691d22025-05-21 08:14:15 -05001175 setCollectionStatusProperty(i_vpdFilePath,
Anupama B R5cd1b2d2025-08-05 04:57:40 -05001176 constants::vpdCollectionFailed);
Priyanga Ramasamy1aad7832024-12-12 22:13:52 -06001177
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001178 // handle all the exceptions internally. Return only true/false
1179 // based on status of execution.
1180 if (typeid(ex) == std::type_index(typeid(DataException)))
1181 {
Rekha Aparna017567a2025-08-13 02:07:06 -05001182 uint16_t l_errCode = 0;
Sunny Srivastava78c91072025-02-05 14:09:50 +05301183 // In case of pass1 planar, VPD can be corrupted on PCIe cards. Skip
1184 // logging error for these cases.
Rekha Aparna715eaff2025-10-23 02:06:50 -05001185 if (vpdSpecificUtility::isPass1Planar(l_errCode))
Sunny Srivastava78c91072025-02-05 14:09:50 +05301186 {
Rekha Aparna017567a2025-08-13 02:07:06 -05001187 std::string l_invPath =
1188 jsonUtility::getInventoryObjPathFromJson(
1189 m_parsedJson, i_vpdFilePath, l_errCode);
1190
1191 if (l_errCode != 0)
1192 {
1193 logging::logMessage(
1194 "Failed to get inventory object path from JSON for FRU [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301195 i_vpdFilePath +
1196 "], error: " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna017567a2025-08-13 02:07:06 -05001197 }
1198
RekhaAparna011ef21002025-02-18 23:47:36 -06001199 const std::string& l_invPathLeafValue =
Rekha Aparna017567a2025-08-13 02:07:06 -05001200 sdbusplus::message::object_path(l_invPath).filename();
Sunny Srivastava78c91072025-02-05 14:09:50 +05301201
RekhaAparna011ef21002025-02-18 23:47:36 -06001202 if ((l_invPathLeafValue.find("pcie_card", 0) !=
1203 std::string::npos))
Sunny Srivastava78c91072025-02-05 14:09:50 +05301204 {
1205 // skip logging any PEL for PCIe cards on pass 1 planar.
1206 return std::make_tuple(false, i_vpdFilePath);
1207 }
1208 }
Rekha Aparna715eaff2025-10-23 02:06:50 -05001209 else if (l_errCode)
1210 {
1211 logging::logMessage(
1212 "Failed to check if system is Pass 1 Planar, error : " +
1213 commonUtility::getErrCodeMsg(l_errCode));
1214 }
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301215 }
Sunny Srivastava78c91072025-02-05 14:09:50 +05301216
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301217 EventLogger::createSyncPel(
Souvik Roy37c6bef2025-07-17 00:55:59 -05001218 EventLogger::getErrorType(ex),
1219 (typeid(ex) == typeid(DataException)) ||
1220 (typeid(ex) == typeid(EccException))
1221 ? types::SeverityType::Warning
1222 : types::SeverityType::Informational,
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301223 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(ex),
1224 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001225
1226 // TODO: Figure out a way to clear data in case of any failure at
1227 // runtime.
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301228
1229 // set present property to false for any error case. In future this will
1230 // be replaced by presence logic.
Souvik Roy6a9553c2025-02-07 01:16:32 -06001231 // Update Present property for this FRU only if we handle Present
1232 // property for the FRU.
1233 if (isPresentPropertyHandlingRequired(
1234 m_parsedJson["frus"][i_vpdFilePath].at(0)))
1235 {
1236 setPresentProperty(i_vpdFilePath, false);
1237 }
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301238
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001239 m_semaphore.release();
1240 return std::make_tuple(false, i_vpdFilePath);
1241 }
Anupama B R4c65fcd2025-09-01 08:09:00 -05001242
1243 setCollectionStatusProperty(i_vpdFilePath,
1244 constants::vpdCollectionCompleted);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001245 m_semaphore.release();
1246 return std::make_tuple(true, i_vpdFilePath);
1247}
1248
Sunny Srivastava61611752025-02-04 00:29:33 -06001249bool Worker::skipPathForCollection(const std::string& i_vpdFilePath)
1250{
1251 if (i_vpdFilePath.empty())
1252 {
1253 return true;
1254 }
1255
1256 // skip processing of system VPD again as it has been already collected.
1257 if (i_vpdFilePath == SYSTEM_VPD_FILE_PATH)
1258 {
1259 return true;
1260 }
1261
1262 if (dbusUtility::isChassisPowerOn())
1263 {
1264 // If chassis is powered on, skip collecting FRUs which are
1265 // powerOffOnly.
Rekha Aparna52041882025-09-01 20:48:07 -05001266
1267 uint16_t l_errCode = 0;
1268 if (jsonUtility::isFruPowerOffOnly(m_parsedJson, i_vpdFilePath,
1269 l_errCode))
Sunny Srivastava61611752025-02-04 00:29:33 -06001270 {
1271 return true;
1272 }
Rekha Aparna52041882025-09-01 20:48:07 -05001273 else if (l_errCode)
1274 {
1275 logging::logMessage(
1276 "Failed to check if FRU is power off only for FRU [" +
1277 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301278 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna52041882025-09-01 20:48:07 -05001279 }
Sunny Srivastava61611752025-02-04 00:29:33 -06001280
Rekha Aparna017567a2025-08-13 02:07:06 -05001281 std::string l_invPath = jsonUtility::getInventoryObjPathFromJson(
1282 m_parsedJson, i_vpdFilePath, l_errCode);
1283
1284 if (l_errCode)
1285 {
1286 logging::logMessage(
1287 "Failed to get inventory path from JSON for FRU [" +
1288 i_vpdFilePath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301289 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna017567a2025-08-13 02:07:06 -05001290
1291 return false;
1292 }
1293
Sunny Srivastava61611752025-02-04 00:29:33 -06001294 const std::string& l_invPathLeafValue =
Rekha Aparna017567a2025-08-13 02:07:06 -05001295 sdbusplus::message::object_path(l_invPath).filename();
Sunny Srivastava61611752025-02-04 00:29:33 -06001296
1297 if ((l_invPathLeafValue.find("pcie_card", 0) != std::string::npos))
1298 {
1299 return true;
1300 }
1301 }
1302
1303 return false;
1304}
1305
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001306void Worker::collectFrusFromJson()
1307{
1308 // A parsed JSON file should be present to pick FRUs EEPROM paths
1309 if (m_parsedJson.empty())
1310 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301311 throw JsonException(
1312 std::string(__FUNCTION__) +
1313 ": Config JSON is mandatory for processing of FRUs through this API.",
1314 m_configJsonPath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001315 }
1316
1317 const nlohmann::json& listOfFrus =
1318 m_parsedJson["frus"].get_ref<const nlohmann::json::object_t&>();
1319
1320 for (const auto& itemFRUS : listOfFrus.items())
1321 {
1322 const std::string& vpdFilePath = itemFRUS.key();
1323
Sunny Srivastava61611752025-02-04 00:29:33 -06001324 if (skipPathForCollection(vpdFilePath))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001325 {
1326 continue;
1327 }
1328
Souvik Roy1f4c8f82025-01-23 00:37:43 -06001329 try
1330 {
1331 std::thread{[vpdFilePath, this]() {
1332 const auto& l_parseResult = parseAndPublishVPD(vpdFilePath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001333
Souvik Roy1f4c8f82025-01-23 00:37:43 -06001334 m_mutex.lock();
1335 m_activeCollectionThreadCount--;
1336 m_mutex.unlock();
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001337
Souvik Roy1f4c8f82025-01-23 00:37:43 -06001338 if (!m_activeCollectionThreadCount)
1339 {
1340 m_isAllFruCollected = true;
1341 }
1342 }}.detach();
1343 }
1344 catch (const std::exception& l_ex)
1345 {
1346 // add vpdFilePath(EEPROM path) to failed list
1347 m_failedEepromPaths.push_front(vpdFilePath);
1348 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001349 }
1350}
1351
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001352void Worker::deleteFruVpd(const std::string& i_dbusObjPath)
1353{
1354 if (i_dbusObjPath.empty())
1355 {
1356 throw std::runtime_error("Given DBus object path is empty.");
1357 }
1358
Rekha Aparna0578dd22025-09-02 08:20:21 -05001359 uint16_t l_errCode = 0;
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001360 const std::string& l_fruPath =
Rekha Aparna0578dd22025-09-02 08:20:21 -05001361 jsonUtility::getFruPathFromJson(m_parsedJson, i_dbusObjPath, l_errCode);
1362
1363 if (l_errCode)
1364 {
1365 logging::logMessage(
1366 "Failed to get FRU path for inventory path [" + i_dbusObjPath +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301367 "], error : " + commonUtility::getErrCodeMsg(l_errCode) +
Rekha Aparna0578dd22025-09-02 08:20:21 -05001368 " Aborting FRU VPD deletion.");
1369 return;
1370 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001371
1372 try
1373 {
1374 auto l_presentPropValue = dbusUtility::readDbusProperty(
1375 constants::pimServiceName, i_dbusObjPath,
1376 constants::inventoryItemInf, "Present");
1377
1378 if (auto l_value = std::get_if<bool>(&l_presentPropValue))
1379 {
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001380 uint16_t l_errCode = 0;
Souvik Roye9120152025-07-02 08:24:38 -05001381 // check if FRU's Present property is handled by vpd-manager
1382 const auto& l_isFruPresenceHandled =
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001383 jsonUtility::isFruPresenceHandled(m_parsedJson, l_fruPath,
1384 l_errCode);
1385
1386 if (l_errCode)
1387 {
1388 throw std::runtime_error(
1389 "Failed to check if FRU's presence is handled, reason: " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301390 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaa1187a52025-09-01 12:42:19 -05001391 }
Souvik Roye9120152025-07-02 08:24:38 -05001392
1393 if (!(*l_value) && l_isFruPresenceHandled)
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001394 {
1395 throw std::runtime_error("Given FRU is not present");
1396 }
Souvik Roye9120152025-07-02 08:24:38 -05001397 else if (*l_value && !l_isFruPresenceHandled)
1398 {
1399 throw std::runtime_error(
1400 "Given FRU is present and its presence is not handled by vpd-manager.");
1401 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001402 else
1403 {
1404 if (jsonUtility::isActionRequired(m_parsedJson, l_fruPath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001405 "preAction", "deletion",
1406 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001407 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001408 if (!processPreAction(l_fruPath, "deletion", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001409 {
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001410 std::string l_msg = "Pre action failed";
1411 if (l_errCode)
1412 {
Rekha Aparnac6159a22025-10-09 12:20:20 +05301413 l_msg += " Reason: " +
1414 commonUtility::getErrCodeMsg(l_errCode);
Sunny Srivastava4f053df2025-09-03 02:27:37 -05001415 }
1416 throw std::runtime_error(l_msg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001417 }
1418 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001419 else if (l_errCode)
1420 {
1421 logging::logMessage(
1422 "Failed to check if pre action required for FRU [" +
1423 l_fruPath + "], error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301424 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001425 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001426
1427 std::vector<std::string> l_interfaceList{
1428 constants::operationalStatusInf};
1429
1430 types::MapperGetSubTree l_subTreeMap =
1431 dbusUtility::getObjectSubTree(i_dbusObjPath, 0,
1432 l_interfaceList);
1433
1434 types::ObjectMap l_objectMap;
1435
1436 // Updates VPD specific interfaces property value under PIM for
1437 // sub FRUs.
1438 for (const auto& [l_objectPath, l_serviceInterfaceMap] :
1439 l_subTreeMap)
1440 {
1441 types::InterfaceMap l_interfaceMap;
Rekha Aparna2c04eeb2025-10-22 22:15:07 -05001442 vpdSpecificUtility::resetDataUnderPIM(
1443 l_objectPath, l_interfaceMap, l_errCode);
1444
1445 if (l_errCode)
1446 {
1447 throw std::runtime_error(
1448 "Failed to reset data under PIM for sub FRU [" +
1449 l_objectPath + "], error : " +
1450 commonUtility::getErrCodeMsg(l_errCode));
1451 }
1452
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001453 l_objectMap.emplace(l_objectPath,
1454 std::move(l_interfaceMap));
1455 }
1456
1457 types::InterfaceMap l_interfaceMap;
Rekha Aparna2c04eeb2025-10-22 22:15:07 -05001458 vpdSpecificUtility::resetDataUnderPIM(
1459 i_dbusObjPath, l_interfaceMap, l_errCode);
1460
1461 if (l_errCode)
1462 {
1463 throw std::runtime_error(
1464 "Failed to reset data under PIM, error : " +
1465 commonUtility::getErrCodeMsg(l_errCode));
1466 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001467
1468 l_objectMap.emplace(i_dbusObjPath, std::move(l_interfaceMap));
1469
1470 if (!dbusUtility::callPIM(std::move(l_objectMap)))
1471 {
1472 throw std::runtime_error("Call to PIM failed.");
1473 }
1474
1475 if (jsonUtility::isActionRequired(m_parsedJson, l_fruPath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001476 "postAction", "deletion",
1477 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001478 {
1479 if (!processPostAction(l_fruPath, "deletion"))
1480 {
1481 throw std::runtime_error("Post action failed");
1482 }
1483 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001484 else if (l_errCode)
1485 {
1486 logging::logMessage(
1487 "Failed to check if post action required during deletion for FRU [" +
1488 l_fruPath + "], error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301489 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001490 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001491 }
1492 }
1493 else
1494 {
1495 logging::logMessage(
1496 "Can't process delete VPD for FRU [" + i_dbusObjPath +
1497 "] as unable to read present property");
1498 return;
1499 }
1500
1501 logging::logMessage(
1502 "Successfully completed deletion of FRU VPD for " + i_dbusObjPath);
1503 }
1504 catch (const std::exception& l_ex)
1505 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001506 uint16_t l_errCode = 0;
1507 std::string l_errMsg =
1508 "Failed to delete VPD for FRU : " + i_dbusObjPath +
1509 " error: " + std::string(l_ex.what());
1510
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001511 if (jsonUtility::isActionRequired(m_parsedJson, l_fruPath,
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001512 "postFailAction", "deletion",
1513 l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001514 {
1515 if (!jsonUtility::executePostFailAction(m_parsedJson, l_fruPath,
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001516 "deletion", l_errCode))
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001517 {
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001518 l_errMsg += ". Post fail action also failed, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301519 commonUtility::getErrCodeMsg(l_errCode);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001520 }
1521 }
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001522 else if (l_errCode)
1523 {
1524 l_errMsg +=
1525 ". Failed to check if post fail action required, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301526 commonUtility::getErrCodeMsg(l_errCode);
Rekha Aparnab50bf0e2025-09-02 21:13:26 -05001527 }
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001528
Rekha Aparnaff7d7992025-09-01 11:08:53 -05001529 logging::logMessage(l_errMsg);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001530 }
1531}
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301532
1533void Worker::setPresentProperty(const std::string& i_vpdPath,
1534 const bool& i_value)
1535{
1536 try
1537 {
1538 if (i_vpdPath.empty())
1539 {
1540 throw std::runtime_error(
1541 "Path is empty. Can't set present property");
1542 }
1543
1544 types::ObjectMap l_objectInterfaceMap;
1545
1546 // If the given path is EEPROM path.
1547 if (m_parsedJson["frus"].contains(i_vpdPath))
1548 {
1549 for (const auto& l_Fru : m_parsedJson["frus"][i_vpdPath])
1550 {
1551 sdbusplus::message::object_path l_fruObjectPath(
1552 l_Fru["inventoryPath"]);
1553
1554 types::PropertyMap l_propertyValueMap;
1555 l_propertyValueMap.emplace("Present", i_value);
1556
Rekha Aparnad3662222025-10-14 10:33:17 -05001557 uint16_t l_errCode = 0;
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301558 types::InterfaceMap l_interfaces;
Rekha Aparnad3662222025-10-14 10:33:17 -05001559 vpdSpecificUtility::insertOrMerge(
1560 l_interfaces, constants::inventoryItemInf,
1561 move(l_propertyValueMap), l_errCode);
1562
1563 if (l_errCode)
1564 {
1565 logging::logMessage(
1566 "Failed to insert value into map, error : " +
1567 commonUtility::getErrCodeMsg(l_errCode));
1568 }
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301569
1570 l_objectInterfaceMap.emplace(std::move(l_fruObjectPath),
1571 std::move(l_interfaces));
1572 }
1573 }
1574 else
1575 {
1576 // consider it as an inventory path.
1577 if (i_vpdPath.find(constants::pimPath) != constants::VALUE_0)
1578 {
1579 throw std::runtime_error(
1580 "Invalid inventory path: " + i_vpdPath);
1581 }
1582
1583 types::PropertyMap l_propertyValueMap;
1584 l_propertyValueMap.emplace("Present", i_value);
1585
Rekha Aparnad3662222025-10-14 10:33:17 -05001586 uint16_t l_errCode = 0;
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301587 types::InterfaceMap l_interfaces;
Rekha Aparnad3662222025-10-14 10:33:17 -05001588 vpdSpecificUtility::insertOrMerge(
1589 l_interfaces, constants::inventoryItemInf,
1590 move(l_propertyValueMap), l_errCode);
1591
1592 if (l_errCode)
1593 {
1594 logging::logMessage(
1595 "Failed to insert value into map, error : " +
1596 commonUtility::getErrCodeMsg(l_errCode));
1597 }
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301598
1599 l_objectInterfaceMap.emplace(i_vpdPath, std::move(l_interfaces));
1600 }
1601
1602 // Notify PIM
1603 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
1604 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301605 throw DbusException(
1606 std::string(__FUNCTION__) +
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301607 "Call to PIM failed while setting present property for path " +
1608 i_vpdPath);
1609 }
1610 }
1611 catch (const std::exception& l_ex)
1612 {
Sunny Srivastava4c509c22025-03-25 12:43:40 +05301613 EventLogger::createSyncPel(
1614 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
1615 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
1616 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
Sunny Srivastavad159bb42025-01-09 11:13:50 +05301617 }
1618}
1619
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301620void Worker::performVpdRecollection()
1621{
1622 try
1623 {
1624 // Check if system config JSON is present
1625 if (m_parsedJson.empty())
1626 {
1627 throw std::runtime_error(
1628 "System config json object is empty, can't process recollection.");
1629 }
1630
Rekha Aparna88d53302025-09-01 18:16:55 -05001631 uint16_t l_errCode = 0;
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301632 const auto& l_frusReplaceableAtStandby =
Rekha Aparna88d53302025-09-01 18:16:55 -05001633 jsonUtility::getListOfFrusReplaceableAtStandby(m_parsedJson,
1634 l_errCode);
1635
1636 if (l_errCode)
1637 {
1638 logging::logMessage(
1639 "Failed to get list of FRUs replaceable at runtime, error : " +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301640 commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna88d53302025-09-01 18:16:55 -05001641 return;
1642 }
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301643
1644 for (const auto& l_fruInventoryPath : l_frusReplaceableAtStandby)
1645 {
1646 // ToDo: Add some logic/trace to know the flow to
1647 // collectSingleFruVpd has been directed via
1648 // performVpdRecollection.
1649 collectSingleFruVpd(l_fruInventoryPath);
1650 }
1651 return;
1652 }
1653
1654 catch (const std::exception& l_ex)
1655 {
1656 // TODO Log PEL
1657 logging::logMessage(
1658 "VPD recollection failed with error: " + std::string(l_ex.what()));
1659 }
1660}
1661
1662void Worker::collectSingleFruVpd(
1663 const sdbusplus::message::object_path& i_dbusObjPath)
1664{
Anupama B R48f297b2025-08-13 04:29:06 -05001665 std::string l_fruPath{};
Rekha Aparna0578dd22025-09-02 08:20:21 -05001666 uint16_t l_errCode = 0;
1667
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301668 try
1669 {
1670 // Check if system config JSON is present
1671 if (m_parsedJson.empty())
1672 {
1673 logging::logMessage(
1674 "System config JSON object not present. Single FRU VPD collection is not performed for " +
1675 std::string(i_dbusObjPath));
1676 return;
1677 }
1678
1679 // Get FRU path for the given D-bus object path from JSON
Rekha Aparna0578dd22025-09-02 08:20:21 -05001680 l_fruPath = jsonUtility::getFruPathFromJson(m_parsedJson, i_dbusObjPath,
1681 l_errCode);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301682
1683 if (l_fruPath.empty())
1684 {
Rekha Aparna0578dd22025-09-02 08:20:21 -05001685 if (l_errCode)
1686 {
1687 logging::logMessage(
1688 "Failed to get FRU path for [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301689 std::string(i_dbusObjPath) +
1690 "], error : " + commonUtility::getErrCodeMsg(l_errCode) +
Rekha Aparna0578dd22025-09-02 08:20:21 -05001691 " Aborting single FRU VPD collection.");
1692 return;
1693 }
1694
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301695 logging::logMessage(
1696 "D-bus object path not present in JSON. Single FRU VPD collection is not performed for " +
1697 std::string(i_dbusObjPath));
1698 return;
1699 }
1700
1701 // Check if host is up and running
1702 if (dbusUtility::isHostRunning())
1703 {
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001704 uint16_t l_errCode = 0;
1705 bool isFruReplaceableAtRuntime =
1706 jsonUtility::isFruReplaceableAtRuntime(m_parsedJson, l_fruPath,
1707 l_errCode);
1708
1709 if (l_errCode)
1710 {
1711 logging::logMessage(
1712 "Failed to check if FRU is replaceable at runtime for FRU : [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301713 std::string(i_dbusObjPath) +
1714 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001715 return;
1716 }
1717
1718 if (!isFruReplaceableAtRuntime)
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301719 {
1720 logging::logMessage(
1721 "Given FRU is not replaceable at host runtime. Single FRU VPD collection is not performed for " +
1722 std::string(i_dbusObjPath));
1723 return;
1724 }
1725 }
1726 else if (dbusUtility::isBMCReady())
1727 {
Rekha Aparna40845612025-09-01 19:58:56 -05001728 uint16_t l_errCode = 0;
1729 bool isFruReplaceableAtStandby =
1730 jsonUtility::isFruReplaceableAtStandby(m_parsedJson, l_fruPath,
1731 l_errCode);
1732
1733 if (l_errCode)
1734 {
1735 logging::logMessage(
1736 "Error while checking if FRU is replaceable at standby for FRU [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301737 std::string(i_dbusObjPath) +
1738 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna40845612025-09-01 19:58:56 -05001739 }
1740
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001741 bool isFruReplaceableAtRuntime =
1742 jsonUtility::isFruReplaceableAtRuntime(m_parsedJson, l_fruPath,
1743 l_errCode);
1744
1745 if (l_errCode)
1746 {
1747 logging::logMessage(
1748 "Failed to check if FRU is replaceable at runtime for FRU : [" +
Rekha Aparnac6159a22025-10-09 12:20:20 +05301749 std::string(i_dbusObjPath) +
1750 "], error : " + commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparnaad0db9e2025-09-01 20:29:18 -05001751 return;
1752 }
1753
1754 if (!isFruReplaceableAtStandby && (!isFruReplaceableAtRuntime))
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301755 {
1756 logging::logMessage(
1757 "Given FRU is neither replaceable at standby nor replaceable at runtime. Single FRU VPD collection is not performed for " +
1758 std::string(i_dbusObjPath));
1759 return;
1760 }
1761 }
1762
Anupama B R5cd1b2d2025-08-05 04:57:40 -05001763 // Set collection Status as InProgress. Since it's an intermediate state
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301764 // D-bus set-property call is good enough to update the status.
Anupama B R5cd1b2d2025-08-05 04:57:40 -05001765 const std::string& l_collStatusProp = "Status";
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301766
Anupama B R4c65fcd2025-09-01 08:09:00 -05001767 setCollectionStatusProperty(l_fruPath,
1768 constants::vpdCollectionInProgress);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301769
1770 // Parse VPD
1771 types::VPDMapVariant l_parsedVpd = parseVpdFile(l_fruPath);
1772
1773 // If l_parsedVpd is pointing to std::monostate
1774 if (l_parsedVpd.index() == 0)
1775 {
1776 throw std::runtime_error(
1777 "VPD parsing failed for " + std::string(i_dbusObjPath));
1778 }
1779
1780 // Get D-bus object map from worker class
1781 types::ObjectMap l_dbusObjectMap;
1782 populateDbus(l_parsedVpd, l_dbusObjectMap, l_fruPath);
1783
1784 if (l_dbusObjectMap.empty())
1785 {
1786 throw std::runtime_error(
1787 "Failed to create D-bus object map. Single FRU VPD collection failed for " +
1788 std::string(i_dbusObjPath));
1789 }
1790
1791 // Call PIM's Notify method
1792 if (!dbusUtility::callPIM(move(l_dbusObjectMap)))
1793 {
1794 throw std::runtime_error(
1795 "Notify PIM failed. Single FRU VPD collection failed for " +
1796 std::string(i_dbusObjPath));
1797 }
Anupama B R4c65fcd2025-09-01 08:09:00 -05001798 setCollectionStatusProperty(l_fruPath,
1799 constants::vpdCollectionCompleted);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301800 }
1801 catch (const std::exception& l_error)
1802 {
Anupama B R48f297b2025-08-13 04:29:06 -05001803 setCollectionStatusProperty(l_fruPath, constants::vpdCollectionFailed);
Sunny Srivastava380efbb2025-04-25 10:28:30 +05301804 // TODO: Log PEL
1805 logging::logMessage(std::string(l_error.what()));
1806 }
1807}
Anupama B R24691d22025-05-21 08:14:15 -05001808
1809void Worker::setCollectionStatusProperty(
1810 const std::string& i_vpdPath, const std::string& i_value) const noexcept
1811{
1812 try
1813 {
1814 if (i_vpdPath.empty())
1815 {
1816 throw std::runtime_error(
Anupama B R5cd1b2d2025-08-05 04:57:40 -05001817 "Given path is empty. Can't set collection Status property");
Anupama B R24691d22025-05-21 08:14:15 -05001818 }
1819
Anupama B R4c65fcd2025-09-01 08:09:00 -05001820 types::PropertyMap l_timeStampMap;
1821 if (i_value == constants::vpdCollectionCompleted ||
1822 i_value == constants::vpdCollectionFailed)
1823 {
1824 l_timeStampMap.emplace(
1825 "CompletedTime",
1826 types::DbusVariantType{
1827 commonUtility::getCurrentTimeSinceEpoch()});
1828 }
1829 else if (i_value == constants::vpdCollectionInProgress)
1830 {
1831 l_timeStampMap.emplace(
1832 "StartTime", types::DbusVariantType{
1833 commonUtility::getCurrentTimeSinceEpoch()});
1834 }
1835 else if (i_value == constants::vpdCollectionNotStarted)
1836 {
1837 l_timeStampMap.emplace("StartTime", 0);
1838 l_timeStampMap.emplace("CompletedTime", 0);
1839 }
1840
Anupama B R24691d22025-05-21 08:14:15 -05001841 types::ObjectMap l_objectInterfaceMap;
1842
1843 if (m_parsedJson["frus"].contains(i_vpdPath))
1844 {
1845 for (const auto& l_Fru : m_parsedJson["frus"][i_vpdPath])
1846 {
1847 sdbusplus::message::object_path l_fruObjectPath(
1848 l_Fru["inventoryPath"]);
1849
1850 types::PropertyMap l_propertyValueMap;
Anupama B R5cd1b2d2025-08-05 04:57:40 -05001851 l_propertyValueMap.emplace("Status", i_value);
Anupama B R4c65fcd2025-09-01 08:09:00 -05001852 l_propertyValueMap.insert(l_timeStampMap.begin(),
1853 l_timeStampMap.end());
Anupama B R24691d22025-05-21 08:14:15 -05001854
Rekha Aparnad3662222025-10-14 10:33:17 -05001855 uint16_t l_errCode = 0;
Anupama B R24691d22025-05-21 08:14:15 -05001856 types::InterfaceMap l_interfaces;
1857 vpdSpecificUtility::insertOrMerge(
1858 l_interfaces, constants::vpdCollectionInterface,
Rekha Aparnad3662222025-10-14 10:33:17 -05001859 move(l_propertyValueMap), l_errCode);
1860
1861 if (l_errCode)
1862 {
1863 logging::logMessage(
1864 "Failed to insert value into map, error : " +
1865 commonUtility::getErrCodeMsg(l_errCode));
1866 }
Anupama B R24691d22025-05-21 08:14:15 -05001867
1868 l_objectInterfaceMap.emplace(std::move(l_fruObjectPath),
1869 std::move(l_interfaces));
1870 }
1871 }
1872 else
1873 {
1874 // consider it as an inventory path.
1875 if (i_vpdPath.find(constants::pimPath) != constants::VALUE_0)
1876 {
1877 throw std::runtime_error(
1878 "Invalid inventory path: " + i_vpdPath +
Anupama B R5cd1b2d2025-08-05 04:57:40 -05001879 ". Can't set collection Status property");
Anupama B R24691d22025-05-21 08:14:15 -05001880 }
1881
1882 types::PropertyMap l_propertyValueMap;
Anupama B R5cd1b2d2025-08-05 04:57:40 -05001883 l_propertyValueMap.emplace("Status", i_value);
Anupama B R4c65fcd2025-09-01 08:09:00 -05001884 l_propertyValueMap.insert(l_timeStampMap.begin(),
1885 l_timeStampMap.end());
Anupama B R24691d22025-05-21 08:14:15 -05001886
Rekha Aparnad3662222025-10-14 10:33:17 -05001887 uint16_t l_errCode = 0;
Anupama B R24691d22025-05-21 08:14:15 -05001888 types::InterfaceMap l_interfaces;
Rekha Aparnad3662222025-10-14 10:33:17 -05001889 vpdSpecificUtility::insertOrMerge(
1890 l_interfaces, constants::vpdCollectionInterface,
1891 move(l_propertyValueMap), l_errCode);
1892
1893 if (l_errCode)
1894 {
1895 logging::logMessage(
1896 "Failed to insert value into map, error : " +
1897 commonUtility::getErrCodeMsg(l_errCode));
1898 }
Anupama B R24691d22025-05-21 08:14:15 -05001899
1900 l_objectInterfaceMap.emplace(i_vpdPath, std::move(l_interfaces));
1901 }
1902
1903 // Notify PIM
1904 if (!dbusUtility::callPIM(move(l_objectInterfaceMap)))
1905 {
1906 throw DbusException(
1907 std::string(__FUNCTION__) +
Anupama B R5cd1b2d2025-08-05 04:57:40 -05001908 "Call to PIM failed while setting collection Status property for path " +
Anupama B R24691d22025-05-21 08:14:15 -05001909 i_vpdPath);
1910 }
1911 }
1912 catch (const std::exception& l_ex)
1913 {
1914 EventLogger::createSyncPel(
1915 EventLogger::getErrorType(l_ex), types::SeverityType::Warning,
1916 __FILE__, __FUNCTION__, 0, EventLogger::getErrorMsg(l_ex),
1917 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
1918 }
1919}
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001920} // namespace vpd