blob: 409087a6f30a0b38e36bbc7c139b3bfedd251ef6 [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>(),
292 i_parsedVpdMap);
293 l_propertyMap.emplace(l_property, l_value);
294
295 auto l_locCodeProperty = l_propertyMap;
296 vpd::vpdSpecificUtility::insertOrMerge(
297 io_interfaceMap,
298 std::string(vpd::constants::xyzLocationCodeInf),
Rekha Aparnad3662222025-10-14 10:33:17 -0500299 move(l_locCodeProperty), l_errCode);
300
301 if (l_errCode)
302 {
303 m_logger->logMessage(
304 "Failed to insert value into map, error : " +
305 vpd::commonUtility::getErrCodeMsg(l_errCode));
306 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500307 }
308 else
309 {
310 l_propertyMap.emplace(
311 l_property, l_propValuePair.value().get<std::string>());
312 }
313 }
314 else if (l_propValuePair.value().is_array())
315 {
316 try
317 {
318 l_propertyMap.emplace(l_property,
319 l_propValuePair.value()
320 .get<vpd::types::BinaryVector>());
321 }
322 catch (const nlohmann::detail::type_error& e)
323 {
324 std::cerr << "Type exception: " << e.what() << "\n";
325 }
326 }
327 else if (l_propValuePair.value().is_number())
328 {
329 // For now assume the value is a size_t. In the future it would
330 // be nice to come up with a way to get the type from the JSON.
331 l_propertyMap.emplace(l_property,
332 l_propValuePair.value().get<size_t>());
333 }
334 else if (l_propValuePair.value().is_object())
335 {
336 const std::string& l_record =
337 l_propValuePair.value().value("recordName", "");
338 const std::string& l_keyword =
339 l_propValuePair.value().value("keywordName", "");
340 const std::string& l_encoding =
341 l_propValuePair.value().value("encoding", "");
342
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500343 uint16_t l_errCode = 0;
344
Anupama B Rca738cf2025-09-19 06:40:54 -0500345 if (auto l_ipzVpdMap =
346 std::get_if<vpd::types::IPZVpdMap>(&i_parsedVpdMap))
347 {
348 if (!l_record.empty() && !l_keyword.empty() &&
349 (*l_ipzVpdMap).count(l_record) &&
350 (*l_ipzVpdMap).at(l_record).count(l_keyword))
351 {
352 auto l_encoded = vpd::vpdSpecificUtility::encodeKeyword(
353 ((*l_ipzVpdMap).at(l_record).at(l_keyword)),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500354 l_encoding, l_errCode);
355
356 if (l_errCode)
357 {
358 m_logger->logMessage(
359 "Failed to get encoded keyword value for : " +
360 l_keyword + ", error : " +
361 vpd::commonUtility::getErrCodeMsg(l_errCode));
362 }
363
Anupama B Rca738cf2025-09-19 06:40:54 -0500364 l_propertyMap.emplace(l_property, l_encoded);
365 }
366 }
367 else if (auto l_kwdVpdMap =
368 std::get_if<vpd::types::KeywordVpdMap>(
369 &i_parsedVpdMap))
370 {
371 if (!l_keyword.empty() && (*l_kwdVpdMap).count(l_keyword))
372 {
373 if (auto l_kwValue =
374 std::get_if<vpd::types::BinaryVector>(
375 &(*l_kwdVpdMap).at(l_keyword)))
376 {
377 auto l_encodedValue =
378 vpd::vpdSpecificUtility::encodeKeyword(
379 std::string((*l_kwValue).begin(),
380 (*l_kwValue).end()),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500381 l_encoding, l_errCode);
382
383 if (l_errCode)
384 {
385 m_logger->logMessage(
386 "Failed to get encoded keyword value for : " +
387 l_keyword + ", error : " +
388 vpd::commonUtility::getErrCodeMsg(
389 l_errCode));
390 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500391
392 l_propertyMap.emplace(l_property, l_encodedValue);
393 }
394 else if (auto l_kwValue = std::get_if<std::string>(
395 &(*l_kwdVpdMap).at(l_keyword)))
396 {
397 auto l_encodedValue =
398 vpd::vpdSpecificUtility::encodeKeyword(
399 std::string((*l_kwValue).begin(),
400 (*l_kwValue).end()),
Rekha Aparna17ddfb52025-10-09 20:45:53 -0500401 l_encoding, l_errCode);
402
403 if (l_errCode)
404 {
405 m_logger->logMessage(
406 "Failed to get encoded keyword value for : " +
407 l_keyword + ", error : " +
408 vpd::commonUtility::getErrCodeMsg(
409 l_errCode));
410 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500411
412 l_propertyMap.emplace(l_property, l_encodedValue);
413 }
414 else if (auto l_uintValue = std::get_if<size_t>(
415 &(*l_kwdVpdMap).at(l_keyword)))
416 {
417 l_propertyMap.emplace(l_property, *l_uintValue);
418 }
419 else
420 {
421 m_logger->logMessage(
422 "Unknown keyword found, Keywrod = " +
423 l_keyword);
424 }
425 }
426 }
427 }
428 }
Rekha Aparnad3662222025-10-14 10:33:17 -0500429 l_errCode = 0;
Anupama B Rca738cf2025-09-19 06:40:54 -0500430 vpd::vpdSpecificUtility::insertOrMerge(io_interfaceMap, l_interface,
Rekha Aparnad3662222025-10-14 10:33:17 -0500431 move(l_propertyMap), l_errCode);
432
433 if (l_errCode)
434 {
435 m_logger->logMessage("Failed to insert value into map, error : " +
436 vpd::commonUtility::getErrCodeMsg(l_errCode));
437 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500438 }
Anupama B R445819f2025-09-18 11:00:25 -0500439}
440
441void PrimeInventory::processFunctionalProperty(
Anupama B Rca738cf2025-09-19 06:40:54 -0500442 const std::string& i_inventoryObjPath,
443 vpd::types::InterfaceMap& io_interfaces) const noexcept
Anupama B R445819f2025-09-18 11:00:25 -0500444{
Anupama B Rca738cf2025-09-19 06:40:54 -0500445 if (!vpd::dbusUtility::isChassisPowerOn())
446 {
447 std::vector<std::string> l_operationalStatusInf{
448 vpd::constants::operationalStatusInf};
449
450 auto l_mapperObjectMap = vpd::dbusUtility::getObjectMap(
451 i_inventoryObjPath, l_operationalStatusInf);
452
453 // If the object has been found. Check if it is under PIM.
454 if (l_mapperObjectMap.size() != 0)
455 {
456 for (const auto& [l_serviceName, l_interfaceLsit] :
457 l_mapperObjectMap)
458 {
459 if (l_serviceName == vpd::constants::pimServiceName)
460 {
461 // The object is already under PIM. No need to process
462 // again. Retain the old value.
463 return;
464 }
465 }
466 }
467
468 // Implies value is not there in D-Bus. Populate it with default
469 // value "true".
Rekha Aparnad3662222025-10-14 10:33:17 -0500470 uint16_t l_errCode = 0;
Anupama B Rca738cf2025-09-19 06:40:54 -0500471 vpd::types::PropertyMap l_functionalProp;
472 l_functionalProp.emplace("Functional", true);
473 vpd::vpdSpecificUtility::insertOrMerge(
474 io_interfaces, vpd::constants::operationalStatusInf,
Rekha Aparnad3662222025-10-14 10:33:17 -0500475 move(l_functionalProp), l_errCode);
476
477 if (l_errCode)
478 {
479 m_logger->logMessage("Failed to insert value into map, error : " +
480 vpd::commonUtility::getErrCodeMsg(l_errCode));
481 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500482 }
483
484 // if chassis is power on. Functional property should be there on D-Bus.
485 // Don't process.
486 return;
Anupama B R445819f2025-09-18 11:00:25 -0500487}
488
489void PrimeInventory::processEnabledProperty(
Anupama B Rca738cf2025-09-19 06:40:54 -0500490 const std::string& i_inventoryObjPath,
491 vpd::types::InterfaceMap& io_interfaces) const noexcept
Anupama B R445819f2025-09-18 11:00:25 -0500492{
Anupama B Rca738cf2025-09-19 06:40:54 -0500493 if (!vpd::dbusUtility::isChassisPowerOn())
494 {
495 std::vector<std::string> l_enableInf{vpd::constants::enableInf};
496
497 auto l_mapperObjectMap =
498 vpd::dbusUtility::getObjectMap(i_inventoryObjPath, l_enableInf);
499
500 // If the object has been found. Check if it is under PIM.
501 if (l_mapperObjectMap.size() != 0)
502 {
503 for (const auto& [l_serviceName, l_interfaceLsit] :
504 l_mapperObjectMap)
505 {
506 if (l_serviceName == vpd::constants::pimServiceName)
507 {
508 // The object is already under PIM. No need to process
509 // again. Retain the old value.
510 return;
511 }
512 }
513 }
514
515 // Implies value is not there in D-Bus. Populate it with default
516 // value "true".
Rekha Aparnad3662222025-10-14 10:33:17 -0500517 uint16_t l_errCode = 0;
Anupama B Rca738cf2025-09-19 06:40:54 -0500518 vpd::types::PropertyMap l_enabledProp;
519 l_enabledProp.emplace("Enabled", true);
520 vpd::vpdSpecificUtility::insertOrMerge(
Rekha Aparnad3662222025-10-14 10:33:17 -0500521 io_interfaces, vpd::constants::enableInf, move(l_enabledProp),
522 l_errCode);
523
524 if (l_errCode)
525 {
526 m_logger->logMessage("Failed to insert value into map, error : " +
527 vpd::commonUtility::getErrCodeMsg(l_errCode));
528 }
Anupama B Rca738cf2025-09-19 06:40:54 -0500529 }
530
531 // if chassis is power on. Enabled property should be there on D-Bus.
532 // Don't process.
533 return;
Anupama B R445819f2025-09-18 11:00:25 -0500534}