blob: d6266cb7210b7fbca06b447f762c21f61f6335a8 [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
145 logging::logMessage(
146 "Performing VPD read on " + m_vpdFilePath);
147
148 l_keywordValue =
149 l_vpdParserInstance->readKeywordFromHardware(
150 types::ReadVpdParams(
151 std::make_tuple(l_recordName, l_propertyName)));
152 }
153 catch (const std::exception& l_exception)
154 {
155 // Unable to read keyword's value from hardware.
156 std::string l_errMsg(
157 "Error while reading keyword's value from hadware path " +
158 m_vpdFilePath +
159 ", error: " + std::string(l_exception.what()));
160
161 // TODO: Log PEL
162
163 throw std::runtime_error(l_errMsg);
164 }
165 }
166 else
167 {
168 // Input parameter type provided isn't compatible to perform
169 // update.
170 std::string l_errMsg(
171 "Input parameter type isn't compatible to update keyword's value on DBus for object path: " +
172 l_inventoryObjPath);
173 throw std::runtime_error(l_errMsg);
174 }
175
176 // Get D-bus name for the given keyword
177 l_propertyName =
178 vpdSpecificUtility::getDbusPropNameForGivenKw(l_propertyName);
179
180 // Create D-bus object map
181 types::ObjectMap l_dbusObjMap = {std::make_pair(
182 l_inventoryObjPath,
183 types::InterfaceMap{std::make_pair(
184 l_interfaceName, types::PropertyMap{std::make_pair(
185 l_propertyName, l_keywordValue)})})};
186
187 // Call PIM's Notify method to perform update
188 if (!dbusUtility::callPIM(std::move(l_dbusObjMap)))
189 {
190 // Call to PIM's Notify method failed.
191 std::string l_errMsg("Notify PIM is failed for object path: " +
192 l_inventoryObjPath);
193 throw std::runtime_error(l_errMsg);
194 }
195 }
196
197 // Update keyword's value on redundant hardware if present
198 if (!l_redundantFruPath.empty())
199 {
200 if (updateVpdKeywordOnRedundantPath(l_redundantFruPath,
201 i_paramsToWriteData) < 0)
202 {
203 std::string l_errMsg(
204 "Error while updating keyword's value on redundant path " +
205 l_redundantFruPath);
206 throw std::runtime_error(l_errMsg);
207 }
208 }
209
210 // TODO: Check if revert is required when any of the writes fails.
211 // TODO: Handle error logging
212 }
213 catch (const std::exception& l_ex)
214 {
215 logging::logMessage("Update VPD Keyword failed for : " +
216 l_keyWordIdentifier(i_paramsToWriteData) +
217 " failed due to error: " + l_ex.what());
218
219 // update failed, set return value to failure
220 l_bytesUpdatedOnHardware = constants::FAILURE;
221 }
222
223 // Disable Reboot Guard
224 if (constants::FAILURE == dbusUtility::DisableRebootGuard())
225 {
226 EventLogger::createAsyncPel(
227 types::ErrorType::DbusFailure, types::SeverityType::Critical,
228 __FILE__, __FUNCTION__, 0,
229 std::string("Failed to disable BMC Reboot Guard while updating " +
230 l_keyWordIdentifier(i_paramsToWriteData)),
231 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
232 }
233
234 return l_bytesUpdatedOnHardware;
235}
236
237int Parser::updateVpdKeywordOnRedundantPath(
238 const std::string& i_fruPath,
239 const types::WriteVpdParams& i_paramsToWriteData)
240{
241 try
242 {
243 std::shared_ptr<Parser> l_parserObj =
244 std::make_shared<Parser>(i_fruPath, m_parsedJson);
245
246 std::shared_ptr<ParserInterface> l_vpdParserInstance =
247 l_parserObj->getVpdParserInstance();
248
249 return l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
250 }
251 catch (const std::exception& l_exception)
252 {
253 EventLogger::createSyncPel(
254 types::ErrorType::InvalidVpdMessage,
255 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
256 "Error while updating keyword's value on redundant path " +
257 i_fruPath + ", error: " + std::string(l_exception.what()),
258 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
259 return -1;
260 }
261}
262
263int Parser::updateVpdKeywordOnHardware(
264 const types::WriteVpdParams& i_paramsToWriteData)
265{
266 int l_bytesUpdatedOnHardware = constants::FAILURE;
267
268 // A lambda to extract Record : Keyword string from i_paramsToWriteData
269 auto l_keyWordIdentifier =
270 [](const types::WriteVpdParams& i_paramsToWriteData) -> std::string {
271 std::string l_keywordString{};
272 if (const types::IpzData* l_ipzData =
273 std::get_if<types::IpzData>(&i_paramsToWriteData))
274 {
275 l_keywordString =
276 std::get<0>(*l_ipzData) + ":" + std::get<1>(*l_ipzData);
277 }
278 else if (const types::KwData* l_kwData =
279 std::get_if<types::KwData>(&i_paramsToWriteData))
280 {
281 l_keywordString = std::get<0>(*l_kwData);
282 }
283 return l_keywordString;
284 };
285
286 try
287 {
288 // Enable Reboot Guard
289 if (constants::FAILURE == dbusUtility::EnableRebootGuard())
290 {
291 EventLogger::createAsyncPel(
292 types::ErrorType::DbusFailure,
293 types::SeverityType::Informational, __FILE__, __FUNCTION__, 0,
294 std::string(
295 "Failed to enable BMC Reboot Guard while updating " +
296 l_keyWordIdentifier(i_paramsToWriteData)),
297 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
298
299 return constants::FAILURE;
300 }
301
302 std::shared_ptr<ParserInterface> l_vpdParserInstance =
303 getVpdParserInstance();
304 l_bytesUpdatedOnHardware =
305 l_vpdParserInstance->writeKeywordOnHardware(i_paramsToWriteData);
306 }
307 catch (const std::exception& l_exception)
308 {
309 types::ErrorType l_errorType;
310
311 if (typeid(l_exception) == typeid(EccException))
312 {
313 l_errorType = types::ErrorType::EccCheckFailed;
314 }
315 else
316 {
317 l_errorType = types::ErrorType::InvalidVpdMessage;
318 }
319
320 EventLogger::createAsyncPel(
321 l_errorType, types::SeverityType::Informational, __FILE__,
322 __FUNCTION__, 0,
323 "Error while updating keyword's value on hardware path [" +
324 m_vpdFilePath + "], error: " + std::string(l_exception.what()),
325 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
326 }
327
328 // Disable Reboot Guard
329 if (constants::FAILURE == dbusUtility::DisableRebootGuard())
330 {
331 EventLogger::createAsyncPel(
332 types::ErrorType::DbusFailure, types::SeverityType::Critical,
333 __FILE__, __FUNCTION__, 0,
334 std::string("Failed to disable BMC Reboot Guard while updating " +
335 l_keyWordIdentifier(i_paramsToWriteData)),
336 std::nullopt, std::nullopt, std::nullopt, std::nullopt);
337 }
338
339 return l_bytesUpdatedOnHardware;
340}
341
342} // namespace vpd