blob: 22cdc277681a870bc8e2fd5290dcbecbbc3f1cf9 [file] [log] [blame]
Matt Spinler711d51d2019-11-06 09:36:51 -06001/**
2 * Copyright © 2019 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
Matt Spinler367144c2019-09-19 15:33:52 -050016#include "registry.hpp"
17
18#include "pel_types.hpp"
19#include "pel_values.hpp"
20
21#include <fstream>
22#include <phosphor-logging/log.hpp>
23
24namespace openpower
25{
26namespace pels
27{
28namespace message
29{
30
31namespace pv = pel_values;
32namespace fs = std::filesystem;
33using namespace phosphor::logging;
34
35constexpr auto debugFilePath = "/etc/phosphor-logging/";
36
37namespace helper
38{
39
40uint8_t getSubsystem(const std::string& subsystemName)
41{
42 // Get the actual value to use in the PEL for the string name
43 auto ss = pv::findByName(subsystemName, pv::subsystemValues);
44 if (ss == pv::subsystemValues.end())
45 {
46 // Schema validation should be catching this.
47 log<level::ERR>("Invalid subsystem name used in message registry",
48 entry("SUBSYSTEM=%s", subsystemName.c_str()));
49
50 throw std::runtime_error("Invalid subsystem used in message registry");
51 }
52
53 return std::get<pv::fieldValuePos>(*ss);
54}
55
56uint8_t getSeverity(const std::string& severityName)
57{
58 auto s = pv::findByName(severityName, pv::severityValues);
59 if (s == pv::severityValues.end())
60 {
61 // Schema validation should be catching this.
62 log<level::ERR>("Invalid severity name used in message registry",
63 entry("SEVERITY=%s", severityName.c_str()));
64
65 throw std::runtime_error("Invalid severity used in message registry");
66 }
67
68 return std::get<pv::fieldValuePos>(*s);
69}
70
Matt Spinleraadccc82020-04-10 14:33:42 -050071std::vector<RegistrySeverity> getSeverities(const nlohmann::json& severity)
72{
73 std::vector<RegistrySeverity> severities;
74
75 // The plain string value, like "unrecoverable"
76 if (severity.is_string())
77 {
78 RegistrySeverity s;
79 s.severity = getSeverity(severity.get<std::string>());
80 severities.push_back(std::move(s));
81 }
82 else
83 {
84 // An array, with an element like:
85 // {
86 // "SevValue": "unrecoverable",
87 // "System", "systemA"
88 // }
89 for (const auto& sev : severity)
90 {
91 RegistrySeverity s;
92 s.severity = getSeverity(sev["SevValue"].get<std::string>());
93
94 if (sev.contains("System"))
95 {
96 s.system = sev["System"].get<std::string>();
97 }
98
99 severities.push_back(std::move(s));
100 }
101 }
102
103 return severities;
104}
105
Matt Spinler367144c2019-09-19 15:33:52 -0500106uint16_t getActionFlags(const std::vector<std::string>& flags)
107{
108 uint16_t actionFlags = 0;
109
110 // Make the bitmask based on the array of flag names
111 for (const auto& flag : flags)
112 {
113 auto s = pv::findByName(flag, pv::actionFlagsValues);
114 if (s == pv::actionFlagsValues.end())
115 {
116 // Schema validation should be catching this.
117 log<level::ERR>("Invalid action flag name used in message registry",
118 entry("FLAG=%s", flag.c_str()));
119
120 throw std::runtime_error(
121 "Invalid action flag used in message registry");
122 }
123
124 actionFlags |= std::get<pv::fieldValuePos>(*s);
125 }
126
127 return actionFlags;
128}
129
130uint8_t getEventType(const std::string& eventTypeName)
131{
132 auto t = pv::findByName(eventTypeName, pv::eventTypeValues);
133 if (t == pv::eventTypeValues.end())
134 {
135 log<level::ERR>("Invalid event type used in message registry",
136 entry("EVENT_TYPE=%s", eventTypeName.c_str()));
137
138 throw std::runtime_error("Invalid event type used in message registry");
139 }
140 return std::get<pv::fieldValuePos>(*t);
141}
142
143uint8_t getEventScope(const std::string& eventScopeName)
144{
145 auto s = pv::findByName(eventScopeName, pv::eventScopeValues);
146 if (s == pv::eventScopeValues.end())
147 {
148 log<level::ERR>("Invalid event scope used in registry",
149 entry("EVENT_SCOPE=%s", eventScopeName.c_str()));
150
151 throw std::runtime_error(
152 "Invalid event scope used in message registry");
153 }
154 return std::get<pv::fieldValuePos>(*s);
155}
156
Matt Spinler93e29322019-09-20 11:16:15 -0500157uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name)
158{
159 std::string rc = src["ReasonCode"];
160 uint16_t reasonCode = strtoul(rc.c_str(), nullptr, 16);
161 if (reasonCode == 0)
162 {
163 log<phosphor::logging::level::ERR>(
164 "Invalid reason code in message registry",
165 entry("ERROR_NAME=%s", name.c_str()),
166 entry("REASON_CODE=%s", rc.c_str()));
167
168 throw std::runtime_error("Invalid reason code in message registry");
169 }
170 return reasonCode;
171}
172
173uint8_t getSRCType(const nlohmann::json& src, const std::string& name)
174{
175 // Looks like: "22"
176 std::string srcType = src["Type"];
177 size_t type = strtoul(srcType.c_str(), nullptr, 16);
178 if ((type == 0) || (srcType.size() != 2)) // 1 hex byte
179 {
180 log<phosphor::logging::level::ERR>(
181 "Invalid SRC Type in message registry",
182 entry("ERROR_NAME=%s", name.c_str()),
183 entry("SRC_TYPE=%s", srcType.c_str()));
184
185 throw std::runtime_error("Invalid SRC Type in message registry");
186 }
187
188 return type;
189}
190
191std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>>
192 getSRCHexwordFields(const nlohmann::json& src, const std::string& name)
193{
194 std::map<SRC::WordNum, SRC::AdditionalDataField> hexwordFields;
195
196 // Build the map of which AdditionalData fields to use for which SRC words
197
198 // Like:
199 // {
200 // "8":
201 // {
202 // "AdditionalDataPropSource": "TEST"
203 // }
204 //
205 // }
206
207 for (const auto& word : src["Words6To9"].items())
208 {
209 std::string num = word.key();
210 size_t wordNum = std::strtoul(num.c_str(), nullptr, 10);
211
212 if (wordNum == 0)
213 {
214 log<phosphor::logging::level::ERR>(
215 "Invalid SRC word number in message registry",
216 entry("ERROR_NAME=%s", name.c_str()),
217 entry("SRC_WORD_NUM=%s", num.c_str()));
218
219 throw std::runtime_error("Invalid SRC word in message registry");
220 }
221
222 auto attributes = word.value();
223 std::string adPropName = attributes["AdditionalDataPropSource"];
224 hexwordFields[wordNum] = std::move(adPropName);
225 }
226
227 if (!hexwordFields.empty())
228 {
229 return hexwordFields;
230 }
231
232 return std::nullopt;
233}
234std::optional<std::vector<SRC::WordNum>>
235 getSRCSymptomIDFields(const nlohmann::json& src, const std::string& name)
236{
237 std::vector<SRC::WordNum> symptomIDFields;
238
239 // Looks like:
240 // "SymptomIDFields": ["SRCWord3", "SRCWord6"],
241
242 for (const std::string& field : src["SymptomIDFields"])
243 {
244 // Just need the last digit off the end, e.g. SRCWord6.
245 // The schema enforces the format of these.
246 auto srcWordNum = field.substr(field.size() - 1);
247 size_t num = std::strtoul(srcWordNum.c_str(), nullptr, 10);
248 if (num == 0)
249 {
250 log<phosphor::logging::level::ERR>(
251 "Invalid symptom ID field in message registry",
252 entry("ERROR_NAME=%s", name.c_str()),
253 entry("FIELD_NAME=%s", srcWordNum.c_str()));
254
255 throw std::runtime_error("Invalid symptom ID in message registry");
256 }
257 symptomIDFields.push_back(num);
258 }
259 if (!symptomIDFields.empty())
260 {
261 return symptomIDFields;
262 }
263
264 return std::nullopt;
265}
266
267uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode,
268 const nlohmann::json& pelEntry, const std::string& name)
269{
270 uint16_t id = 0;
271
272 // If the ComponentID field is there, use that. Otherwise, if it's a
273 // 0xBD BMC error SRC, use the reasoncode.
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500274 if (pelEntry.contains("ComponentID"))
Matt Spinler93e29322019-09-20 11:16:15 -0500275 {
276 std::string componentID = pelEntry["ComponentID"];
277 id = strtoul(componentID.c_str(), nullptr, 16);
278 }
279 else
280 {
281 // On BMC error SRCs (BD), can just get the component ID from
282 // the first byte of the reason code.
283 if (srcType == static_cast<uint8_t>(SRCType::bmcError))
284 {
285 id = reasonCode & 0xFF00;
286 }
287 else
288 {
289 log<level::ERR>("Missing component ID field in message registry",
290 entry("ERROR_NAME=%s", name.c_str()));
291
292 throw std::runtime_error(
293 "Missing component ID field in message registry");
294 }
295 }
296
297 return id;
298}
299
Matt Spinler6b427cc2020-04-09 09:42:59 -0500300/**
301 * @brief Says if the JSON is the format that contains AdditionalData keys
302 * as in index into them.
303 *
304 * @param[in] json - The highest level callout JSON
305 *
306 * @return bool - If it is the AdditionalData format or not
307 */
308bool calloutUsesAdditionalData(const nlohmann::json& json)
309{
310 return (json.contains("ADName") &&
311 json.contains("CalloutsWithTheirADValues"));
312}
313
314/**
315 * @brief Finds the callouts to use when there is no AdditionalData,
316 * but the system type may be used as a key.
317 *
318 * One entry in the array looks like the following. The System key
319 * is optional and if not present it means that entry applies to
320 * every configuration that doesn't have another entry with a matching
321 * System key.
322 *
323 * {
324 * "System": "system1",
325 * "CalloutList":
326 * [
327 * {
328 * "Priority": "high",
329 * "LocCode": "P1-C1"
330 * },
331 * {
332 * "Priority": "low",
333 * "LocCode": "P1"
334 * }
335 * ]
336 * }
337 */
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500338const nlohmann::json&
339 findCalloutList(const nlohmann::json& json,
340 const std::vector<std::string>& systemNames)
Matt Spinler6b427cc2020-04-09 09:42:59 -0500341{
342 const nlohmann::json* callouts = nullptr;
343
344 if (!json.is_array())
345 {
346 throw std::runtime_error{"findCalloutList was not passed a JSON array"};
347 }
348
349 // The entry with the system type match will take precedence over the entry
350 // without any "System" field in it at all, which will match all other
351 // cases.
352 for (const auto& calloutList : json)
353 {
354 if (calloutList.contains("System"))
355 {
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500356 if (std::find(systemNames.begin(), systemNames.end(),
357 calloutList["System"].get<std::string>()) !=
358 systemNames.end())
Matt Spinler6b427cc2020-04-09 09:42:59 -0500359 {
360 callouts = &calloutList["CalloutList"];
361 break;
362 }
363 }
364 else
365 {
366 // Any entry with no System key
367 callouts = &calloutList["CalloutList"];
368 }
369 }
370
371 if (!callouts)
372 {
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500373 std::string types;
374 std::for_each(systemNames.begin(), systemNames.end(),
375 [&types](const auto& t) { types += t + '|'; });
Matt Spinler6b427cc2020-04-09 09:42:59 -0500376 log<level::WARNING>(
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500377 "No matching system name entry or default system name entry "
Matt Spinler6b427cc2020-04-09 09:42:59 -0500378 " for PEL callout list",
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500379 entry("SYSTEMNAMES=%s", types.c_str()));
Matt Spinler6b427cc2020-04-09 09:42:59 -0500380
381 throw std::runtime_error{
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500382 "Could not find a CalloutList JSON for this error and system name"};
Matt Spinler6b427cc2020-04-09 09:42:59 -0500383 }
384
385 return *callouts;
386}
387
388/**
389 * @brief Creates a RegistryCallout based on the input JSON.
390 *
391 * The JSON looks like:
392 * {
393 * "Priority": "high",
394 * "LocCode": "E1"
395 * ...
396 * }
397 *
398 * Schema validation enforces what keys are present.
399 *
400 * @param[in] json - The JSON dictionary entry for a callout
401 *
402 * @return RegistryCallout - A filled in RegistryCallout
403 */
404RegistryCallout makeRegistryCallout(const nlohmann::json& json)
405{
406 RegistryCallout callout;
407
408 callout.priority = "high";
409
410 if (json.contains("Priority"))
411 {
412 callout.priority = json["Priority"].get<std::string>();
413 }
414
415 if (json.contains("LocCode"))
416 {
417 callout.locCode = json["LocCode"].get<std::string>();
418 }
419
420 if (json.contains("Procedure"))
421 {
422 callout.procedure = json["Procedure"].get<std::string>();
423 }
424 else if (json.contains("SymbolicFRU"))
425 {
426 callout.symbolicFRU = json["SymbolicFRU"].get<std::string>();
427 }
428 else if (json.contains("SymbolicFRUTrusted"))
429 {
430 callout.symbolicFRUTrusted =
431 json["SymbolicFRUTrusted"].get<std::string>();
432 }
433
434 return callout;
435}
436
437/**
438 * @brief Returns the callouts to use when an AdditionalData key is
439 * required to find the correct entries.
440 *
441 * The System property is used to find which CalloutList to use.
442 * If System is missing, then that CalloutList is valid for
443 * everything.
444 *
445 * The JSON looks like:
446 * [
447 * {
448 * "System": "systemA",
449 * "CalloutList":
450 * [
451 * {
452 * "Priority": "high",
453 * "LocCode": "P1-C5"
454 * }
455 * ]
456 * }
457 * ]
458 *
459 * @param[in] json - The callout JSON
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500460 * @param[in] systemNames - List of compatible system type names
Matt Spinler6b427cc2020-04-09 09:42:59 -0500461 *
462 * @return std::vector<RegistryCallout> - The callouts to use
463 */
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500464std::vector<RegistryCallout>
465 getCalloutsWithoutAD(const nlohmann::json& json,
466 const std::vector<std::string>& systemNames)
Matt Spinler6b427cc2020-04-09 09:42:59 -0500467{
468 std::vector<RegistryCallout> calloutEntries;
469
470 // Find the CalloutList to use based on the system type
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500471 const auto& calloutList = findCalloutList(json, systemNames);
Matt Spinler6b427cc2020-04-09 09:42:59 -0500472
473 // We finally found the callouts, make the objects.
474 for (const auto& callout : calloutList)
475 {
476 calloutEntries.push_back(std::move(makeRegistryCallout(callout)));
477 }
478
479 return calloutEntries;
480}
481
482/**
483 * @brief Returns the callouts to use when an AdditionalData key is
484 * required to find the correct entries.
485 *
486 * The JSON looks like:
487 * {
488 * "ADName": "PROC_NUM",
489 * "CalloutsWithTheirADValues":
490 * [
491 * {
492 * "ADValue": "0",
493 * "Callouts":
494 * [
495 * {
496 * "CalloutList":
497 * [
498 * {
499 * "Priority": "high",
500 * "LocCode": "P1-C5"
501 * }
502 * ]
503 * }
504 * ]
505 * }
506 * ]
507 * }
508 *
509 * Note that the "Callouts" entry above is the same as the top level
510 * entry used when there is no AdditionalData key.
511 *
512 * @param[in] json - The callout JSON
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500513 * @param[in] systemNames - List of compatible system type names
Matt Spinler6b427cc2020-04-09 09:42:59 -0500514 * @param[in] additionalData - The AdditionalData property
515 *
516 * @return std::vector<RegistryCallout> - The callouts to use
517 */
518std::vector<RegistryCallout>
519 getCalloutsUsingAD(const nlohmann::json& json,
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500520 const std::vector<std::string>& systemNames,
Matt Spinler6b427cc2020-04-09 09:42:59 -0500521 const AdditionalData& additionalData)
522{
523 // This indicates which AD field we'll be using
524 auto keyName = json["ADName"].get<std::string>();
525
526 // Get the actual value from the AD data
527 auto adValue = additionalData.getValue(keyName);
528
529 if (!adValue)
530 {
531 // The AdditionalData did not contain the necessary key
532 log<level::WARNING>(
533 "The PEL message registry callouts JSON "
534 "said to use an AdditionalData key that isn't in the "
535 "AdditionalData event log property",
536 entry("ADNAME=%s\n", keyName.c_str()));
537 throw std::runtime_error{
538 "Missing AdditionalData entry for this callout"};
539 }
540
541 const auto& callouts = json["CalloutsWithTheirADValues"];
542
543 // find the entry with that AD value
544 auto it = std::find_if(
545 callouts.begin(), callouts.end(), [adValue](const nlohmann::json& j) {
546 return *adValue == j["ADValue"].get<std::string>();
547 });
548
549 if (it == callouts.end())
550 {
551 log<level::WARNING>(
552 "No callout entry found for the AdditionalData value used",
553 entry("AD_VALUE=%s", adValue->c_str()));
554
555 throw std::runtime_error{
556 "No callout entry found for the AdditionalData value used"};
557 }
558
559 // Proceed to find the callouts possibly based on system type.
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500560 return getCalloutsWithoutAD((*it)["Callouts"], systemNames);
Matt Spinler6b427cc2020-04-09 09:42:59 -0500561}
562
Matt Spinler367144c2019-09-19 15:33:52 -0500563} // namespace helper
564
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800565std::optional<Entry> Registry::lookup(const std::string& name, LookupType type,
566 bool toCache)
Matt Spinler367144c2019-09-19 15:33:52 -0500567{
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800568 std::optional<nlohmann::json> registryTmp;
569 auto& registryOpt = (_registry) ? _registry : registryTmp;
570 if (!registryOpt)
Matt Spinler367144c2019-09-19 15:33:52 -0500571 {
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800572 registryOpt = readRegistry(_registryFile);
573 if (!registryOpt)
574 {
575 return std::nullopt;
576 }
577 else if (toCache)
578 {
579 // Save message registry in memory for peltool
580 _registry = std::move(registryTmp);
581 }
Matt Spinler367144c2019-09-19 15:33:52 -0500582 }
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800583 auto& reg = (_registry) ? _registry : registryTmp;
584 const auto& registry = reg.value();
Matt Spinler367144c2019-09-19 15:33:52 -0500585 // Find an entry with this name in the PEL array.
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800586 auto e = std::find_if(
587 registry["PELs"].begin(), registry["PELs"].end(),
588 [&name, &type](const auto& j) {
589 return ((name == j["Name"] && type == LookupType::name) ||
590 (name == j["SRC"]["ReasonCode"] &&
591 type == LookupType::reasonCode));
592 });
Matt Spinler367144c2019-09-19 15:33:52 -0500593
594 if (e != registry["PELs"].end())
595 {
596 // Fill in the Entry structure from the JSON. Most, but not all, fields
597 // are optional.
598
599 try
600 {
601 Entry entry;
602 entry.name = (*e)["Name"];
603 entry.subsystem = helper::getSubsystem((*e)["Subsystem"]);
Matt Spinlere07f9152019-11-01 10:48:36 -0500604
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500605 if (e->contains("ActionFlags"))
Matt Spinlere07f9152019-11-01 10:48:36 -0500606 {
607 entry.actionFlags = helper::getActionFlags((*e)["ActionFlags"]);
608 }
Matt Spinler367144c2019-09-19 15:33:52 -0500609
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500610 if (e->contains("MfgActionFlags"))
Matt Spinler367144c2019-09-19 15:33:52 -0500611 {
612 entry.mfgActionFlags =
613 helper::getActionFlags((*e)["MfgActionFlags"]);
614 }
615
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500616 if (e->contains("Severity"))
Matt Spinler367144c2019-09-19 15:33:52 -0500617 {
Matt Spinleraadccc82020-04-10 14:33:42 -0500618 entry.severity = helper::getSeverities((*e)["Severity"]);
Matt Spinler367144c2019-09-19 15:33:52 -0500619 }
620
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500621 if (e->contains("MfgSeverity"))
Matt Spinler367144c2019-09-19 15:33:52 -0500622 {
Matt Spinleraadccc82020-04-10 14:33:42 -0500623 entry.mfgSeverity = helper::getSeverities((*e)["MfgSeverity"]);
Matt Spinler367144c2019-09-19 15:33:52 -0500624 }
625
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500626 if (e->contains("EventType"))
Matt Spinler367144c2019-09-19 15:33:52 -0500627 {
628 entry.eventType = helper::getEventType((*e)["EventType"]);
629 }
630
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500631 if (e->contains("EventScope"))
Matt Spinler367144c2019-09-19 15:33:52 -0500632 {
633 entry.eventScope = helper::getEventScope((*e)["EventScope"]);
634 }
635
Matt Spinler93e29322019-09-20 11:16:15 -0500636 auto& src = (*e)["SRC"];
637 entry.src.reasonCode = helper::getSRCReasonCode(src, name);
638
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500639 if (src.contains("Type"))
Matt Spinler93e29322019-09-20 11:16:15 -0500640 {
641 entry.src.type = helper::getSRCType(src, name);
642 }
643 else
644 {
645 entry.src.type = static_cast<uint8_t>(SRCType::bmcError);
646 }
647
648 // Now that we know the SRC type and reason code,
649 // we can get the component ID.
650 entry.componentID = helper::getComponentID(
651 entry.src.type, entry.src.reasonCode, *e, name);
652
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500653 if (src.contains("Words6To9"))
Matt Spinler93e29322019-09-20 11:16:15 -0500654 {
655 entry.src.hexwordADFields =
656 helper::getSRCHexwordFields(src, name);
657 }
658
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500659 if (src.contains("SymptomIDFields"))
Matt Spinler93e29322019-09-20 11:16:15 -0500660 {
661 entry.src.symptomID = helper::getSRCSymptomIDFields(src, name);
662 }
663
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500664 if (src.contains("PowerFault"))
Matt Spinler93e29322019-09-20 11:16:15 -0500665 {
666 entry.src.powerFault = src["PowerFault"];
667 }
Matt Spinler367144c2019-09-19 15:33:52 -0500668
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800669 auto& doc = (*e)["Documentation"];
670 entry.doc.message = doc["Message"];
671 entry.doc.description = doc["Description"];
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500672 if (doc.contains("MessageArgSources"))
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800673 {
674 entry.doc.messageArgSources = doc["MessageArgSources"];
675 }
676
Matt Spinlerd8e29002020-04-09 09:11:22 -0500677 // If there are callouts defined, save the JSON for later
678 if (_loadCallouts)
679 {
680 if (e->contains("Callouts"))
681 {
682 entry.callouts = (*e)["Callouts"];
683 }
684 else if (e->contains("CalloutsUsingAD"))
685 {
686 entry.callouts = (*e)["CalloutsUsingAD"];
687 }
688 }
689
Matt Spinler367144c2019-09-19 15:33:52 -0500690 return entry;
691 }
692 catch (std::exception& e)
693 {
694 log<level::ERR>("Found invalid message registry field",
695 entry("ERROR=%s", e.what()));
696 }
697 }
698
699 return std::nullopt;
700}
701
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800702std::optional<nlohmann::json>
703 Registry::readRegistry(const std::filesystem::path& registryFile)
704{
705 // Look in /etc first in case someone put a test file there
706 fs::path debugFile{fs::path{debugFilePath} / registryFileName};
707 nlohmann::json registry;
708 std::ifstream file;
709
710 if (fs::exists(debugFile))
711 {
712 log<level::INFO>("Using debug PEL message registry");
713 file.open(debugFile);
714 }
715 else
716 {
717 file.open(registryFile);
718 }
719
720 try
721 {
722 registry = nlohmann::json::parse(file);
723 }
724 catch (std::exception& e)
725 {
726 log<level::ERR>("Error parsing message registry JSON",
727 entry("JSON_ERROR=%s", e.what()));
728 return std::nullopt;
729 }
730 return registry;
731}
732
Matt Spinler6b427cc2020-04-09 09:42:59 -0500733std::vector<RegistryCallout>
734 Registry::getCallouts(const nlohmann::json& calloutJSON,
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500735 const std::vector<std::string>& systemNames,
Matt Spinler6b427cc2020-04-09 09:42:59 -0500736 const AdditionalData& additionalData)
737{
738 // The JSON may either use an AdditionalData key
739 // as an index, or not.
740 if (helper::calloutUsesAdditionalData(calloutJSON))
741 {
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500742 return helper::getCalloutsUsingAD(calloutJSON, systemNames,
Matt Spinler6b427cc2020-04-09 09:42:59 -0500743 additionalData);
744 }
745
Matt Spinler6ea4d5f2020-05-20 13:31:07 -0500746 return helper::getCalloutsWithoutAD(calloutJSON, systemNames);
Matt Spinler6b427cc2020-04-09 09:42:59 -0500747}
748
Matt Spinler367144c2019-09-19 15:33:52 -0500749} // namespace message
750} // namespace pels
751} // namespace openpower