blob: 9b2262d9b292cc48d8622883c2d0565537bdb800 [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 */
338const nlohmann::json& findCalloutList(const nlohmann::json& json,
339 const std::string& systemType)
340{
341 const nlohmann::json* callouts = nullptr;
342
343 if (!json.is_array())
344 {
345 throw std::runtime_error{"findCalloutList was not passed a JSON array"};
346 }
347
348 // The entry with the system type match will take precedence over the entry
349 // without any "System" field in it at all, which will match all other
350 // cases.
351 for (const auto& calloutList : json)
352 {
353 if (calloutList.contains("System"))
354 {
355 if (systemType == calloutList["System"].get<std::string>())
356 {
357 callouts = &calloutList["CalloutList"];
358 break;
359 }
360 }
361 else
362 {
363 // Any entry with no System key
364 callouts = &calloutList["CalloutList"];
365 }
366 }
367
368 if (!callouts)
369 {
370 log<level::WARNING>(
371 "No matching system type entry or default system type entry "
372 " for PEL callout list",
373 entry("SYSTEMTYPE=%s", systemType.c_str()));
374
375 throw std::runtime_error{
376 "Could not find a CalloutList JSON for this error and system type"};
377 }
378
379 return *callouts;
380}
381
382/**
383 * @brief Creates a RegistryCallout based on the input JSON.
384 *
385 * The JSON looks like:
386 * {
387 * "Priority": "high",
388 * "LocCode": "E1"
389 * ...
390 * }
391 *
392 * Schema validation enforces what keys are present.
393 *
394 * @param[in] json - The JSON dictionary entry for a callout
395 *
396 * @return RegistryCallout - A filled in RegistryCallout
397 */
398RegistryCallout makeRegistryCallout(const nlohmann::json& json)
399{
400 RegistryCallout callout;
401
402 callout.priority = "high";
403
404 if (json.contains("Priority"))
405 {
406 callout.priority = json["Priority"].get<std::string>();
407 }
408
409 if (json.contains("LocCode"))
410 {
411 callout.locCode = json["LocCode"].get<std::string>();
412 }
413
414 if (json.contains("Procedure"))
415 {
416 callout.procedure = json["Procedure"].get<std::string>();
417 }
418 else if (json.contains("SymbolicFRU"))
419 {
420 callout.symbolicFRU = json["SymbolicFRU"].get<std::string>();
421 }
422 else if (json.contains("SymbolicFRUTrusted"))
423 {
424 callout.symbolicFRUTrusted =
425 json["SymbolicFRUTrusted"].get<std::string>();
426 }
427
428 return callout;
429}
430
431/**
432 * @brief Returns the callouts to use when an AdditionalData key is
433 * required to find the correct entries.
434 *
435 * The System property is used to find which CalloutList to use.
436 * If System is missing, then that CalloutList is valid for
437 * everything.
438 *
439 * The JSON looks like:
440 * [
441 * {
442 * "System": "systemA",
443 * "CalloutList":
444 * [
445 * {
446 * "Priority": "high",
447 * "LocCode": "P1-C5"
448 * }
449 * ]
450 * }
451 * ]
452 *
453 * @param[in] json - The callout JSON
454 * @param[in] systemType - The system type from EntityManager
455 *
456 * @return std::vector<RegistryCallout> - The callouts to use
457 */
458std::vector<RegistryCallout> getCalloutsWithoutAD(const nlohmann::json& json,
459 const std::string& systemType)
460{
461 std::vector<RegistryCallout> calloutEntries;
462
463 // Find the CalloutList to use based on the system type
464 const auto& calloutList = findCalloutList(json, systemType);
465
466 // We finally found the callouts, make the objects.
467 for (const auto& callout : calloutList)
468 {
469 calloutEntries.push_back(std::move(makeRegistryCallout(callout)));
470 }
471
472 return calloutEntries;
473}
474
475/**
476 * @brief Returns the callouts to use when an AdditionalData key is
477 * required to find the correct entries.
478 *
479 * The JSON looks like:
480 * {
481 * "ADName": "PROC_NUM",
482 * "CalloutsWithTheirADValues":
483 * [
484 * {
485 * "ADValue": "0",
486 * "Callouts":
487 * [
488 * {
489 * "CalloutList":
490 * [
491 * {
492 * "Priority": "high",
493 * "LocCode": "P1-C5"
494 * }
495 * ]
496 * }
497 * ]
498 * }
499 * ]
500 * }
501 *
502 * Note that the "Callouts" entry above is the same as the top level
503 * entry used when there is no AdditionalData key.
504 *
505 * @param[in] json - The callout JSON
506 * @param[in] systemType - The system type from EntityManager
507 * @param[in] additionalData - The AdditionalData property
508 *
509 * @return std::vector<RegistryCallout> - The callouts to use
510 */
511std::vector<RegistryCallout>
512 getCalloutsUsingAD(const nlohmann::json& json,
513 const std::string& systemType,
514 const AdditionalData& additionalData)
515{
516 // This indicates which AD field we'll be using
517 auto keyName = json["ADName"].get<std::string>();
518
519 // Get the actual value from the AD data
520 auto adValue = additionalData.getValue(keyName);
521
522 if (!adValue)
523 {
524 // The AdditionalData did not contain the necessary key
525 log<level::WARNING>(
526 "The PEL message registry callouts JSON "
527 "said to use an AdditionalData key that isn't in the "
528 "AdditionalData event log property",
529 entry("ADNAME=%s\n", keyName.c_str()));
530 throw std::runtime_error{
531 "Missing AdditionalData entry for this callout"};
532 }
533
534 const auto& callouts = json["CalloutsWithTheirADValues"];
535
536 // find the entry with that AD value
537 auto it = std::find_if(
538 callouts.begin(), callouts.end(), [adValue](const nlohmann::json& j) {
539 return *adValue == j["ADValue"].get<std::string>();
540 });
541
542 if (it == callouts.end())
543 {
544 log<level::WARNING>(
545 "No callout entry found for the AdditionalData value used",
546 entry("AD_VALUE=%s", adValue->c_str()));
547
548 throw std::runtime_error{
549 "No callout entry found for the AdditionalData value used"};
550 }
551
552 // Proceed to find the callouts possibly based on system type.
553 return getCalloutsWithoutAD((*it)["Callouts"], systemType);
554}
555
Matt Spinler367144c2019-09-19 15:33:52 -0500556} // namespace helper
557
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800558std::optional<Entry> Registry::lookup(const std::string& name, LookupType type,
559 bool toCache)
Matt Spinler367144c2019-09-19 15:33:52 -0500560{
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800561 std::optional<nlohmann::json> registryTmp;
562 auto& registryOpt = (_registry) ? _registry : registryTmp;
563 if (!registryOpt)
Matt Spinler367144c2019-09-19 15:33:52 -0500564 {
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800565 registryOpt = readRegistry(_registryFile);
566 if (!registryOpt)
567 {
568 return std::nullopt;
569 }
570 else if (toCache)
571 {
572 // Save message registry in memory for peltool
573 _registry = std::move(registryTmp);
574 }
Matt Spinler367144c2019-09-19 15:33:52 -0500575 }
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800576 auto& reg = (_registry) ? _registry : registryTmp;
577 const auto& registry = reg.value();
Matt Spinler367144c2019-09-19 15:33:52 -0500578 // Find an entry with this name in the PEL array.
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800579 auto e = std::find_if(
580 registry["PELs"].begin(), registry["PELs"].end(),
581 [&name, &type](const auto& j) {
582 return ((name == j["Name"] && type == LookupType::name) ||
583 (name == j["SRC"]["ReasonCode"] &&
584 type == LookupType::reasonCode));
585 });
Matt Spinler367144c2019-09-19 15:33:52 -0500586
587 if (e != registry["PELs"].end())
588 {
589 // Fill in the Entry structure from the JSON. Most, but not all, fields
590 // are optional.
591
592 try
593 {
594 Entry entry;
595 entry.name = (*e)["Name"];
596 entry.subsystem = helper::getSubsystem((*e)["Subsystem"]);
Matt Spinlere07f9152019-11-01 10:48:36 -0500597
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500598 if (e->contains("ActionFlags"))
Matt Spinlere07f9152019-11-01 10:48:36 -0500599 {
600 entry.actionFlags = helper::getActionFlags((*e)["ActionFlags"]);
601 }
Matt Spinler367144c2019-09-19 15:33:52 -0500602
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500603 if (e->contains("MfgActionFlags"))
Matt Spinler367144c2019-09-19 15:33:52 -0500604 {
605 entry.mfgActionFlags =
606 helper::getActionFlags((*e)["MfgActionFlags"]);
607 }
608
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500609 if (e->contains("Severity"))
Matt Spinler367144c2019-09-19 15:33:52 -0500610 {
Matt Spinleraadccc82020-04-10 14:33:42 -0500611 entry.severity = helper::getSeverities((*e)["Severity"]);
Matt Spinler367144c2019-09-19 15:33:52 -0500612 }
613
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500614 if (e->contains("MfgSeverity"))
Matt Spinler367144c2019-09-19 15:33:52 -0500615 {
Matt Spinleraadccc82020-04-10 14:33:42 -0500616 entry.mfgSeverity = helper::getSeverities((*e)["MfgSeverity"]);
Matt Spinler367144c2019-09-19 15:33:52 -0500617 }
618
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500619 if (e->contains("EventType"))
Matt Spinler367144c2019-09-19 15:33:52 -0500620 {
621 entry.eventType = helper::getEventType((*e)["EventType"]);
622 }
623
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500624 if (e->contains("EventScope"))
Matt Spinler367144c2019-09-19 15:33:52 -0500625 {
626 entry.eventScope = helper::getEventScope((*e)["EventScope"]);
627 }
628
Matt Spinler93e29322019-09-20 11:16:15 -0500629 auto& src = (*e)["SRC"];
630 entry.src.reasonCode = helper::getSRCReasonCode(src, name);
631
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500632 if (src.contains("Type"))
Matt Spinler93e29322019-09-20 11:16:15 -0500633 {
634 entry.src.type = helper::getSRCType(src, name);
635 }
636 else
637 {
638 entry.src.type = static_cast<uint8_t>(SRCType::bmcError);
639 }
640
641 // Now that we know the SRC type and reason code,
642 // we can get the component ID.
643 entry.componentID = helper::getComponentID(
644 entry.src.type, entry.src.reasonCode, *e, name);
645
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500646 if (src.contains("Words6To9"))
Matt Spinler93e29322019-09-20 11:16:15 -0500647 {
648 entry.src.hexwordADFields =
649 helper::getSRCHexwordFields(src, name);
650 }
651
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500652 if (src.contains("SymptomIDFields"))
Matt Spinler93e29322019-09-20 11:16:15 -0500653 {
654 entry.src.symptomID = helper::getSRCSymptomIDFields(src, name);
655 }
656
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500657 if (src.contains("PowerFault"))
Matt Spinler93e29322019-09-20 11:16:15 -0500658 {
659 entry.src.powerFault = src["PowerFault"];
660 }
Matt Spinler367144c2019-09-19 15:33:52 -0500661
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800662 auto& doc = (*e)["Documentation"];
663 entry.doc.message = doc["Message"];
664 entry.doc.description = doc["Description"];
Matt Spinler3ace0cf2020-04-09 15:16:57 -0500665 if (doc.contains("MessageArgSources"))
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800666 {
667 entry.doc.messageArgSources = doc["MessageArgSources"];
668 }
669
Matt Spinlerd8e29002020-04-09 09:11:22 -0500670 // If there are callouts defined, save the JSON for later
671 if (_loadCallouts)
672 {
673 if (e->contains("Callouts"))
674 {
675 entry.callouts = (*e)["Callouts"];
676 }
677 else if (e->contains("CalloutsUsingAD"))
678 {
679 entry.callouts = (*e)["CalloutsUsingAD"];
680 }
681 }
682
Matt Spinler367144c2019-09-19 15:33:52 -0500683 return entry;
684 }
685 catch (std::exception& e)
686 {
687 log<level::ERR>("Found invalid message registry field",
688 entry("ERROR=%s", e.what()));
689 }
690 }
691
692 return std::nullopt;
693}
694
Harisuddin Mohamed Isa0f717e12020-01-15 20:05:33 +0800695std::optional<nlohmann::json>
696 Registry::readRegistry(const std::filesystem::path& registryFile)
697{
698 // Look in /etc first in case someone put a test file there
699 fs::path debugFile{fs::path{debugFilePath} / registryFileName};
700 nlohmann::json registry;
701 std::ifstream file;
702
703 if (fs::exists(debugFile))
704 {
705 log<level::INFO>("Using debug PEL message registry");
706 file.open(debugFile);
707 }
708 else
709 {
710 file.open(registryFile);
711 }
712
713 try
714 {
715 registry = nlohmann::json::parse(file);
716 }
717 catch (std::exception& e)
718 {
719 log<level::ERR>("Error parsing message registry JSON",
720 entry("JSON_ERROR=%s", e.what()));
721 return std::nullopt;
722 }
723 return registry;
724}
725
Matt Spinler6b427cc2020-04-09 09:42:59 -0500726std::vector<RegistryCallout>
727 Registry::getCallouts(const nlohmann::json& calloutJSON,
728 const std::string& systemType,
729 const AdditionalData& additionalData)
730{
731 // The JSON may either use an AdditionalData key
732 // as an index, or not.
733 if (helper::calloutUsesAdditionalData(calloutJSON))
734 {
735 return helper::getCalloutsUsingAD(calloutJSON, systemType,
736 additionalData);
737 }
738
739 return helper::getCalloutsWithoutAD(calloutJSON, systemType);
740}
741
Matt Spinler367144c2019-09-19 15:33:52 -0500742} // namespace message
743} // namespace pels
744} // namespace openpower