blob: cede92067bfbf047ac14cd9fb1cf47f627e211c7 [file] [log] [blame]
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -05001#include "parser.hpp"
2
3#include "constants.hpp"
4#include "event_logger.hpp"
5
6#include <utility/dbus_utility.hpp>
7#include <utility/json_utility.hpp>
8#include <utility/vpd_specific_utility.hpp>
9
10#include <fstream>
11
12namespace vpd
13{
14Parser::Parser(const std::string& vpdFilePath, nlohmann::json parsedJson) :
15 m_vpdFilePath(vpdFilePath), m_parsedJson(parsedJson)
16{
17 std::error_code l_errCode;
18
19 // ToDo: Add minimum file size check in all the concert praser classes,
20 // depends on their VPD type.
21 if (!std::filesystem::exists(m_vpdFilePath, l_errCode))
22 {
23 std::string l_message{"Parser object creation failed, file [" +
24 m_vpdFilePath + "] doesn't exists."};
25
26 if (l_errCode)
27 {
28 l_message += " Error message: " + l_errCode.message();
29 }
30
31 throw std::runtime_error(l_message);
32 }
33
34 // Read VPD offset if applicable.
35 if (!m_parsedJson.empty())
36 {
37 m_vpdStartOffset = jsonUtility::getVPDOffset(m_parsedJson, vpdFilePath);
38 }
39}
40
41std::shared_ptr<vpd::ParserInterface> Parser::getVpdParserInstance()
42{
43 // Read the VPD data into a vector.
44 vpdSpecificUtility::getVpdDataInVector(m_vpdFilePath, m_vpdVector,
45 m_vpdStartOffset);
46
47 // This will detect the type of parser required.
48 std::shared_ptr<vpd::ParserInterface> l_parser =
49 ParserFactory::getParser(m_vpdVector, m_vpdFilePath, m_vpdStartOffset);
50
51 return l_parser;
52}
53
54types::VPDMapVariant Parser::parse()
55{
56 std::shared_ptr<vpd::ParserInterface> l_parser = getVpdParserInstance();
57 return l_parser->parse();
58}
59
60int Parser::updateVpdKeyword(const types::WriteVpdParams& i_paramsToWriteData)
61{
62 int l_bytesUpdatedOnHardware = constants::FAILURE;
63
64 // A lambda to extract Record : Keyword string from i_paramsToWriteData
65 auto l_keyWordIdentifier =
66 [](const types::WriteVpdParams& i_paramsToWriteData) -> std::string {
67 std::string l_keywordString{};
68 if (const types::IpzData* l_ipzData =
69 std::get_if<types::IpzData>(&i_paramsToWriteData))
70 {
71 l_keywordString =
72 std::get<0>(*l_ipzData) + ":" + std::get<1>(*l_ipzData);
73 }
74 else if (const types::KwData* l_kwData =
75 std::get_if<types::KwData>(&i_paramsToWriteData))
76 {
77 l_keywordString = std::get<0>(*l_kwData);
78 }
79 return l_keywordString;
80 };
81
82 try
83 {
84 // Enable Reboot Guard
85 if (constants::FAILURE == dbusUtility::EnableRebootGuard())
86 {
87 EventLogger::createAsyncPel(
88 types::ErrorType::DbusFailure,
89 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
90 std::string(
91 "Failed to enable BMC Reboot Guard while updating " +
92 l_keyWordIdentifier(i_paramsToWriteData)),
93 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
94
95 return constants::FAILURE;
96 }
97
98 // Update keyword's value on hardware
99 try
100 {
101 std::shared_ptr<ParserInterface> l_vpdParserInstance =
102 getVpdParserInstance();
103 l_bytesUpdatedOnHardware =
104 l_vpdParserInstance->writeKeywordOnHardware(
105 i_paramsToWriteData);
106 }
107 catch (const std::exception& l_exception)
108 {
109 std::string l_errMsg(
110 "Error while updating keyword's value on hardware path " +
111 m_vpdFilePath + ", error: " + std::string(l_exception.what()));
112
113 // TODO : Log PEL
114
115 throw std::runtime_error(l_errMsg);
116 }
117
118 auto [l_fruPath, l_inventoryObjPath, l_redundantFruPath] =
119 jsonUtility::getAllPathsToUpdateKeyword(m_parsedJson,
120 m_vpdFilePath);
121
122 // If inventory D-bus object path is present, update keyword's value on
123 // DBus
124 if (!l_inventoryObjPath.empty())
125 {
126 types::Record l_recordName;
127 std::string l_interfaceName;
128 std::string l_propertyName;
129 types::DbusVariantType l_keywordValue;
130
131 if (const types::IpzData* l_ipzData =
132 std::get_if<types::IpzData>(&i_paramsToWriteData))
133 {
134 l_recordName = std::get<0>(*l_ipzData);
135 l_interfaceName = constants::ipzVpdInf + l_recordName;
136 l_propertyName = std::get<1>(*l_ipzData);
137
138 try
139 {
140 // Read keyword's value from hardware to write the same on
141 // D-bus.
142 std::shared_ptr<ParserInterface> l_vpdParserInstance =
143 getVpdParserInstance();
144
Sunny Srivastavafa5e4d32023-03-12 11:59:49 -0500145 l_keywordValue =
146 l_vpdParserInstance->readKeywordFromHardware(
147 types::ReadVpdParams(
148 std::make_tuple(l_recordName, l_propertyName)));
149 }
150 catch (const std::exception& l_exception)
151 {
152 // Unable to read keyword's value from hardware.
153 std::string l_errMsg(
154 "Error while reading keyword's value from hadware path " +
155 m_vpdFilePath +
156 ", error: " + std::string(l_exception.what()));
157
158 // TODO: Log PEL
159
160 throw std::runtime_error(l_errMsg);
161 }
162 }
163 else
164 {
165 // Input parameter type provided isn't compatible to perform
166 // update.
167 std::string l_errMsg(
168 "Input parameter type isn't compatible to update keyword's value on DBus for object path: " +
169 l_inventoryObjPath);
170 throw std::runtime_error(l_errMsg);
171 }
172
173 // Get D-bus name for the given keyword
174 l_propertyName =
175 vpdSpecificUtility::getDbusPropNameForGivenKw(l_propertyName);
176
177 // Create D-bus object map
178 types::ObjectMap l_dbusObjMap = {std::make_pair(
179 l_inventoryObjPath,
180 types::InterfaceMap{std::make_pair(
181 l_interfaceName, types::PropertyMap{std::make_pair(
182 l_propertyName, l_keywordValue)})})};
183
184 // Call PIM's Notify method to perform update
185 if (!dbusUtility::callPIM(std::move(l_dbusObjMap)))
186 {
187 // Call to PIM's Notify method failed.
188 std::string l_errMsg("Notify PIM is failed for object path: " +
189 l_inventoryObjPath);
190 throw std::runtime_error(l_errMsg);
191 }
192 }
193
194 // Update keyword's value on redundant hardware if present
195 if (!l_redundantFruPath.empty())
196 {
197 if (updateVpdKeywordOnRedundantPath(l_redundantFruPath,
198 i_paramsToWriteData) < 0)
199 {
200 std::string l_errMsg(
201 "Error while updating keyword's value on redundant path " +
202 l_redundantFruPath);
203 throw std::runtime_error(l_errMsg);
204 }
205 }
206
207 // TODO: Check if revert is required when any of the writes fails.
208 // TODO: Handle error logging
209 }
210 catch (const std::exception& l_ex)
211 {
212 logging::logMessage("Update VPD Keyword failed for : " +
213 l_keyWordIdentifier(i_paramsToWriteData) +
214 " failed due to error: " + l_ex.what());
215
216 // update failed, set return value to failure
217 l_bytesUpdatedOnHardware = constants::FAILURE;
218 }
219
220 // Disable Reboot Guard
221 if (constants::FAILURE == dbusUtility::DisableRebootGuard())
222 {
223 EventLogger::createAsyncPel(
224 types::ErrorType::DbusFailure, types::SeverityType::Critical,
225 __FILE__, __FUNCTION__, 0,
226 std::string("Failed to disable BMC Reboot Guard while updating " +
227 l_keyWordIdentifier(i_paramsToWriteData)),
228 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
229 }
230
231 return l_bytesUpdatedOnHardware;
232}
233
234int Parser::updateVpdKeywordOnRedundantPath(
235 const std::string& i_fruPath,
236 const types::WriteVpdParams& i_paramsToWriteData)
237{
238 try
239 {
240 std::shared_ptr<Parser> l_parserObj =
241 std::make_shared<Parser>(i_fruPath, m_parsedJson);
242
243 std::shared_ptr<ParserInterface> l_vpdParserInstance =
244 l_parserObj->getVpdParserInstance();
245
246 return l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
247 }
248 catch (const std::exception& l_exception)
249 {
250 EventLogger::createSyncPel(
251 types::ErrorType::InvalidVpdMessage,
252 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
253 "Error while updating keyword's value on redundant path " +
254 i_fruPath + ", error: " + std::string(l_exception.what()),
255 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
256 return -1;
257 }
258}
259
260int Parser::updateVpdKeywordOnHardware(
261 const types::WriteVpdParams& i_paramsToWriteData)
262{
263 int l_bytesUpdatedOnHardware = constants::FAILURE;
264
265 // A lambda to extract Record : Keyword string from i_paramsToWriteData
266 auto l_keyWordIdentifier =
267 [](const types::WriteVpdParams& i_paramsToWriteData) -> std::string {
268 std::string l_keywordString{};
269 if (const types::IpzData* l_ipzData =
270 std::get_if<types::IpzData>(&i_paramsToWriteData))
271 {
272 l_keywordString =
273 std::get<0>(*l_ipzData) + ":" + std::get<1>(*l_ipzData);
274 }
275 else if (const types::KwData* l_kwData =
276 std::get_if<types::KwData>(&i_paramsToWriteData))
277 {
278 l_keywordString = std::get<0>(*l_kwData);
279 }
280 return l_keywordString;
281 };
282
283 try
284 {
285 // Enable Reboot Guard
286 if (constants::FAILURE == dbusUtility::EnableRebootGuard())
287 {
288 EventLogger::createAsyncPel(
289 types::ErrorType::DbusFailure,
290 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
291 std::string(
292 "Failed to enable BMC Reboot Guard while updating " +
293 l_keyWordIdentifier(i_paramsToWriteData)),
294 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
295
296 return constants::FAILURE;
297 }
298
299 std::shared_ptr<ParserInterface> l_vpdParserInstance =
300 getVpdParserInstance();
301 l_bytesUpdatedOnHardware =
302 l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
303 }
304 catch (const std::exception& l_exception)
305 {
306 types::ErrorType l_errorType;
307
308 if (typeid(l_exception) == typeid(EccException))
309 {
310 l_errorType = types::ErrorType::EccCheckFailed;
311 }
312 else
313 {
314 l_errorType = types::ErrorType::InvalidVpdMessage;
315 }
316
317 EventLogger::createAsyncPel(
318 l_errorType, types::SeverityType::Informational, __FILE__,
319 __FUNCTION__, 0,
320 "Error while updating keyword's value on hardware path [" +
321 m_vpdFilePath + "], error: " + std::string(l_exception.what()),
322 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
323 }
324
325 // Disable Reboot Guard
326 if (constants::FAILURE == dbusUtility::DisableRebootGuard())
327 {
328 EventLogger::createAsyncPel(
329 types::ErrorType::DbusFailure, types::SeverityType::Critical,
330 __FILE__, __FUNCTION__, 0,
331 std::string("Failed to disable BMC Reboot Guard while updating " +
332 l_keyWordIdentifier(i_paramsToWriteData)),
333 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
334 }
335
336 return l_bytesUpdatedOnHardware;
337}
338
339} // namespace vpd