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 try
24 {
25 m_backupAndRestoreCfgJsonObj =
26 jsonUtility::getParsedJson(l_backupAndRestoreCfgFilePath);
27 }
28 catch (const std::exception& ex)
29 {
30 logging::logMessage(
31 "Failed to intialize backup and restore object for file = " +
32 l_backupAndRestoreCfgFilePath);
33 throw(ex);
34 }
35 }
36
37 std::tuple<types::VPDMapVariant, types::VPDMapVariant>
backupAndRestore()38 BackupAndRestore::backupAndRestore()
39 {
40 auto l_emptyVariantPair =
41 std::make_tuple(std::monostate{}, std::monostate{});
42
43 if (m_backupAndRestoreStatus >= BackupAndRestoreStatus::Invoked)
44 {
45 logging::logMessage("Backup and restore invoked already.");
46 return l_emptyVariantPair;
47 }
48
49 m_backupAndRestoreStatus = BackupAndRestoreStatus::Invoked;
50 try
51 {
52 if (m_backupAndRestoreCfgJsonObj.empty() ||
53 !m_backupAndRestoreCfgJsonObj.contains("source") ||
54 !m_backupAndRestoreCfgJsonObj.contains("destination") ||
55 !m_backupAndRestoreCfgJsonObj.contains("type") ||
56 !m_backupAndRestoreCfgJsonObj.contains("backupMap"))
57 {
58 logging::logMessage(
59 "Backup restore config JSON is missing necessary tag(s), can't initiate backup and restore.");
60 return l_emptyVariantPair;
61 }
62
63 std::string l_srcVpdPath;
64 types::VPDMapVariant l_srcVpdVariant;
65 if (l_srcVpdPath = m_backupAndRestoreCfgJsonObj["source"].value(
66 "hardwarePath", "");
67 !l_srcVpdPath.empty() && std::filesystem::exists(l_srcVpdPath))
68 {
69 std::shared_ptr<Parser> l_vpdParser =
70 std::make_shared<Parser>(l_srcVpdPath, m_sysCfgJsonObj);
71 l_srcVpdVariant = l_vpdParser->parse();
72 }
73 else if (l_srcVpdPath = m_backupAndRestoreCfgJsonObj["source"].value(
74 "inventoryPath", "");
75 l_srcVpdPath.empty())
76 {
77 logging::logMessage(
78 "Couldn't extract source path, can't initiate backup and restore.");
79 return l_emptyVariantPair;
80 }
81
82 std::string l_dstVpdPath;
83 types::VPDMapVariant l_dstVpdVariant;
84 if (l_dstVpdPath = m_backupAndRestoreCfgJsonObj["destination"].value(
85 "hardwarePath", "");
86 !l_dstVpdPath.empty() && std::filesystem::exists(l_dstVpdPath))
87 {
88 std::shared_ptr<Parser> l_vpdParser =
89 std::make_shared<Parser>(l_dstVpdPath, m_sysCfgJsonObj);
90 l_dstVpdVariant = l_vpdParser->parse();
91 }
92 else if (l_dstVpdPath = m_backupAndRestoreCfgJsonObj["destination"]
93 .value("inventoryPath", "");
94 l_dstVpdPath.empty())
95 {
96 logging::logMessage(
97 "Couldn't extract destination path, can't initiate backup and restore.");
98 return l_emptyVariantPair;
99 }
100
101 // Implement backup and restore for IPZ type VPD
102 auto l_backupAndRestoreType =
103 m_backupAndRestoreCfgJsonObj.value("type", "");
104 if (l_backupAndRestoreType.compare("IPZ") == constants::STR_CMP_SUCCESS)
105 {
106 types::IPZVpdMap l_srcVpdMap;
107 if (auto l_srcVpdPtr =
108 std::get_if<types::IPZVpdMap>(&l_srcVpdVariant))
109 {
110 l_srcVpdMap = *l_srcVpdPtr;
111 }
112 else if (!std::holds_alternative<std::monostate>(l_srcVpdVariant))
113 {
114 logging::logMessage("Source VPD is not of IPZ type.");
115 return l_emptyVariantPair;
116 }
117
118 types::IPZVpdMap l_dstVpdMap;
119 if (auto l_dstVpdPtr =
120 std::get_if<types::IPZVpdMap>(&l_dstVpdVariant))
121 {
122 l_dstVpdMap = *l_dstVpdPtr;
123 }
124 else if (!std::holds_alternative<std::monostate>(l_dstVpdVariant))
125 {
126 logging::logMessage("Destination VPD is not of IPZ type.");
127 return l_emptyVariantPair;
128 }
129
130 backupAndRestoreIpzVpd(l_srcVpdMap, l_dstVpdMap, l_srcVpdPath,
131 l_dstVpdPath);
132 m_backupAndRestoreStatus = BackupAndRestoreStatus::Completed;
133
134 return std::make_tuple(l_srcVpdMap, l_dstVpdMap);
135 }
136 // Note: add implementation here to support any other VPD type.
137 }
138 catch (const std::exception& ex)
139 {
140 logging::logMessage("Back up and restore failed with exception: " +
141 std::string(ex.what()));
142 }
143 return l_emptyVariantPair;
144 }
145
backupAndRestoreIpzVpd(types::IPZVpdMap & io_srcVpdMap,types::IPZVpdMap & io_dstVpdMap,const std::string & i_srcPath,const std::string & i_dstPath)146 void BackupAndRestore::backupAndRestoreIpzVpd(
147 types::IPZVpdMap& io_srcVpdMap, types::IPZVpdMap& io_dstVpdMap,
148 const std::string& i_srcPath, const std::string& i_dstPath)
149 {
150 if (!m_backupAndRestoreCfgJsonObj["backupMap"].is_array())
151 {
152 logging::logMessage(
153 "Invalid value found for tag backupMap, in backup and restore config JSON.");
154 return;
155 }
156
157 const std::string l_srcFruPath =
158 jsonUtility::getFruPathFromJson(m_sysCfgJsonObj, i_srcPath);
159 const std::string l_dstFruPath =
160 jsonUtility::getFruPathFromJson(m_sysCfgJsonObj, i_dstPath);
161 if (l_srcFruPath.empty() || l_dstFruPath.empty())
162 {
163 logging::logMessage(
164 "Couldn't find either source or destination FRU path.");
165 return;
166 }
167
168 const std::string l_srcInvPath =
169 jsonUtility::getInventoryObjPathFromJson(m_sysCfgJsonObj, i_srcPath);
170 const std::string l_dstInvPath =
171 jsonUtility::getInventoryObjPathFromJson(m_sysCfgJsonObj, i_dstPath);
172 if (l_srcInvPath.empty() || l_dstInvPath.empty())
173 {
174 logging::logMessage(
175 "Couldn't find either source or destination inventory path.");
176 return;
177 }
178
179 const std::string l_srcServiceName =
180 jsonUtility::getServiceName(m_sysCfgJsonObj, l_srcInvPath);
181 const std::string l_dstServiceName =
182 jsonUtility::getServiceName(m_sysCfgJsonObj, l_dstInvPath);
183 if (l_srcServiceName.empty() || l_dstServiceName.empty())
184 {
185 logging::logMessage(
186 "Couldn't find either source or destination DBus service name.");
187 return;
188 }
189
190 for (const auto& l_aRecordKwInfo :
191 m_backupAndRestoreCfgJsonObj["backupMap"])
192 {
193 const std::string& l_srcRecordName =
194 l_aRecordKwInfo.value("sourceRecord", "");
195 const std::string& l_srcKeywordName =
196 l_aRecordKwInfo.value("sourceKeyword", "");
197 const std::string& l_dstRecordName =
198 l_aRecordKwInfo.value("destinationRecord", "");
199 const std::string& l_dstKeywordName =
200 l_aRecordKwInfo.value("destinationKeyword", "");
201
202 if (l_srcRecordName.empty() || l_dstRecordName.empty() ||
203 l_srcKeywordName.empty() || l_dstKeywordName.empty())
204 {
205 logging::logMessage(
206 "Record or keyword not found in the backup and restore config JSON.");
207 continue;
208 }
209
210 if (!io_srcVpdMap.empty() &&
211 io_srcVpdMap.find(l_srcRecordName) == io_srcVpdMap.end())
212 {
213 logging::logMessage(
214 "Record: " + l_srcRecordName +
215 ", is not found in the source path: " + i_srcPath);
216 continue;
217 }
218
219 if (!io_dstVpdMap.empty() &&
220 io_dstVpdMap.find(l_dstRecordName) == io_dstVpdMap.end())
221 {
222 logging::logMessage(
223 "Record: " + l_dstRecordName +
224 ", is not found in the destination path: " + i_dstPath);
225 continue;
226 }
227
228 types::BinaryVector l_defaultBinaryValue;
229 if (l_aRecordKwInfo.contains("defaultValue") &&
230 l_aRecordKwInfo["defaultValue"].is_array())
231 {
232 l_defaultBinaryValue =
233 l_aRecordKwInfo["defaultValue"].get<types::BinaryVector>();
234 }
235 else
236 {
237 logging::logMessage(
238 "Couldn't read default value for record name: " +
239 l_srcRecordName + ", keyword name: " + l_srcKeywordName +
240 " from backup and restore config JSON file.");
241 continue;
242 }
243
244 bool l_isPelRequired = l_aRecordKwInfo.value("isPelRequired", false);
245
246 types::BinaryVector l_srcBinaryValue;
247 std::string l_srcStrValue;
248 if (!io_srcVpdMap.empty())
249 {
250 vpdSpecificUtility::getKwVal(io_srcVpdMap.at(l_srcRecordName),
251 l_srcKeywordName, l_srcStrValue);
252 l_srcBinaryValue =
253 types::BinaryVector(l_srcStrValue.begin(), l_srcStrValue.end());
254 }
255 else
256 {
257 // Read keyword value from DBus
258 const auto l_value = dbusUtility::readDbusProperty(
259 l_srcServiceName, l_srcInvPath,
260 constants::ipzVpdInf + l_srcRecordName, l_srcKeywordName);
261 if (const auto l_binaryValue =
262 std::get_if<types::BinaryVector>(&l_value))
263 {
264 l_srcBinaryValue = *l_binaryValue;
265 l_srcStrValue = std::string(l_srcBinaryValue.begin(),
266 l_srcBinaryValue.end());
267 }
268 }
269
270 types::BinaryVector l_dstBinaryValue;
271 std::string l_dstStrValue;
272 if (!io_dstVpdMap.empty())
273 {
274 vpdSpecificUtility::getKwVal(io_dstVpdMap.at(l_dstRecordName),
275 l_dstKeywordName, l_dstStrValue);
276 l_dstBinaryValue =
277 types::BinaryVector(l_dstStrValue.begin(), l_dstStrValue.end());
278 }
279 else
280 {
281 // Read keyword value from DBus
282 const auto l_value = dbusUtility::readDbusProperty(
283 l_dstServiceName, l_dstInvPath,
284 constants::ipzVpdInf + l_dstRecordName, l_dstKeywordName);
285 if (const auto l_binaryValue =
286 std::get_if<types::BinaryVector>(&l_value))
287 {
288 l_dstBinaryValue = *l_binaryValue;
289 l_dstStrValue = std::string(l_dstBinaryValue.begin(),
290 l_dstBinaryValue.end());
291 }
292 }
293
294 if (l_srcBinaryValue != l_dstBinaryValue)
295 {
296 // ToDo: Handle if there is no valid default value in the backup and
297 // restore config JSON.
298 if (l_dstBinaryValue == l_defaultBinaryValue)
299 {
300 // Update keyword's value on hardware
301 auto l_vpdParser =
302 std::make_shared<Parser>(l_dstFruPath, m_sysCfgJsonObj);
303
304 auto l_bytesUpdatedOnHardware = l_vpdParser->updateVpdKeyword(
305 types::IpzData(l_dstRecordName, l_dstKeywordName,
306 l_srcBinaryValue));
307
308 /* To keep the data in sync between hardware and parsed map
309 updating the io_dstVpdMap. This should only be done if write
310 on hardware returns success.*/
311 if (!io_dstVpdMap.empty() && l_bytesUpdatedOnHardware > 0)
312 {
313 io_dstVpdMap[l_dstRecordName][l_dstKeywordName] =
314 l_srcStrValue;
315 }
316 continue;
317 }
318
319 if (l_srcBinaryValue == l_defaultBinaryValue)
320 {
321 // Update keyword's value on hardware
322 auto l_vpdParser =
323 std::make_shared<Parser>(l_srcFruPath, m_sysCfgJsonObj);
324
325 auto l_bytesUpdatedOnHardware = l_vpdParser->updateVpdKeyword(
326 types::IpzData(l_srcRecordName, l_srcKeywordName,
327 l_dstBinaryValue));
328
329 /* To keep the data in sync between hardware and parsed map
330 updating the io_srcVpdMap. This should only be done if write
331 on hardware returns success.*/
332 if (!io_srcVpdMap.empty() && l_bytesUpdatedOnHardware > 0)
333 {
334 io_srcVpdMap[l_srcRecordName][l_srcKeywordName] =
335 l_dstStrValue;
336 }
337 }
338 else
339 {
340 /**
341 * Update io_srcVpdMap to publish the same data on DBus, which
342 * is already present on the DBus. Because after calling
343 * backupAndRestore API the map value will get published to DBus
344 * in the worker flow.
345 */
346 if (!io_srcVpdMap.empty() && io_dstVpdMap.empty())
347 {
348 io_srcVpdMap[l_srcRecordName][l_srcKeywordName] =
349 l_dstStrValue;
350 }
351
352 std::string l_errorMsg(
353 "Mismatch found between source and destination VPD for record : " +
354 l_srcRecordName + " and keyword : " + l_srcKeywordName +
355 " . Value read from source : " + l_srcStrValue +
356 " . Value read from destination : " + l_dstStrValue);
357
358 EventLogger::createSyncPel(
359 types::ErrorType::VpdMismatch, types::SeverityType::Warning,
360 __FILE__, __FUNCTION__, 0, l_errorMsg, std::nullopt,
361 std::nullopt, std::nullopt, std::nullopt);
362 }
363 }
364 else if (l_srcBinaryValue == l_defaultBinaryValue &&
365 l_dstBinaryValue == l_defaultBinaryValue && l_isPelRequired)
366 {
367 std::string l_errorMsg(
368 "Default value found on both source and destination VPD, for record: " +
369 l_srcRecordName + " and keyword: " + l_srcKeywordName);
370
371 EventLogger::createSyncPel(
372 types::ErrorType::DefaultValue, types::SeverityType::Error,
373 __FILE__, __FUNCTION__, 0, l_errorMsg, std::nullopt,
374 std::nullopt, std::nullopt, std::nullopt);
375 }
376 }
377 }
378
setBackupAndRestoreStatus(const BackupAndRestoreStatus & i_status)379 void BackupAndRestore::setBackupAndRestoreStatus(
380 const BackupAndRestoreStatus& i_status)
381 {
382 m_backupAndRestoreStatus = i_status;
383 }
384 } // namespace vpd
385