1 #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
13 namespace vpd
14 {
15 BackupAndRestoreStatus BackupAndRestore::m_backupAndRestoreStatus =
16 BackupAndRestoreStatus::NotStarted;
17
BackupAndRestore(const nlohmann::json & i_sysCfgJsonObj)18 BackupAndRestore::BackupAndRestore(const nlohmann::json& i_sysCfgJsonObj) :
19 m_sysCfgJsonObj(i_sysCfgJsonObj)
20 {
21 std::string l_backupAndRestoreCfgFilePath =
22 i_sysCfgJsonObj.value("backupRestoreConfigPath", "");
23
24 m_backupAndRestoreCfgJsonObj =
25 jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath);
26
27 if (m_backupAndRestoreCfgJsonObj.empty())
28 {
29 throw JsonException("JSON parsing failed",
30 l_backupAndRestoreCfgFilePath);
31 }
32 }
33
34 std::tuple<types::VPDMapVariant, types::VPDMapVariant>
backupAndRestore()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
backupAndRestoreIpzVpd(types::IPZVpdMap & io_srcVpdMap,types::IPZVpdMap & io_dstVpdMap,const std::string & i_srcPath,const std::string & i_dstPath)143 void 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 {
247 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
257 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 {
279 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
289 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 +
368 " . Value read from source : " + l_srcStrValue +
369 " . Value read from destination : " + l_dstStrValue);
370
371 EventLogger::createSyncPel(
372 types::ErrorType::VpdMismatch, types::SeverityType::Warning,
373 __FILE__, __FUNCTION__, 0, l_errorMsg, std::nullopt,
374 std::nullopt, std::nullopt, std::nullopt);
375 }
376 }
377 else if (l_srcBinaryValue == l_defaultBinaryValue &&
378 l_dstBinaryValue == l_defaultBinaryValue && l_isPelRequired)
379 {
380 std::string l_errorMsg(
381 "Default value found on both source and destination VPD, for record: " +
382 l_srcRecordName + " and keyword: " + l_srcKeywordName);
383
384 EventLogger::createSyncPel(
385 types::ErrorType::DefaultValue, types::SeverityType::Error,
386 __FILE__, __FUNCTION__, 0, l_errorMsg, std::nullopt,
387 std::nullopt, std::nullopt, std::nullopt);
388 }
389 }
390 }
391
setBackupAndRestoreStatus(const BackupAndRestoreStatus & i_status)392 void BackupAndRestore::setBackupAndRestoreStatus(
393 const BackupAndRestoreStatus& i_status)
394 {
395 m_backupAndRestoreStatus = i_status;
396 }
397 } // namespace vpd
398