blob: 8e3a53e2fe25b0367a2e0a40b62d4fde03e81c83 [file] [log] [blame]
Anupama B R445819f2025-09-18 11:00:25 -05001#include "prime_inventory.hpp"
2
3#include "event_logger.hpp"
4#include "exceptions.hpp"
Rekha Aparnac6159a22025-10-09 12:20:20 +05305#include "utility/common_utility.hpp"
Anupama B R445819f2025-09-18 11:00:25 -05006#include "utility/dbus_utility.hpp"
7#include "utility/json_utility.hpp"
8#include "utility/vpd_specific_utility.hpp"
9
10#include <string>
Anupama B Rca738cf2025-09-19 06:40:54 -050011#include <vector>
Anupama B R445819f2025-09-18 11:00:25 -050012
13PrimeInventory::PrimeInventory()
14{
15 try
16 {
17 uint16_t l_errCode = 0;
18 m_sysCfgJsonObj =
19 vpd::jsonUtility::getParsedJson(INVENTORY_JSON_SYM_LINK, l_errCode);
20
21 if (l_errCode)
22 {
23 throw std::runtime_error(
24 "JSON parsing failed for file [ " +
Rekha Aparnac6159a22025-10-09 12:20:20 +053025 std::string(INVENTORY_JSON_SYM_LINK) +
26 " ], error : " + vpd::commonUtility::getErrCodeMsg(l_errCode));
Anupama B R445819f2025-09-18 11:00:25 -050027 }
28
29 // check for mandatory fields at this point itself.
30 if (!m_sysCfgJsonObj.contains("frus"))
31 {
32 throw std::runtime_error(
33 "Mandatory tag(s) missing from JSON file [" +
34 std::string(INVENTORY_JSON_SYM_LINK) + "]");
35 }
Anupama B Rca738cf2025-09-19 06:40:54 -050036
37 m_logger = vpd::Logger::getLoggerInstance();
Anupama B R445819f2025-09-18 11:00:25 -050038 }
39 catch (const std::exception& l_ex)
40 {
41 vpd::EventLogger::createSyncPel(
42 vpd::types::ErrorType::JsonFailure,
43 vpd::types::SeverityType::Critical, __FILE__, __FUNCTION__, 0,
44 "Prime inventory failed, reason: " + std::string(l_ex.what()),
45 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
46
47 throw;
48 }
49}
50
51bool PrimeInventory::isPrimingRequired() const noexcept
52{
Anupama B Rca738cf2025-09-19 06:40:54 -050053 try
54 {
55 // get all object paths under PIM
56 const auto l_objectPaths = vpd::dbusUtility::GetSubTreePaths(
57 vpd::constants::systemInvPath, 0,
58 std::vector<std::string>{vpd::constants::vpdCollectionInterface});
59
60 const nlohmann::json& l_listOfFrus =
61 m_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
62
63 size_t l_invPathCount = 0;
64
65 for (const auto& l_itemFRUS : l_listOfFrus.items())
66 {
67 for (const auto& l_Fru : l_itemFRUS.value())
68 {
69 if (l_Fru.contains("ccin") || (l_Fru.contains("noprime") &&
70 l_Fru.value("noprime", false)))
71 {
72 continue;
73 }
74
75 l_invPathCount += 1;
76 }
77 }
Anupama B R61741a42025-10-16 00:31:26 -050078 return (l_objectPaths.size() < l_invPathCount);
Anupama B Rca738cf2025-09-19 06:40:54 -050079 }
80 catch (const std::exception& l_ex)
81 {
82 m_logger->logMessage(
83 "Error while checking is priming required or not, error: " +
84 std::string(l_ex.what()));
85 }
86
87 // In case of any error, perform priming, as it's unclear whether priming is
88 // required.
Anupama B R445819f2025-09-18 11:00:25 -050089 return true;
90}
91
92void PrimeInventory::primeSystemBlueprint() const noexcept
93{
94 try
95 {
Anupama B R61741a42025-10-16 00:31:26 -050096 if (m_sysCfgJsonObj.empty() || !isPrimingRequired())
Anupama B Rca738cf2025-09-19 06:40:54 -050097 {
98 return;
99 }
100
101 const nlohmann::json& l_listOfFrus =
102 m_sysCfgJsonObj["frus"].get_ref<const nlohmann::json::object_t&>();
103
104 vpd::types::ObjectMap l_objectInterfaceMap;
105 for (const auto& l_itemFRUS : l_listOfFrus.items())
106 {
107 const std::string& l_vpdFilePath = l_itemFRUS.key();
108
109 if (l_vpdFilePath == SYSTEM_VPD_FILE_PATH)
110 {
111 continue;
112 }
113
114 // Prime the inventry for FRUs
115 for (const auto& l_Fru : m_sysCfgJsonObj["frus"][l_vpdFilePath])
116 {
117 if (!primeInventory(l_objectInterfaceMap, l_Fru))
118 {
119 m_logger->logMessage(
120 "Priming of inventory failed for FRU " +
121 std::string(l_Fru["inventoryPath"]));
122 }
123 }
124 }
125
126 // Notify PIM
127 if (!l_objectInterfaceMap.empty())
128 {
129 if (!vpd::dbusUtility::callPIM(move(l_objectInterfaceMap)))
130 {
131 m_logger->logMessage(
132 "Call to PIM failed while priming inventory");
133 }
134 }
135 else
136 {
137 m_logger->logMessage("Priming inventory failed");
138 }
Anupama B R445819f2025-09-18 11:00:25 -0500139 }
140 catch (const std::exception& l_ex)
141 {
Anupama B Rca738cf2025-09-19 06:40:54 -0500142 m_logger->logMessage("Prime system inventory failed, reason: " +
143 std::string(l_ex.what()));
Anupama B R445819f2025-09-18 11:00:25 -0500144 }
145}
146
147bool PrimeInventory::primeInventory(
Anupama B Rca738cf2025-09-19 06:40:54 -0500148 vpd::types::ObjectMap& o_objectInterfaceMap,
149 const nlohmann::json& i_fruJsonObj) const noexcept
Anupama B R445819f2025-09-18 11:00:25 -0500150{
Anupama B Rca738cf2025-09-19 06:40:54 -0500151 if (i_fruJsonObj.empty())
152 {
153 m_logger->logMessage("Empty FRU JSON given");
154 return false;
155 }
156
157 vpd::types::InterfaceMap l_interfaces;
158 sdbusplus::message::object_path l_fruObjectPath(
159 i_fruJsonObj["inventoryPath"]);
160
161 if (i_fruJsonObj.contains("ccin"))
162 {
163 return true;
164 }
165
166 if (i_fruJsonObj.contains("noprime") &&
167 i_fruJsonObj.value("noprime", false))
168 {
169 return true;
170 }
171
172 // Reset data under PIM for this FRU only if the FRU is not synthesized
173 // and we handle it's Present property.
174 if (isPresentPropertyHandlingRequired(i_fruJsonObj))
175 {
176 // Clear data under PIM if already exists.
Rekha Aparna2c04eeb2025-10-22 22:15:07 -0500177 uint16_t l_errCode = 0;
Anupama B Rca738cf2025-09-19 06:40:54 -0500178 vpd::vpdSpecificUtility::resetDataUnderPIM(
Rekha Aparna2c04eeb2025-10-22 22:15:07 -0500179 std::string(i_fruJsonObj["inventoryPath"]), l_interfaces,
180 l_errCode);
181
182 if (l_errCode)
183 {
184 m_logger->logMessage(
185 "Failed to reset data under PIM for path [" +
186 std::string(i_fruJsonObj["inventoryPath"]) +
187 "], error : " + vpd::commonUtility::getErrCodeMsg(l_errCode));
188 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500189 }
190
191 // Add extra interfaces mentioned in the Json config file
192 if (i_fruJsonObj.contains("extraInterfaces"))
193 {
194 populateInterfaces(i_fruJsonObj["extraInterfaces"], l_interfaces,
195 std::monostate{});
196 }
197
198 vpd::types::PropertyMap l_propertyValueMap;
199
200 // Update Present property for this FRU only if we handle Present
201 // property for the FRU.
202 if (isPresentPropertyHandlingRequired(i_fruJsonObj))
203 {
204 l_propertyValueMap.emplace("Present", false);
205
206 // TODO: Present based on file will be taken care in future.
207 // By default present is set to false for FRU at the time of
208 // priming. Once collection goes through, it will be set to true in
209 // that flow.
210 /*if (std::filesystem::exists(i_vpdFilePath))
211 {
212 l_propertyValueMap["Present"] = true;
213 }*/
214 }
215
Rekha Aparnad3662222025-10-14 10:33:17 -0500216 uint16_t l_errCode = 0;
217
Anupama B Rca738cf2025-09-19 06:40:54 -0500218 vpd::vpdSpecificUtility::insertOrMerge(
219 l_interfaces, "xyz.openbmc_project.Inventory.Item",
Rekha Aparnad3662222025-10-14 10:33:17 -0500220 move(l_propertyValueMap), l_errCode);
221
222 if (l_errCode)
223 {
224 m_logger->logMessage("Failed to insert value into map, error : " +
225 vpd::commonUtility::getErrCodeMsg(l_errCode));
226 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500227
228 if (i_fruJsonObj.value("inherit", true) &&
229 m_sysCfgJsonObj.contains("commonInterfaces"))
230 {
231 populateInterfaces(m_sysCfgJsonObj["commonInterfaces"], l_interfaces,
232 std::monostate{});
233 }
234
235 processFunctionalProperty(i_fruJsonObj["inventoryPath"], l_interfaces);
236 processEnabledProperty(i_fruJsonObj["inventoryPath"], l_interfaces);
237
238 // Emplace the default state of FRU VPD collection
239 vpd::types::PropertyMap l_fruCollectionProperty = {
240 {"Status", vpd::constants::vpdCollectionNotStarted}};
241
Rekha Aparnad3662222025-10-14 10:33:17 -0500242 l_errCode = 0;
Anupama B Rca738cf2025-09-19 06:40:54 -0500243 vpd::vpdSpecificUtility::insertOrMerge(
244 l_interfaces, vpd::constants::vpdCollectionInterface,
Rekha Aparnad3662222025-10-14 10:33:17 -0500245 std::move(l_fruCollectionProperty), l_errCode);
246
247 if (l_errCode)
248 {
249 m_logger->logMessage("Failed to insert value into map, error : " +
250 vpd::commonUtility::getErrCodeMsg(l_errCode));
251 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500252
253 o_objectInterfaceMap.emplace(std::move(l_fruObjectPath),
254 std::move(l_interfaces));
255
Anupama B R445819f2025-09-18 11:00:25 -0500256 return true;
257}
258
259void PrimeInventory::populateInterfaces(
Anupama B Rca738cf2025-09-19 06:40:54 -0500260 const nlohmann::json& i_interfaceJson,
261 vpd::types::InterfaceMap& io_interfaceMap,
262 const vpd::types::VPDMapVariant& i_parsedVpdMap) const noexcept
Anupama B R445819f2025-09-18 11:00:25 -0500263{
Souvik Roy0f740562025-10-27 14:43:33 +0000264 if (i_interfaceJson.empty())
265 {
266 return;
267 }
268
Anupama B Rca738cf2025-09-19 06:40:54 -0500269 for (const auto& l_interfacesPropPair : i_interfaceJson.items())
270 {
271 const std::string& l_interface = l_interfacesPropPair.key();
272 vpd::types::PropertyMap l_propertyMap;
Rekha Aparnad3662222025-10-14 10:33:17 -0500273 uint16_t l_errCode = 0;
Anupama B Rca738cf2025-09-19 06:40:54 -0500274
275 for (const auto& l_propValuePair : l_interfacesPropPair.value().items())
276 {
277 const std::string l_property = l_propValuePair.key();
278
279 if (l_propValuePair.value().is_boolean())
280 {
281 l_propertyMap.emplace(l_property,
282 l_propValuePair.value().get<bool>());
283 }
284 else if (l_propValuePair.value().is_string())
285 {
286 if (l_property.compare("LocationCode") == 0 &&
287 l_interface.compare("com.ibm.ipzvpd.Location") == 0)
288 {
289 std::string l_value =
290 vpd::vpdSpecificUtility::getExpandedLocationCode(
291 l_propValuePair.value().get<std::string>(),
Rekha Aparna6256db92025-10-17 09:58:49 -0500292 i_parsedVpdMap, l_errCode);
293
294 if (l_errCode)
295 {
296 m_logger->logMessage(
297 "Failed to get expanded location code for location code - " +
298 l_propValuePair.value().get<std::string>() +
299 " ,error : " +
300 vpd::commonUtility::getErrCodeMsg(l_errCode));
301
302 l_errCode = 0;
303 }
304
Anupama B Rca738cf2025-09-19 06:40:54 -0500305 l_propertyMap.emplace(l_property, l_value);
306
307 auto l_locCodeProperty = l_propertyMap;
308 vpd::vpdSpecificUtility::insertOrMerge(
309 io_interfaceMap,
310 std::string(vpd::constants::xyzLocationCodeInf),
Rekha Aparnad3662222025-10-14 10:33:17 -0500311 move(l_locCodeProperty), l_errCode);
312
313 if (l_errCode)
314 {
315 m_logger->logMessage(
316 "Failed to insert value into map, error : " +
317 vpd::commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna6256db92025-10-17 09:58:49 -0500318
319 l_errCode = 0;
Rekha Aparnad3662222025-10-14 10:33:17 -0500320 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500321 }
322 else
323 {
324 l_propertyMap.emplace(
325 l_property, l_propValuePair.value().get<std::string>());
326 }
327 }
328 else if (l_propValuePair.value().is_array())
329 {
330 try
331 {
332 l_propertyMap.emplace(l_property,
333 l_propValuePair.value()
334 .get<vpd::types::BinaryVector>());
335 }
336 catch (const nlohmann::detail::type_error& e)
337 {
338 std::cerr << "Type exception: " << e.what() << "\n";
339 }
340 }
341 else if (l_propValuePair.value().is_number())
342 {
343 // For now assume the value is a size_t. In the future it would
344 // be nice to come up with a way to get the type from the JSON.
345 l_propertyMap.emplace(l_property,
346 l_propValuePair.value().get<size_t>());
347 }
348 else if (l_propValuePair.value().is_object())
349 {
350 const std::string& l_record =
351 l_propValuePair.value().value("recordName", "");
352 const std::string& l_keyword =
353 l_propValuePair.value().value("keywordName", "");
354 const std::string& l_encoding =
355 l_propValuePair.value().value("encoding", "");
356
357 if (auto l_ipzVpdMap =
358 std::get_if<vpd::types::IPZVpdMap>(&i_parsedVpdMap))
359 {
360 if (!l_record.empty() && !l_keyword.empty() &&
361 (*l_ipzVpdMap).count(l_record) &&
362 (*l_ipzVpdMap).at(l_record).count(l_keyword))
363 {
364 auto l_encoded = vpd::vpdSpecificUtility::encodeKeyword(
365 ((*l_ipzVpdMap).at(l_record).at(l_keyword)),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500366 l_encoding, l_errCode);
367
368 if (l_errCode)
369 {
370 m_logger->logMessage(
371 "Failed to get encoded keyword value for : " +
372 l_keyword + ", error : " +
373 vpd::commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna6256db92025-10-17 09:58:49 -0500374
375 l_errCode = 0;
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500376 }
377
Anupama B Rca738cf2025-09-19 06:40:54 -0500378 l_propertyMap.emplace(l_property, l_encoded);
379 }
380 }
381 else if (auto l_kwdVpdMap =
382 std::get_if<vpd::types::KeywordVpdMap>(
383 &i_parsedVpdMap))
384 {
385 if (!l_keyword.empty() && (*l_kwdVpdMap).count(l_keyword))
386 {
387 if (auto l_kwValue =
388 std::get_if<vpd::types::BinaryVector>(
389 &(*l_kwdVpdMap).at(l_keyword)))
390 {
391 auto l_encodedValue =
392 vpd::vpdSpecificUtility::encodeKeyword(
393 std::string((*l_kwValue).begin(),
394 (*l_kwValue).end()),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500395 l_encoding, l_errCode);
396
397 if (l_errCode)
398 {
399 m_logger->logMessage(
400 "Failed to get encoded keyword value for : " +
401 l_keyword + ", error : " +
402 vpd::commonUtility::getErrCodeMsg(
403 l_errCode));
Rekha Aparna6256db92025-10-17 09:58:49 -0500404
405 l_errCode = 0;
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500406 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500407
408 l_propertyMap.emplace(l_property, l_encodedValue);
409 }
410 else if (auto l_kwValue = std::get_if<std::string>(
411 &(*l_kwdVpdMap).at(l_keyword)))
412 {
413 auto l_encodedValue =
414 vpd::vpdSpecificUtility::encodeKeyword(
415 std::string((*l_kwValue).begin(),
416 (*l_kwValue).end()),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500417 l_encoding, l_errCode);
418
419 if (l_errCode)
420 {
421 m_logger->logMessage(
422 "Failed to get encoded keyword value for : " +
423 l_keyword + ", error : " +
424 vpd::commonUtility::getErrCodeMsg(
425 l_errCode));
Rekha Aparna6256db92025-10-17 09:58:49 -0500426
427 l_errCode = 0;
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500428 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500429
430 l_propertyMap.emplace(l_property, l_encodedValue);
431 }
432 else if (auto l_uintValue = std::get_if<size_t>(
433 &(*l_kwdVpdMap).at(l_keyword)))
434 {
435 l_propertyMap.emplace(l_property, *l_uintValue);
436 }
437 else
438 {
439 m_logger->logMessage(
440 "Unknown keyword found, Keywrod = " +
441 l_keyword);
442 }
443 }
444 }
445 }
446 }
447 vpd::vpdSpecificUtility::insertOrMerge(io_interfaceMap, l_interface,
Rekha Aparnad3662222025-10-14 10:33:17 -0500448 move(l_propertyMap), l_errCode);
449
450 if (l_errCode)
451 {
452 m_logger->logMessage("Failed to insert value into map, error : " +
453 vpd::commonUtility::getErrCodeMsg(l_errCode));
Rekha Aparna6256db92025-10-17 09:58:49 -0500454
455 l_errCode = 0;
Rekha Aparnad3662222025-10-14 10:33:17 -0500456 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500457 }
Anupama B R445819f2025-09-18 11:00:25 -0500458}
459
460void PrimeInventory::processFunctionalProperty(
Anupama B Rca738cf2025-09-19 06:40:54 -0500461 const std::string& i_inventoryObjPath,
462 vpd::types::InterfaceMap& io_interfaces) const noexcept
Anupama B R445819f2025-09-18 11:00:25 -0500463{
Anupama B Rca738cf2025-09-19 06:40:54 -0500464 if (!vpd::dbusUtility::isChassisPowerOn())
465 {
466 std::vector<std::string> l_operationalStatusInf{
467 vpd::constants::operationalStatusInf};
468
469 auto l_mapperObjectMap = vpd::dbusUtility::getObjectMap(
470 i_inventoryObjPath, l_operationalStatusInf);
471
472 // If the object has been found. Check if it is under PIM.
473 if (l_mapperObjectMap.size() != 0)
474 {
475 for (const auto& [l_serviceName, l_interfaceLsit] :
476 l_mapperObjectMap)
477 {
478 if (l_serviceName == vpd::constants::pimServiceName)
479 {
480 // The object is already under PIM. No need to process
481 // again. Retain the old value.
482 return;
483 }
484 }
485 }
486
487 // Implies value is not there in D-Bus. Populate it with default
488 // value "true".
Rekha Aparnad3662222025-10-14 10:33:17 -0500489 uint16_t l_errCode = 0;
Anupama B Rca738cf2025-09-19 06:40:54 -0500490 vpd::types::PropertyMap l_functionalProp;
491 l_functionalProp.emplace("Functional", true);
492 vpd::vpdSpecificUtility::insertOrMerge(
493 io_interfaces, vpd::constants::operationalStatusInf,
Rekha Aparnad3662222025-10-14 10:33:17 -0500494 move(l_functionalProp), l_errCode);
495
496 if (l_errCode)
497 {
498 m_logger->logMessage("Failed to insert value into map, error : " +
499 vpd::commonUtility::getErrCodeMsg(l_errCode));
500 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500501 }
502
503 // if chassis is power on. Functional property should be there on D-Bus.
504 // Don't process.
505 return;
Anupama B R445819f2025-09-18 11:00:25 -0500506}
507
508void PrimeInventory::processEnabledProperty(
Anupama B Rca738cf2025-09-19 06:40:54 -0500509 const std::string& i_inventoryObjPath,
510 vpd::types::InterfaceMap& io_interfaces) const noexcept
Anupama B R445819f2025-09-18 11:00:25 -0500511{
Anupama B Rca738cf2025-09-19 06:40:54 -0500512 if (!vpd::dbusUtility::isChassisPowerOn())
513 {
514 std::vector<std::string> l_enableInf{vpd::constants::enableInf};
515
516 auto l_mapperObjectMap =
517 vpd::dbusUtility::getObjectMap(i_inventoryObjPath, l_enableInf);
518
519 // If the object has been found. Check if it is under PIM.
520 if (l_mapperObjectMap.size() != 0)
521 {
522 for (const auto& [l_serviceName, l_interfaceLsit] :
523 l_mapperObjectMap)
524 {
525 if (l_serviceName == vpd::constants::pimServiceName)
526 {
527 // The object is already under PIM. No need to process
528 // again. Retain the old value.
529 return;
530 }
531 }
532 }
533
534 // Implies value is not there in D-Bus. Populate it with default
535 // value "true".
Rekha Aparnad3662222025-10-14 10:33:17 -0500536 uint16_t l_errCode = 0;
Anupama B Rca738cf2025-09-19 06:40:54 -0500537 vpd::types::PropertyMap l_enabledProp;
538 l_enabledProp.emplace("Enabled", true);
539 vpd::vpdSpecificUtility::insertOrMerge(
Rekha Aparnad3662222025-10-14 10:33:17 -0500540 io_interfaces, vpd::constants::enableInf, move(l_enabledProp),
541 l_errCode);
542
543 if (l_errCode)
544 {
545 m_logger->logMessage("Failed to insert value into map, error : " +
546 vpd::commonUtility::getErrCodeMsg(l_errCode));
547 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500548 }
549
550 // if chassis is power on. Enabled property should be there on D-Bus.
551 // Don't process.
552 return;
Anupama B R445819f2025-09-18 11:00:25 -0500553}