blob: 61d5ba569ffa9775a1f90ec7e46dcda4c21ce3de [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#include "backup_restore.hpp"
2
3#include "constants.hpp"
4#include "event_logger.hpp"
5#include "exceptions.hpp"
6#include "logger.hpp"
7#include "parser.hpp"
8#include "types.hpp"
9
10#include <utility/json_utility.hpp>
11#include <utility/vpd_specific_utility.hpp>
12
13namespace vpd
14{
15BackupAndRestoreStatus BackupAndRestore::m_backupAndRestoreStatus =
16 BackupAndRestoreStatus::NotStarted;
17
18BackupAndRestore::BackupAndRestore(const nlohmann::json& i_sysCfgJsonObj) :
19 m_sysCfgJsonObj(i_sysCfgJsonObj)
20{
21 std::string l_backupAndRestoreCfgFilePath =
22 i_sysCfgJsonObj.value("backupRestoreConfigPath", "");
RekhaAparna011ef21002025-02-18 23:47:36 -060023
24 m_backupAndRestoreCfgJsonObj =
25 jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath);
26
27 if (m_backupAndRestoreCfgJsonObj.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050028 {
RekhaAparna011ef21002025-02-18 23:47:36 -060029 throw JsonException("JSON parsing failed",
30 l_backupAndRestoreCfgFilePath);
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -050031 }
32}
33
34std::tuple<types::VPDMapVariant, types::VPDMapVariant>
35 BackupAndRestore::backupAndRestore()
36{
37 auto l_emptyVariantPair =
38 std::make_tuple(std::monostate{}, std::monostate{});
39
40 if (m_backupAndRestoreStatus >= BackupAndRestoreStatus::Invoked)
41 {
42 logging::logMessage("Backup and restore invoked already.");
43 return l_emptyVariantPair;
44 }
45
46 m_backupAndRestoreStatus = BackupAndRestoreStatus::Invoked;
47 try
48 {
49 if (m_backupAndRestoreCfgJsonObj.empty() ||
50 !m_backupAndRestoreCfgJsonObj.contains("source") ||
51 !m_backupAndRestoreCfgJsonObj.contains("destination") ||
52 !m_backupAndRestoreCfgJsonObj.contains("type") ||
53 !m_backupAndRestoreCfgJsonObj.contains("backupMap"))
54 {
55 logging::logMessage(
56 "Backup restore config JSON is missing necessary tag(s), can't initiate backup and restore.");
57 return l_emptyVariantPair;
58 }
59
60 std::string l_srcVpdPath;
61 types::VPDMapVariant l_srcVpdVariant;
62 if (l_srcVpdPath = m_backupAndRestoreCfgJsonObj["source"].value(
63 "hardwarePath", "");
64 !l_srcVpdPath.empty() && std::filesystem::exists(l_srcVpdPath))
65 {
66 std::shared_ptr<Parser> l_vpdParser =
67 std::make_shared<Parser>(l_srcVpdPath, m_sysCfgJsonObj);
68 l_srcVpdVariant = l_vpdParser->parse();
69 }
70 else if (l_srcVpdPath = m_backupAndRestoreCfgJsonObj["source"].value(
71 "inventoryPath", "");
72 l_srcVpdPath.empty())
73 {
74 logging::logMessage(
75 "Couldn't extract source path, can't initiate backup and restore.");
76 return l_emptyVariantPair;
77 }
78
79 std::string l_dstVpdPath;
80 types::VPDMapVariant l_dstVpdVariant;
81 if (l_dstVpdPath = m_backupAndRestoreCfgJsonObj["destination"].value(
82 "hardwarePath", "");
83 !l_dstVpdPath.empty() && std::filesystem::exists(l_dstVpdPath))
84 {
85 std::shared_ptr<Parser> l_vpdParser =
86 std::make_shared<Parser>(l_dstVpdPath, m_sysCfgJsonObj);
87 l_dstVpdVariant = l_vpdParser->parse();
88 }
89 else if (l_dstVpdPath = m_backupAndRestoreCfgJsonObj["destination"]
90 .value("inventoryPath", "");
91 l_dstVpdPath.empty())
92 {
93 logging::logMessage(
94 "Couldn't extract destination path, can't initiate backup and restore.");
95 return l_emptyVariantPair;
96 }
97
98 // Implement backup and restore for IPZ type VPD
99 auto l_backupAndRestoreType =
100 m_backupAndRestoreCfgJsonObj.value("type", "");
101 if (l_backupAndRestoreType.compare("IPZ") == constants::STR_CMP_SUCCESS)
102 {
103 types::IPZVpdMap l_srcVpdMap;
104 if (auto l_srcVpdPtr =
105 std::get_if<types::IPZVpdMap>(&l_srcVpdVariant))
106 {
107 l_srcVpdMap = *l_srcVpdPtr;
108 }
109 else if (!std::holds_alternative<std::monostate>(l_srcVpdVariant))
110 {
111 logging::logMessage("Source VPD is not of IPZ type.");
112 return l_emptyVariantPair;
113 }
114
115 types::IPZVpdMap l_dstVpdMap;
116 if (auto l_dstVpdPtr =
117 std::get_if<types::IPZVpdMap>(&l_dstVpdVariant))
118 {
119 l_dstVpdMap = *l_dstVpdPtr;
120 }
121 else if (!std::holds_alternative<std::monostate>(l_dstVpdVariant))
122 {
123 logging::logMessage("Destination VPD is not of IPZ type.");
124 return l_emptyVariantPair;
125 }
126
127 backupAndRestoreIpzVpd(l_srcVpdMap, l_dstVpdMap, l_srcVpdPath,
128 l_dstVpdPath);
129 m_backupAndRestoreStatus = BackupAndRestoreStatus::Completed;
130
131 return std::make_tuple(l_srcVpdMap, l_dstVpdMap);
132 }
133 // Note: add implementation here to support any other VPD type.
134 }
135 catch (const std::exception& ex)
136 {
137 logging::logMessage("Back up and restore failed with exception: " +
138 std::string(ex.what()));
139 }
140 return l_emptyVariantPair;
141}
142
143void BackupAndRestore::backupAndRestoreIpzVpd(
144 types::IPZVpdMap& io_srcVpdMap, types::IPZVpdMap& io_dstVpdMap,
145 const std::string& i_srcPath, const std::string& i_dstPath)
146{
147 if (!m_backupAndRestoreCfgJsonObj["backupMap"].is_array())
148 {
149 logging::logMessage(
150 "Invalid value found for tag backupMap, in backup and restore config JSON.");
151 return;
152 }
153
154 const std::string l_srcFruPath =
155 jsonUtility::getFruPathFromJson(m_sysCfgJsonObj, i_srcPath);
156 const std::string l_dstFruPath =
157 jsonUtility::getFruPathFromJson(m_sysCfgJsonObj, i_dstPath);
158 if (l_srcFruPath.empty() || l_dstFruPath.empty())
159 {
160 logging::logMessage(
161 "Couldn't find either source or destination FRU path.");
162 return;
163 }
164
Rekha Aparna017567a2025-08-13 02:07:06 -0500165 uint16_t l_errCode = 0;
166 const std::string l_srcInvPath = jsonUtility::getInventoryObjPathFromJson(
167 m_sysCfgJsonObj, i_srcPath, l_errCode);
168
169 if (l_srcInvPath.empty())
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500170 {
Rekha Aparna017567a2025-08-13 02:07:06 -0500171 if (l_errCode)
172 {
173 logging::logMessage(
174 "Couldn't find source inventory path. Error : " +
175 vpdSpecificUtility::getErrCodeMsg(l_errCode));
176 return;
177 }
178
179 logging::logMessage("Couldn't find source inventory path.");
180 return;
181 }
182
183 const std::string l_dstInvPath = jsonUtility::getInventoryObjPathFromJson(
184 m_sysCfgJsonObj, i_dstPath, l_errCode);
185
186 if (l_dstInvPath.empty())
187 {
188 if (l_errCode)
189 {
190 logging::logMessage(
191 "Couldn't find destination inventory path. Error : " +
192 vpdSpecificUtility::getErrCodeMsg(l_errCode));
193 return;
194 }
195
196 logging::logMessage("Couldn't find destination inventory path.");
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500197 return;
198 }
199
200 const std::string l_srcServiceName =
201 jsonUtility::getServiceName(m_sysCfgJsonObj, l_srcInvPath);
202 const std::string l_dstServiceName =
203 jsonUtility::getServiceName(m_sysCfgJsonObj, l_dstInvPath);
204 if (l_srcServiceName.empty() || l_dstServiceName.empty())
205 {
206 logging::logMessage(
207 "Couldn't find either source or destination DBus service name.");
208 return;
209 }
210
211 for (const auto& l_aRecordKwInfo :
212 m_backupAndRestoreCfgJsonObj["backupMap"])
213 {
214 const std::string& l_srcRecordName =
215 l_aRecordKwInfo.value("sourceRecord", "");
216 const std::string& l_srcKeywordName =
217 l_aRecordKwInfo.value("sourceKeyword", "");
218 const std::string& l_dstRecordName =
219 l_aRecordKwInfo.value("destinationRecord", "");
220 const std::string& l_dstKeywordName =
221 l_aRecordKwInfo.value("destinationKeyword", "");
222
223 if (l_srcRecordName.empty() || l_dstRecordName.empty() ||
224 l_srcKeywordName.empty() || l_dstKeywordName.empty())
225 {
226 logging::logMessage(
227 "Record or keyword not found in the backup and restore config JSON.");
228 continue;
229 }
230
231 if (!io_srcVpdMap.empty() &&
232 io_srcVpdMap.find(l_srcRecordName) == io_srcVpdMap.end())
233 {
234 logging::logMessage(
235 "Record: " + l_srcRecordName +
236 ", is not found in the source path: " + i_srcPath);
237 continue;
238 }
239
240 if (!io_dstVpdMap.empty() &&
241 io_dstVpdMap.find(l_dstRecordName) == io_dstVpdMap.end())
242 {
243 logging::logMessage(
244 "Record: " + l_dstRecordName +
245 ", is not found in the destination path: " + i_dstPath);
246 continue;
247 }
248
249 types::BinaryVector l_defaultBinaryValue;
250 if (l_aRecordKwInfo.contains("defaultValue") &&
251 l_aRecordKwInfo["defaultValue"].is_array())
252 {
253 l_defaultBinaryValue =
254 l_aRecordKwInfo["defaultValue"].get<types::BinaryVector>();
255 }
256 else
257 {
258 logging::logMessage(
259 "Couldn't read default value for record name: " +
260 l_srcRecordName + ", keyword name: " + l_srcKeywordName +
261 " from backup and restore config JSON file.");
262 continue;
263 }
264
265 bool l_isPelRequired = l_aRecordKwInfo.value("isPelRequired", false);
266
267 types::BinaryVector l_srcBinaryValue;
268 std::string l_srcStrValue;
269 if (!io_srcVpdMap.empty())
270 {
Souvik Roya55fcca2025-02-19 01:33:58 -0600271 l_srcStrValue = vpdSpecificUtility::getKwVal(
272 io_srcVpdMap.at(l_srcRecordName), l_srcKeywordName);
273
274 if (l_srcStrValue.empty())
275 {
276 std::runtime_error(
277 std::string("Failed to get value for keyword [") +
278 l_srcKeywordName + std::string("]"));
279 }
280
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500281 l_srcBinaryValue =
282 types::BinaryVector(l_srcStrValue.begin(), l_srcStrValue.end());
283 }
284 else
285 {
286 // Read keyword value from DBus
287 const auto l_value = dbusUtility::readDbusProperty(
288 l_srcServiceName, l_srcInvPath,
289 constants::ipzVpdInf + l_srcRecordName, l_srcKeywordName);
290 if (const auto l_binaryValue =
291 std::get_if<types::BinaryVector>(&l_value))
292 {
293 l_srcBinaryValue = *l_binaryValue;
294 l_srcStrValue = std::string(l_srcBinaryValue.begin(),
295 l_srcBinaryValue.end());
296 }
297 }
298
299 types::BinaryVector l_dstBinaryValue;
300 std::string l_dstStrValue;
301 if (!io_dstVpdMap.empty())
302 {
Souvik Roya55fcca2025-02-19 01:33:58 -0600303 l_dstStrValue = vpdSpecificUtility::getKwVal(
304 io_dstVpdMap.at(l_dstRecordName), l_dstKeywordName);
305
306 if (l_dstStrValue.empty())
307 {
308 std::runtime_error(
309 std::string("Failed to get value for keyword [") +
310 l_dstKeywordName + std::string("]"));
311 }
312
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500313 l_dstBinaryValue =
314 types::BinaryVector(l_dstStrValue.begin(), l_dstStrValue.end());
315 }
316 else
317 {
318 // Read keyword value from DBus
319 const auto l_value = dbusUtility::readDbusProperty(
320 l_dstServiceName, l_dstInvPath,
321 constants::ipzVpdInf + l_dstRecordName, l_dstKeywordName);
322 if (const auto l_binaryValue =
323 std::get_if<types::BinaryVector>(&l_value))
324 {
325 l_dstBinaryValue = *l_binaryValue;
326 l_dstStrValue = std::string(l_dstBinaryValue.begin(),
327 l_dstBinaryValue.end());
328 }
329 }
330
331 if (l_srcBinaryValue != l_dstBinaryValue)
332 {
333 // ToDo: Handle if there is no valid default value in the backup and
334 // restore config JSON.
335 if (l_dstBinaryValue == l_defaultBinaryValue)
336 {
337 // Update keyword's value on hardware
338 auto l_vpdParser =
339 std::make_shared<Parser>(l_dstFruPath, m_sysCfgJsonObj);
340
341 auto l_bytesUpdatedOnHardware = l_vpdParser->updateVpdKeyword(
342 types::IpzData(l_dstRecordName, l_dstKeywordName,
343 l_srcBinaryValue));
344
345 /* To keep the data in sync between hardware and parsed map
346 updating the io_dstVpdMap. This should only be done if write
347 on hardware returns success.*/
348 if (!io_dstVpdMap.empty() && l_bytesUpdatedOnHardware > 0)
349 {
350 io_dstVpdMap[l_dstRecordName][l_dstKeywordName] =
351 l_srcStrValue;
352 }
353 continue;
354 }
355
356 if (l_srcBinaryValue == l_defaultBinaryValue)
357 {
358 // Update keyword's value on hardware
359 auto l_vpdParser =
360 std::make_shared<Parser>(l_srcFruPath, m_sysCfgJsonObj);
361
362 auto l_bytesUpdatedOnHardware = l_vpdParser->updateVpdKeyword(
363 types::IpzData(l_srcRecordName, l_srcKeywordName,
364 l_dstBinaryValue));
365
366 /* To keep the data in sync between hardware and parsed map
367 updating the io_srcVpdMap. This should only be done if write
368 on hardware returns success.*/
369 if (!io_srcVpdMap.empty() && l_bytesUpdatedOnHardware > 0)
370 {
371 io_srcVpdMap[l_srcRecordName][l_srcKeywordName] =
372 l_dstStrValue;
373 }
374 }
375 else
376 {
377 /**
378 * Update io_srcVpdMap to publish the same data on DBus, which
379 * is already present on the DBus. Because after calling
380 * backupAndRestore API the map value will get published to DBus
381 * in the worker flow.
382 */
383 if (!io_srcVpdMap.empty() && io_dstVpdMap.empty())
384 {
385 io_srcVpdMap[l_srcRecordName][l_srcKeywordName] =
386 l_dstStrValue;
387 }
388
389 std::string l_errorMsg(
390 "Mismatch found between source and destination VPD for record : " +
391 l_srcRecordName + " and keyword : " + l_srcKeywordName +
Anupama B R6f142832025-04-11 04:17:49 -0500392 " . Value read from source : " +
393 commonUtility::convertByteVectorToHex(l_srcBinaryValue) +
394 " . Value read from destination : " +
395 commonUtility::convertByteVectorToHex(l_dstBinaryValue));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500396
397 EventLogger::createSyncPel(
398 types::ErrorType::VpdMismatch, types::SeverityType::Warning,
399 __FILE__, __FUNCTION__, 0, l_errorMsg, std::nullopt,
400 std::nullopt, std::nullopt, std::nullopt);
401 }
402 }
403 else if (l_srcBinaryValue == l_defaultBinaryValue &&
404 l_dstBinaryValue == l_defaultBinaryValue && l_isPelRequired)
405 {
406 std::string l_errorMsg(
407 "Default value found on both source and destination VPD, for record: " +
408 l_srcRecordName + " and keyword: " + l_srcKeywordName);
409
410 EventLogger::createSyncPel(
411 types::ErrorType::DefaultValue, types::SeverityType::Error,
412 __FILE__, __FUNCTION__, 0, l_errorMsg, std::nullopt,
413 std::nullopt, std::nullopt, std::nullopt);
414 }
415 }
416}
417
418void BackupAndRestore::setBackupAndRestoreStatus(
419 const BackupAndRestoreStatus& i_status)
420{
421 m_backupAndRestoreStatus = i_status;
422}
Anupama B R8dedd1e2025-03-24 07:43:47 -0500423
424int BackupAndRestore::updateKeywordOnPrimaryOrBackupPath(
425 const std::string& i_fruPath,
Anupama B R7b293cd2025-03-28 05:35:01 -0500426 const types::WriteVpdParams& i_paramsToWriteData) const noexcept
Anupama B R8dedd1e2025-03-24 07:43:47 -0500427{
428 if (i_fruPath.empty())
429 {
430 logging::logMessage("Given FRU path is empty.");
431 return constants::FAILURE;
432 }
433
Anupama B Rd966f272025-07-21 02:40:16 -0500434 bool l_inputPathIsSourcePath = false;
435 bool l_inputPathIsDestinationPath = false;
Anupama B R7b293cd2025-03-28 05:35:01 -0500436
Anupama B R8dedd1e2025-03-24 07:43:47 -0500437 if (m_backupAndRestoreCfgJsonObj.contains("source") &&
438 m_backupAndRestoreCfgJsonObj["source"].value("hardwarePath", "") ==
439 i_fruPath &&
440 m_backupAndRestoreCfgJsonObj.contains("destination") &&
441 !m_backupAndRestoreCfgJsonObj["destination"]
442 .value("hardwarePath", "")
443 .empty())
444 {
Anupama B Rd966f272025-07-21 02:40:16 -0500445 l_inputPathIsSourcePath = true;
Anupama B R8dedd1e2025-03-24 07:43:47 -0500446 }
447 else if (m_backupAndRestoreCfgJsonObj.contains("destination") &&
448 m_backupAndRestoreCfgJsonObj["destination"].value(
449 "hardwarePath", "") == i_fruPath &&
450 m_backupAndRestoreCfgJsonObj.contains("source") &&
451 !m_backupAndRestoreCfgJsonObj["source"]
452 .value("hardwarePath", "")
453 .empty())
454 {
Anupama B Rd966f272025-07-21 02:40:16 -0500455 l_inputPathIsDestinationPath = true;
Anupama B R7b293cd2025-03-28 05:35:01 -0500456 }
457 else
458 {
459 // Input path is neither source or destination path of the
Anupama B Rd966f272025-07-21 02:40:16 -0500460 // backup&restore JSON or source and destination paths are not hardware
461 // paths in the config JSON.
Anupama B R7b293cd2025-03-28 05:35:01 -0500462 return constants::SUCCESS;
Anupama B R8dedd1e2025-03-24 07:43:47 -0500463 }
464
Anupama B Rd966f272025-07-21 02:40:16 -0500465 if (m_backupAndRestoreCfgJsonObj["backupMap"].is_array())
Anupama B R7b293cd2025-03-28 05:35:01 -0500466 {
467 std::string l_inpRecordName;
468 std::string l_inpKeywordName;
Anupama B Rd966f272025-07-21 02:40:16 -0500469 types::BinaryVector l_inpKeywordValue;
Anupama B R7b293cd2025-03-28 05:35:01 -0500470
471 if (const types::IpzData* l_ipzData =
472 std::get_if<types::IpzData>(&i_paramsToWriteData))
473 {
474 l_inpRecordName = std::get<0>(*l_ipzData);
475 l_inpKeywordName = std::get<1>(*l_ipzData);
Anupama B Rd966f272025-07-21 02:40:16 -0500476 l_inpKeywordValue = std::get<2>(*l_ipzData);
Anupama B R7b293cd2025-03-28 05:35:01 -0500477
478 if (l_inpRecordName.empty() || l_inpKeywordName.empty() ||
Anupama B Rd966f272025-07-21 02:40:16 -0500479 l_inpKeywordValue.empty())
Anupama B R7b293cd2025-03-28 05:35:01 -0500480 {
481 logging::logMessage("Invalid input received");
482 return constants::FAILURE;
483 }
484 }
485 else
486 {
487 // only IPZ type VPD is supported now.
488 return constants::SUCCESS;
489 }
490
491 for (const auto& l_aRecordKwInfo :
492 m_backupAndRestoreCfgJsonObj["backupMap"])
493 {
494 if (l_aRecordKwInfo.value("sourceRecord", "").empty() ||
495 l_aRecordKwInfo.value("sourceKeyword", "").empty() ||
496 l_aRecordKwInfo.value("destinationRecord", "").empty() ||
497 l_aRecordKwInfo.value("destinationKeyword", "").empty())
498 {
499 // invalid backup map found
500 logging::logMessage(
501 "Invalid backup map found, one or more field(s) found empty or not present in the config JSON: sourceRecord: " +
502 l_aRecordKwInfo.value("sourceRecord", "") +
503 ", sourceKeyword: " +
504 l_aRecordKwInfo.value("sourceKeyword", "") +
505 ", destinationRecord: " +
506 l_aRecordKwInfo.value("destinationRecord", "") +
507 ", destinationKeyword: " +
508 l_aRecordKwInfo.value("destinationKeyword", ""));
509 continue;
510 }
511
Anupama B Rd966f272025-07-21 02:40:16 -0500512 if (l_inputPathIsSourcePath &&
Anupama B R7b293cd2025-03-28 05:35:01 -0500513 (l_aRecordKwInfo["sourceRecord"] == l_inpRecordName) &&
514 (l_aRecordKwInfo["sourceKeyword"] == l_inpKeywordName))
515 {
516 std::string l_fruPath(
517 m_backupAndRestoreCfgJsonObj["destination"]
518 ["hardwarePath"]);
519 Parser l_parserObj(l_fruPath, m_sysCfgJsonObj);
520
521 return l_parserObj.updateVpdKeyword(std::make_tuple(
522 l_aRecordKwInfo["destinationRecord"],
Anupama B Rd966f272025-07-21 02:40:16 -0500523 l_aRecordKwInfo["destinationKeyword"], l_inpKeywordValue));
Anupama B R7b293cd2025-03-28 05:35:01 -0500524 }
Anupama B Rd966f272025-07-21 02:40:16 -0500525 else if (l_inputPathIsDestinationPath &&
Anupama B R7b293cd2025-03-28 05:35:01 -0500526 (l_aRecordKwInfo["destinationRecord"] ==
527 l_inpRecordName) &&
528 (l_aRecordKwInfo["destinationKeyword"] ==
529 l_inpKeywordName))
530 {
531 std::string l_fruPath(
532 m_backupAndRestoreCfgJsonObj["source"]["hardwarePath"]);
533 Parser l_parserObj(l_fruPath, m_sysCfgJsonObj);
534
535 return l_parserObj.updateVpdKeyword(std::make_tuple(
536 l_aRecordKwInfo["sourceRecord"],
Anupama B Rd966f272025-07-21 02:40:16 -0500537 l_aRecordKwInfo["sourceKeyword"], l_inpKeywordValue));
Anupama B R7b293cd2025-03-28 05:35:01 -0500538 }
539 }
540 }
541
542 // Received property is not part of backup & restore JSON.
Anupama B R8dedd1e2025-03-24 07:43:47 -0500543 return constants::SUCCESS;
544}
545
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500546} // namespace vpd