blob: 9de43b9db7ecd1f764d63b999cc2f89b9aee9557 [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 {
247 vpdSpecificUtility::getKwVal(io_srcVpdMap.at(l_srcRecordName),
248 l_srcKeywordName, l_srcStrValue);
249 l_srcBinaryValue =
250 types::BinaryVector(l_srcStrValue.begin(), l_srcStrValue.end());
251 }
252 else
253 {
254 // Read keyword value from DBus
255 const auto l_value = dbusUtility::readDbusProperty(
256 l_srcServiceName, l_srcInvPath,
257 constants::ipzVpdInf + l_srcRecordName, l_srcKeywordName);
258 if (const auto l_binaryValue =
259 std::get_if<types::BinaryVector>(&l_value))
260 {
261 l_srcBinaryValue = *l_binaryValue;
262 l_srcStrValue = std::string(l_srcBinaryValue.begin(),
263 l_srcBinaryValue.end());
264 }
265 }
266
267 types::BinaryVector l_dstBinaryValue;
268 std::string l_dstStrValue;
269 if (!io_dstVpdMap.empty())
270 {
271 vpdSpecificUtility::getKwVal(io_dstVpdMap.at(l_dstRecordName),
272 l_dstKeywordName, l_dstStrValue);
273 l_dstBinaryValue =
274 types::BinaryVector(l_dstStrValue.begin(), l_dstStrValue.end());
275 }
276 else
277 {
278 // Read keyword value from DBus
279 const auto l_value = dbusUtility::readDbusProperty(
280 l_dstServiceName, l_dstInvPath,
281 constants::ipzVpdInf + l_dstRecordName, l_dstKeywordName);
282 if (const auto l_binaryValue =
283 std::get_if<types::BinaryVector>(&l_value))
284 {
285 l_dstBinaryValue = *l_binaryValue;
286 l_dstStrValue = std::string(l_dstBinaryValue.begin(),
287 l_dstBinaryValue.end());
288 }
289 }
290
291 if (l_srcBinaryValue != l_dstBinaryValue)
292 {
293 // ToDo: Handle if there is no valid default value in the backup and
294 // restore config JSON.
295 if (l_dstBinaryValue == l_defaultBinaryValue)
296 {
297 // Update keyword's value on hardware
298 auto l_vpdParser =
299 std::make_shared<Parser>(l_dstFruPath, m_sysCfgJsonObj);
300
301 auto l_bytesUpdatedOnHardware = l_vpdParser->updateVpdKeyword(
302 types::IpzData(l_dstRecordName, l_dstKeywordName,
303 l_srcBinaryValue));
304
305 /* To keep the data in sync between hardware and parsed map
306 updating the io_dstVpdMap. This should only be done if write
307 on hardware returns success.*/
308 if (!io_dstVpdMap.empty() && l_bytesUpdatedOnHardware > 0)
309 {
310 io_dstVpdMap[l_dstRecordName][l_dstKeywordName] =
311 l_srcStrValue;
312 }
313 continue;
314 }
315
316 if (l_srcBinaryValue == l_defaultBinaryValue)
317 {
318 // Update keyword's value on hardware
319 auto l_vpdParser =
320 std::make_shared<Parser>(l_srcFruPath, m_sysCfgJsonObj);
321
322 auto l_bytesUpdatedOnHardware = l_vpdParser->updateVpdKeyword(
323 types::IpzData(l_srcRecordName, l_srcKeywordName,
324 l_dstBinaryValue));
325
326 /* To keep the data in sync between hardware and parsed map
327 updating the io_srcVpdMap. This should only be done if write
328 on hardware returns success.*/
329 if (!io_srcVpdMap.empty() && l_bytesUpdatedOnHardware > 0)
330 {
331 io_srcVpdMap[l_srcRecordName][l_srcKeywordName] =
332 l_dstStrValue;
333 }
334 }
335 else
336 {
337 /**
338 * Update io_srcVpdMap to publish the same data on DBus, which
339 * is already present on the DBus. Because after calling
340 * backupAndRestore API the map value will get published to DBus
341 * in the worker flow.
342 */
343 if (!io_srcVpdMap.empty() && io_dstVpdMap.empty())
344 {
345 io_srcVpdMap[l_srcRecordName][l_srcKeywordName] =
346 l_dstStrValue;
347 }
348
349 std::string l_errorMsg(
350 "Mismatch found between source and destination VPD for record : " +
351 l_srcRecordName + " and keyword : " + l_srcKeywordName +
352 " . Value read from source : " + l_srcStrValue +
353 " . Value read from destination : " + l_dstStrValue);
354
355 EventLogger::createSyncPel(
356 types::ErrorType::VpdMismatch, types::SeverityType::Warning,
357 __FILE__, __FUNCTION__, 0, l_errorMsg, std::nullopt,
358 std::nullopt, std::nullopt, std::nullopt);
359 }
360 }
361 else if (l_srcBinaryValue == l_defaultBinaryValue &&
362 l_dstBinaryValue == l_defaultBinaryValue && l_isPelRequired)
363 {
364 std::string l_errorMsg(
365 "Default value found on both source and destination VPD, for record: " +
366 l_srcRecordName + " and keyword: " + l_srcKeywordName);
367
368 EventLogger::createSyncPel(
369 types::ErrorType::DefaultValue, types::SeverityType::Error,
370 __FILE__, __FUNCTION__, 0, l_errorMsg, std::nullopt,
371 std::nullopt, std::nullopt, std::nullopt);
372 }
373 }
374}
375
376void BackupAndRestore::setBackupAndRestoreStatus(
377 const BackupAndRestoreStatus& i_status)
378{
379 m_backupAndRestoreStatus = i_status;
380}
381} // namespace vpd