blob: 6c31eac06c88896a85f34c6ffc504e2c6c25840d [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
165 const std::string l_srcInvPath =
166 jsonUtility::getInventoryObjPathFromJson(m_sysCfgJsonObj, i_srcPath);
167 const std::string l_dstInvPath =
168 jsonUtility::getInventoryObjPathFromJson(m_sysCfgJsonObj, i_dstPath);
169 if (l_srcInvPath.empty() || l_dstInvPath.empty())
170 {
171 logging::logMessage(
172 "Couldn't find either source or destination inventory path.");
173 return;
174 }
175
176 const std::string l_srcServiceName =
177 jsonUtility::getServiceName(m_sysCfgJsonObj, l_srcInvPath);
178 const std::string l_dstServiceName =
179 jsonUtility::getServiceName(m_sysCfgJsonObj, l_dstInvPath);
180 if (l_srcServiceName.empty() || l_dstServiceName.empty())
181 {
182 logging::logMessage(
183 "Couldn't find either source or destination DBus service name.");
184 return;
185 }
186
187 for (const auto& l_aRecordKwInfo :
188 m_backupAndRestoreCfgJsonObj["backupMap"])
189 {
190 const std::string& l_srcRecordName =
191 l_aRecordKwInfo.value("sourceRecord", "");
192 const std::string& l_srcKeywordName =
193 l_aRecordKwInfo.value("sourceKeyword", "");
194 const std::string& l_dstRecordName =
195 l_aRecordKwInfo.value("destinationRecord", "");
196 const std::string& l_dstKeywordName =
197 l_aRecordKwInfo.value("destinationKeyword", "");
198
199 if (l_srcRecordName.empty() || l_dstRecordName.empty() ||
200 l_srcKeywordName.empty() || l_dstKeywordName.empty())
201 {
202 logging::logMessage(
203 "Record or keyword not found in the backup and restore config JSON.");
204 continue;
205 }
206
207 if (!io_srcVpdMap.empty() &&
208 io_srcVpdMap.find(l_srcRecordName) == io_srcVpdMap.end())
209 {
210 logging::logMessage(
211 "Record: " + l_srcRecordName +
212 ", is not found in the source path: " + i_srcPath);
213 continue;
214 }
215
216 if (!io_dstVpdMap.empty() &&
217 io_dstVpdMap.find(l_dstRecordName) == io_dstVpdMap.end())
218 {
219 logging::logMessage(
220 "Record: " + l_dstRecordName +
221 ", is not found in the destination path: " + i_dstPath);
222 continue;
223 }
224
225 types::BinaryVector l_defaultBinaryValue;
226 if (l_aRecordKwInfo.contains("defaultValue") &&
227 l_aRecordKwInfo["defaultValue"].is_array())
228 {
229 l_defaultBinaryValue =
230 l_aRecordKwInfo["defaultValue"].get<types::BinaryVector>();
231 }
232 else
233 {
234 logging::logMessage(
235 "Couldn't read default value for record name: " +
236 l_srcRecordName + ", keyword name: " + l_srcKeywordName +
237 " from backup and restore config JSON file.");
238 continue;
239 }
240
241 bool l_isPelRequired = l_aRecordKwInfo.value("isPelRequired", false);
242
243 types::BinaryVector l_srcBinaryValue;
244 std::string l_srcStrValue;
245 if (!io_srcVpdMap.empty())
246 {
Souvik Roya55fcca2025-02-19 01:33:58 -0600247 l_srcStrValue = vpdSpecificUtility::getKwVal(
248 io_srcVpdMap.at(l_srcRecordName), l_srcKeywordName);
249
250 if (l_srcStrValue.empty())
251 {
252 std::runtime_error(
253 std::string("Failed to get value for keyword [") +
254 l_srcKeywordName + std::string("]"));
255 }
256
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500257 l_srcBinaryValue =
258 types::BinaryVector(l_srcStrValue.begin(), l_srcStrValue.end());
259 }
260 else
261 {
262 // Read keyword value from DBus
263 const auto l_value = dbusUtility::readDbusProperty(
264 l_srcServiceName, l_srcInvPath,
265 constants::ipzVpdInf + l_srcRecordName, l_srcKeywordName);
266 if (const auto l_binaryValue =
267 std::get_if<types::BinaryVector>(&l_value))
268 {
269 l_srcBinaryValue = *l_binaryValue;
270 l_srcStrValue = std::string(l_srcBinaryValue.begin(),
271 l_srcBinaryValue.end());
272 }
273 }
274
275 types::BinaryVector l_dstBinaryValue;
276 std::string l_dstStrValue;
277 if (!io_dstVpdMap.empty())
278 {
Souvik Roya55fcca2025-02-19 01:33:58 -0600279 l_dstStrValue = vpdSpecificUtility::getKwVal(
280 io_dstVpdMap.at(l_dstRecordName), l_dstKeywordName);
281
282 if (l_dstStrValue.empty())
283 {
284 std::runtime_error(
285 std::string("Failed to get value for keyword [") +
286 l_dstKeywordName + std::string("]"));
287 }
288
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500289 l_dstBinaryValue =
290 types::BinaryVector(l_dstStrValue.begin(), l_dstStrValue.end());
291 }
292 else
293 {
294 // Read keyword value from DBus
295 const auto l_value = dbusUtility::readDbusProperty(
296 l_dstServiceName, l_dstInvPath,
297 constants::ipzVpdInf + l_dstRecordName, l_dstKeywordName);
298 if (const auto l_binaryValue =
299 std::get_if<types::BinaryVector>(&l_value))
300 {
301 l_dstBinaryValue = *l_binaryValue;
302 l_dstStrValue = std::string(l_dstBinaryValue.begin(),
303 l_dstBinaryValue.end());
304 }
305 }
306
307 if (l_srcBinaryValue != l_dstBinaryValue)
308 {
309 // ToDo: Handle if there is no valid default value in the backup and
310 // restore config JSON.
311 if (l_dstBinaryValue == l_defaultBinaryValue)
312 {
313 // Update keyword's value on hardware
314 auto l_vpdParser =
315 std::make_shared<Parser>(l_dstFruPath, m_sysCfgJsonObj);
316
317 auto l_bytesUpdatedOnHardware = l_vpdParser->updateVpdKeyword(
318 types::IpzData(l_dstRecordName, l_dstKeywordName,
319 l_srcBinaryValue));
320
321 /* To keep the data in sync between hardware and parsed map
322 updating the io_dstVpdMap. This should only be done if write
323 on hardware returns success.*/
324 if (!io_dstVpdMap.empty() && l_bytesUpdatedOnHardware > 0)
325 {
326 io_dstVpdMap[l_dstRecordName][l_dstKeywordName] =
327 l_srcStrValue;
328 }
329 continue;
330 }
331
332 if (l_srcBinaryValue == l_defaultBinaryValue)
333 {
334 // Update keyword's value on hardware
335 auto l_vpdParser =
336 std::make_shared<Parser>(l_srcFruPath, m_sysCfgJsonObj);
337
338 auto l_bytesUpdatedOnHardware = l_vpdParser->updateVpdKeyword(
339 types::IpzData(l_srcRecordName, l_srcKeywordName,
340 l_dstBinaryValue));
341
342 /* To keep the data in sync between hardware and parsed map
343 updating the io_srcVpdMap. This should only be done if write
344 on hardware returns success.*/
345 if (!io_srcVpdMap.empty() && l_bytesUpdatedOnHardware > 0)
346 {
347 io_srcVpdMap[l_srcRecordName][l_srcKeywordName] =
348 l_dstStrValue;
349 }
350 }
351 else
352 {
353 /**
354 * Update io_srcVpdMap to publish the same data on DBus, which
355 * is already present on the DBus. Because after calling
356 * backupAndRestore API the map value will get published to DBus
357 * in the worker flow.
358 */
359 if (!io_srcVpdMap.empty() && io_dstVpdMap.empty())
360 {
361 io_srcVpdMap[l_srcRecordName][l_srcKeywordName] =
362 l_dstStrValue;
363 }
364
365 std::string l_errorMsg(
366 "Mismatch found between source and destination VPD for record : " +
367 l_srcRecordName + " and keyword : " + l_srcKeywordName +
Anupama B R6f142832025-04-11 04:17:49 -0500368 " . Value read from source : " +
369 commonUtility::convertByteVectorToHex(l_srcBinaryValue) +
370 " . Value read from destination : " +
371 commonUtility::convertByteVectorToHex(l_dstBinaryValue));
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500372
373 EventLogger::createSyncPel(
374 types::ErrorType::VpdMismatch, types::SeverityType::Warning,
375 __FILE__, __FUNCTION__, 0, l_errorMsg, std::nullopt,
376 std::nullopt, std::nullopt, std::nullopt);
377 }
378 }
379 else if (l_srcBinaryValue == l_defaultBinaryValue &&
380 l_dstBinaryValue == l_defaultBinaryValue && l_isPelRequired)
381 {
382 std::string l_errorMsg(
383 "Default value found on both source and destination VPD, for record: " +
384 l_srcRecordName + " and keyword: " + l_srcKeywordName);
385
386 EventLogger::createSyncPel(
387 types::ErrorType::DefaultValue, types::SeverityType::Error,
388 __FILE__, __FUNCTION__, 0, l_errorMsg, std::nullopt,
389 std::nullopt, std::nullopt, std::nullopt);
390 }
391 }
392}
393
394void BackupAndRestore::setBackupAndRestoreStatus(
395 const BackupAndRestoreStatus& i_status)
396{
397 m_backupAndRestoreStatus = i_status;
398}
Anupama B R8dedd1e2025-03-24 07:43:47 -0500399
400int BackupAndRestore::updateKeywordOnPrimaryOrBackupPath(
401 const std::string& i_fruPath,
Anupama B R7b293cd2025-03-28 05:35:01 -0500402 const types::WriteVpdParams& i_paramsToWriteData) const noexcept
Anupama B R8dedd1e2025-03-24 07:43:47 -0500403{
404 if (i_fruPath.empty())
405 {
406 logging::logMessage("Given FRU path is empty.");
407 return constants::FAILURE;
408 }
409
Anupama B Rd966f272025-07-21 02:40:16 -0500410 bool l_inputPathIsSourcePath = false;
411 bool l_inputPathIsDestinationPath = false;
Anupama B R7b293cd2025-03-28 05:35:01 -0500412
Anupama B R8dedd1e2025-03-24 07:43:47 -0500413 if (m_backupAndRestoreCfgJsonObj.contains("source") &&
414 m_backupAndRestoreCfgJsonObj["source"].value("hardwarePath", "") ==
415 i_fruPath &&
416 m_backupAndRestoreCfgJsonObj.contains("destination") &&
417 !m_backupAndRestoreCfgJsonObj["destination"]
418 .value("hardwarePath", "")
419 .empty())
420 {
Anupama B Rd966f272025-07-21 02:40:16 -0500421 l_inputPathIsSourcePath = true;
Anupama B R8dedd1e2025-03-24 07:43:47 -0500422 }
423 else if (m_backupAndRestoreCfgJsonObj.contains("destination") &&
424 m_backupAndRestoreCfgJsonObj["destination"].value(
425 "hardwarePath", "") == i_fruPath &&
426 m_backupAndRestoreCfgJsonObj.contains("source") &&
427 !m_backupAndRestoreCfgJsonObj["source"]
428 .value("hardwarePath", "")
429 .empty())
430 {
Anupama B Rd966f272025-07-21 02:40:16 -0500431 l_inputPathIsDestinationPath = true;
Anupama B R7b293cd2025-03-28 05:35:01 -0500432 }
433 else
434 {
435 // Input path is neither source or destination path of the
Anupama B Rd966f272025-07-21 02:40:16 -0500436 // backup&restore JSON or source and destination paths are not hardware
437 // paths in the config JSON.
Anupama B R7b293cd2025-03-28 05:35:01 -0500438 return constants::SUCCESS;
Anupama B R8dedd1e2025-03-24 07:43:47 -0500439 }
440
Anupama B Rd966f272025-07-21 02:40:16 -0500441 if (m_backupAndRestoreCfgJsonObj["backupMap"].is_array())
Anupama B R7b293cd2025-03-28 05:35:01 -0500442 {
443 std::string l_inpRecordName;
444 std::string l_inpKeywordName;
Anupama B Rd966f272025-07-21 02:40:16 -0500445 types::BinaryVector l_inpKeywordValue;
Anupama B R7b293cd2025-03-28 05:35:01 -0500446
447 if (const types::IpzData* l_ipzData =
448 std::get_if<types::IpzData>(&i_paramsToWriteData))
449 {
450 l_inpRecordName = std::get<0>(*l_ipzData);
451 l_inpKeywordName = std::get<1>(*l_ipzData);
Anupama B Rd966f272025-07-21 02:40:16 -0500452 l_inpKeywordValue = std::get<2>(*l_ipzData);
Anupama B R7b293cd2025-03-28 05:35:01 -0500453
454 if (l_inpRecordName.empty() || l_inpKeywordName.empty() ||
Anupama B Rd966f272025-07-21 02:40:16 -0500455 l_inpKeywordValue.empty())
Anupama B R7b293cd2025-03-28 05:35:01 -0500456 {
457 logging::logMessage("Invalid input received");
458 return constants::FAILURE;
459 }
460 }
461 else
462 {
463 // only IPZ type VPD is supported now.
464 return constants::SUCCESS;
465 }
466
467 for (const auto& l_aRecordKwInfo :
468 m_backupAndRestoreCfgJsonObj["backupMap"])
469 {
470 if (l_aRecordKwInfo.value("sourceRecord", "").empty() ||
471 l_aRecordKwInfo.value("sourceKeyword", "").empty() ||
472 l_aRecordKwInfo.value("destinationRecord", "").empty() ||
473 l_aRecordKwInfo.value("destinationKeyword", "").empty())
474 {
475 // invalid backup map found
476 logging::logMessage(
477 "Invalid backup map found, one or more field(s) found empty or not present in the config JSON: sourceRecord: " +
478 l_aRecordKwInfo.value("sourceRecord", "") +
479 ", sourceKeyword: " +
480 l_aRecordKwInfo.value("sourceKeyword", "") +
481 ", destinationRecord: " +
482 l_aRecordKwInfo.value("destinationRecord", "") +
483 ", destinationKeyword: " +
484 l_aRecordKwInfo.value("destinationKeyword", ""));
485 continue;
486 }
487
Anupama B Rd966f272025-07-21 02:40:16 -0500488 if (l_inputPathIsSourcePath &&
Anupama B R7b293cd2025-03-28 05:35:01 -0500489 (l_aRecordKwInfo["sourceRecord"] == l_inpRecordName) &&
490 (l_aRecordKwInfo["sourceKeyword"] == l_inpKeywordName))
491 {
492 std::string l_fruPath(
493 m_backupAndRestoreCfgJsonObj["destination"]
494 ["hardwarePath"]);
495 Parser l_parserObj(l_fruPath, m_sysCfgJsonObj);
496
497 return l_parserObj.updateVpdKeyword(std::make_tuple(
498 l_aRecordKwInfo["destinationRecord"],
Anupama B Rd966f272025-07-21 02:40:16 -0500499 l_aRecordKwInfo["destinationKeyword"], l_inpKeywordValue));
Anupama B R7b293cd2025-03-28 05:35:01 -0500500 }
Anupama B Rd966f272025-07-21 02:40:16 -0500501 else if (l_inputPathIsDestinationPath &&
Anupama B R7b293cd2025-03-28 05:35:01 -0500502 (l_aRecordKwInfo["destinationRecord"] ==
503 l_inpRecordName) &&
504 (l_aRecordKwInfo["destinationKeyword"] ==
505 l_inpKeywordName))
506 {
507 std::string l_fruPath(
508 m_backupAndRestoreCfgJsonObj["source"]["hardwarePath"]);
509 Parser l_parserObj(l_fruPath, m_sysCfgJsonObj);
510
511 return l_parserObj.updateVpdKeyword(std::make_tuple(
512 l_aRecordKwInfo["sourceRecord"],
Anupama B Rd966f272025-07-21 02:40:16 -0500513 l_aRecordKwInfo["sourceKeyword"], l_inpKeywordValue));
Anupama B R7b293cd2025-03-28 05:35:01 -0500514 }
515 }
516 }
517
518 // Received property is not part of backup & restore JSON.
Anupama B R8dedd1e2025-03-24 07:43:47 -0500519 return constants::SUCCESS;
520}
521
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500522} // namespace vpd