xref: /openbmc/openpower-vpd-parser/vpd-manager/src/backup_restore.cpp (revision fa5e4d325ef9cea3c841fe89d202c340f92bd8c6)
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