| Matt Spinler | 711d51d | 2019-11-06 09:36:51 -0600 | [diff] [blame] | 1 | /** | 
 | 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 Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 16 | #include "registry.hpp" | 
 | 17 |  | 
 | 18 | #include "pel_types.hpp" | 
 | 19 | #include "pel_values.hpp" | 
 | 20 |  | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 21 | #include <phosphor-logging/lg2.hpp> | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 22 |  | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 23 | #include <algorithm> | 
| Patrick Williams | 2544b41 | 2022-10-04 08:41:06 -0500 | [diff] [blame] | 24 | #include <fstream> | 
 | 25 |  | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 26 | namespace openpower | 
 | 27 | { | 
 | 28 | namespace pels | 
 | 29 | { | 
 | 30 | namespace message | 
 | 31 | { | 
 | 32 |  | 
 | 33 | namespace pv = pel_values; | 
 | 34 | namespace fs = std::filesystem; | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 35 |  | 
 | 36 | constexpr auto debugFilePath = "/etc/phosphor-logging/"; | 
 | 37 |  | 
 | 38 | namespace helper | 
 | 39 | { | 
 | 40 |  | 
 | 41 | uint8_t getSubsystem(const std::string& subsystemName) | 
 | 42 | { | 
 | 43 |     // Get the actual value to use in the PEL for the string name | 
 | 44 |     auto ss = pv::findByName(subsystemName, pv::subsystemValues); | 
 | 45 |     if (ss == pv::subsystemValues.end()) | 
 | 46 |     { | 
 | 47 |         // Schema validation should be catching this. | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 48 |         lg2::error("Invalid subsystem name used in message registry: {SUBSYS}", | 
 | 49 |                    "SUBSYS", subsystemName); | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 50 |  | 
 | 51 |         throw std::runtime_error("Invalid subsystem used in message registry"); | 
 | 52 |     } | 
 | 53 |  | 
 | 54 |     return std::get<pv::fieldValuePos>(*ss); | 
 | 55 | } | 
 | 56 |  | 
 | 57 | uint8_t getSeverity(const std::string& severityName) | 
 | 58 | { | 
 | 59 |     auto s = pv::findByName(severityName, pv::severityValues); | 
 | 60 |     if (s == pv::severityValues.end()) | 
 | 61 |     { | 
 | 62 |         // Schema validation should be catching this. | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 63 |         lg2::error("Invalid severity name used in message registry: {SEV}", | 
 | 64 |                    "SEV", severityName); | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 65 |  | 
 | 66 |         throw std::runtime_error("Invalid severity used in message registry"); | 
 | 67 |     } | 
 | 68 |  | 
 | 69 |     return std::get<pv::fieldValuePos>(*s); | 
 | 70 | } | 
 | 71 |  | 
| Matt Spinler | aadccc8 | 2020-04-10 14:33:42 -0500 | [diff] [blame] | 72 | std::vector<RegistrySeverity> getSeverities(const nlohmann::json& severity) | 
 | 73 | { | 
 | 74 |     std::vector<RegistrySeverity> severities; | 
 | 75 |  | 
 | 76 |     // The plain string value, like "unrecoverable" | 
 | 77 |     if (severity.is_string()) | 
 | 78 |     { | 
 | 79 |         RegistrySeverity s; | 
 | 80 |         s.severity = getSeverity(severity.get<std::string>()); | 
 | 81 |         severities.push_back(std::move(s)); | 
 | 82 |     } | 
 | 83 |     else | 
 | 84 |     { | 
 | 85 |         // An array, with an element like: | 
 | 86 |         // { | 
 | 87 |         //    "SevValue": "unrecoverable", | 
 | 88 |         //    "System", "systemA" | 
 | 89 |         // } | 
 | 90 |         for (const auto& sev : severity) | 
 | 91 |         { | 
 | 92 |             RegistrySeverity s; | 
 | 93 |             s.severity = getSeverity(sev["SevValue"].get<std::string>()); | 
 | 94 |  | 
 | 95 |             if (sev.contains("System")) | 
 | 96 |             { | 
 | 97 |                 s.system = sev["System"].get<std::string>(); | 
 | 98 |             } | 
 | 99 |  | 
 | 100 |             severities.push_back(std::move(s)); | 
 | 101 |         } | 
 | 102 |     } | 
 | 103 |  | 
 | 104 |     return severities; | 
 | 105 | } | 
 | 106 |  | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 107 | uint16_t getActionFlags(const std::vector<std::string>& flags) | 
 | 108 | { | 
 | 109 |     uint16_t actionFlags = 0; | 
 | 110 |  | 
 | 111 |     // Make the bitmask based on the array of flag names | 
 | 112 |     for (const auto& flag : flags) | 
 | 113 |     { | 
 | 114 |         auto s = pv::findByName(flag, pv::actionFlagsValues); | 
 | 115 |         if (s == pv::actionFlagsValues.end()) | 
 | 116 |         { | 
 | 117 |             // Schema validation should be catching this. | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 118 |             lg2::error( | 
 | 119 |                 "Invalid action flag name used in message registry: {FLAG}", | 
 | 120 |                 "FLAG", flag); | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 121 |  | 
 | 122 |             throw std::runtime_error( | 
 | 123 |                 "Invalid action flag used in message registry"); | 
 | 124 |         } | 
 | 125 |  | 
 | 126 |         actionFlags |= std::get<pv::fieldValuePos>(*s); | 
 | 127 |     } | 
 | 128 |  | 
 | 129 |     return actionFlags; | 
 | 130 | } | 
 | 131 |  | 
 | 132 | uint8_t getEventType(const std::string& eventTypeName) | 
 | 133 | { | 
 | 134 |     auto t = pv::findByName(eventTypeName, pv::eventTypeValues); | 
 | 135 |     if (t == pv::eventTypeValues.end()) | 
 | 136 |     { | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 137 |         lg2::error("Invalid event type used in message registry: {TYPE}", | 
 | 138 |                    "TYPE", eventTypeName); | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 139 |  | 
 | 140 |         throw std::runtime_error("Invalid event type used in message registry"); | 
 | 141 |     } | 
 | 142 |     return std::get<pv::fieldValuePos>(*t); | 
 | 143 | } | 
 | 144 |  | 
 | 145 | uint8_t getEventScope(const std::string& eventScopeName) | 
 | 146 | { | 
 | 147 |     auto s = pv::findByName(eventScopeName, pv::eventScopeValues); | 
 | 148 |     if (s == pv::eventScopeValues.end()) | 
 | 149 |     { | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 150 |         lg2::error("Invalid event scope used in registry: {SCOPE}", "SCOPE", | 
 | 151 |                    eventScopeName); | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 152 |  | 
 | 153 |         throw std::runtime_error( | 
 | 154 |             "Invalid event scope used in message registry"); | 
 | 155 |     } | 
 | 156 |     return std::get<pv::fieldValuePos>(*s); | 
 | 157 | } | 
 | 158 |  | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 159 | uint16_t getSRCReasonCode(const nlohmann::json& src, const std::string& name) | 
 | 160 | { | 
 | 161 |     std::string rc = src["ReasonCode"]; | 
 | 162 |     uint16_t reasonCode = strtoul(rc.c_str(), nullptr, 16); | 
 | 163 |     if (reasonCode == 0) | 
 | 164 |     { | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 165 |         lg2::error( | 
 | 166 |             "Invalid reason code {RC} in message registry, error name = {ERROR}", | 
 | 167 |             "RC", rc, "ERROR", name); | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 168 |  | 
 | 169 |         throw std::runtime_error("Invalid reason code in message registry"); | 
 | 170 |     } | 
 | 171 |     return reasonCode; | 
 | 172 | } | 
 | 173 |  | 
 | 174 | uint8_t getSRCType(const nlohmann::json& src, const std::string& name) | 
 | 175 | { | 
 | 176 |     // Looks like: "22" | 
 | 177 |     std::string srcType = src["Type"]; | 
 | 178 |     size_t type = strtoul(srcType.c_str(), nullptr, 16); | 
 | 179 |     if ((type == 0) || (srcType.size() != 2)) // 1 hex byte | 
 | 180 |     { | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 181 |         lg2::error( | 
 | 182 |             "Invalid SRC Type {TYPE} in message registry, error name = {ERROR}", | 
 | 183 |             "TYPE", srcType, "ERROR", name); | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 184 |  | 
 | 185 |         throw std::runtime_error("Invalid SRC Type in message registry"); | 
 | 186 |     } | 
 | 187 |  | 
 | 188 |     return type; | 
 | 189 | } | 
 | 190 |  | 
| Matt Spinler | 3fe93e9 | 2023-04-14 14:06:59 -0500 | [diff] [blame] | 191 | bool getSRCDeconfigFlag(const nlohmann::json& src) | 
 | 192 | { | 
 | 193 |     return src["DeconfigFlag"].get<bool>(); | 
 | 194 | } | 
 | 195 |  | 
| Matt Spinler | da5b76b | 2023-06-01 15:56:57 -0500 | [diff] [blame] | 196 | bool getSRCCheckstopFlag(const nlohmann::json& src) | 
 | 197 | { | 
 | 198 |     return src["CheckstopFlag"].get<bool>(); | 
 | 199 | } | 
 | 200 |  | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 201 | std::optional<std::map<SRC::WordNum, SRC::AdditionalDataField>> | 
 | 202 |     getSRCHexwordFields(const nlohmann::json& src, const std::string& name) | 
 | 203 | { | 
 | 204 |     std::map<SRC::WordNum, SRC::AdditionalDataField> hexwordFields; | 
 | 205 |  | 
 | 206 |     // Build the map of which AdditionalData fields to use for which SRC words | 
 | 207 |  | 
 | 208 |     // Like: | 
 | 209 |     // { | 
 | 210 |     //   "8": | 
 | 211 |     //   { | 
 | 212 |     //     "AdditionalDataPropSource": "TEST" | 
 | 213 |     //   } | 
 | 214 |     // | 
 | 215 |     // } | 
 | 216 |  | 
 | 217 |     for (const auto& word : src["Words6To9"].items()) | 
 | 218 |     { | 
 | 219 |         std::string num = word.key(); | 
 | 220 |         size_t wordNum = std::strtoul(num.c_str(), nullptr, 10); | 
 | 221 |  | 
 | 222 |         if (wordNum == 0) | 
 | 223 |         { | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 224 |             lg2::error( | 
 | 225 |                 "Invalid SRC word number {NUM} in message registry, error name = {ERROR}", | 
 | 226 |                 "NUM", num, "ERROR", name); | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 227 |  | 
 | 228 |             throw std::runtime_error("Invalid SRC word in message registry"); | 
 | 229 |         } | 
 | 230 |  | 
 | 231 |         auto attributes = word.value(); | 
| Zane Shelley | e8db29b | 2021-11-13 10:34:07 -0600 | [diff] [blame] | 232 |  | 
 | 233 |         // Use an empty string for the description if it does not exist. | 
 | 234 |         auto itr = attributes.find("Description"); | 
 | 235 |         std::string desc = (attributes.end() != itr) ? *itr : ""; | 
 | 236 |  | 
| Harisuddin Mohamed Isa | 1a1b0df | 2020-11-23 16:34:36 +0800 | [diff] [blame] | 237 |         std::tuple<std::string, std::string> adPropSourceDesc( | 
| Zane Shelley | e8db29b | 2021-11-13 10:34:07 -0600 | [diff] [blame] | 238 |             attributes["AdditionalDataPropSource"], desc); | 
| Harisuddin Mohamed Isa | 1a1b0df | 2020-11-23 16:34:36 +0800 | [diff] [blame] | 239 |         hexwordFields[wordNum] = std::move(adPropSourceDesc); | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 240 |     } | 
 | 241 |  | 
 | 242 |     if (!hexwordFields.empty()) | 
 | 243 |     { | 
 | 244 |         return hexwordFields; | 
 | 245 |     } | 
 | 246 |  | 
 | 247 |     return std::nullopt; | 
 | 248 | } | 
| Patrick Williams | 2529115 | 2025-02-01 08:21:42 -0500 | [diff] [blame] | 249 | std::optional<std::vector<SRC::WordNum>> getSRCSymptomIDFields( | 
 | 250 |     const nlohmann::json& src, const std::string& name) | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 251 | { | 
 | 252 |     std::vector<SRC::WordNum> symptomIDFields; | 
 | 253 |  | 
 | 254 |     // Looks like: | 
 | 255 |     // "SymptomIDFields": ["SRCWord3", "SRCWord6"], | 
 | 256 |  | 
| Matt Spinler | 9d59d58 | 2021-05-19 07:57:10 -0600 | [diff] [blame] | 257 |     for (const std::string field : src["SymptomIDFields"]) | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 258 |     { | 
 | 259 |         // Just need the last digit off the end, e.g. SRCWord6. | 
 | 260 |         // The schema enforces the format of these. | 
 | 261 |         auto srcWordNum = field.substr(field.size() - 1); | 
 | 262 |         size_t num = std::strtoul(srcWordNum.c_str(), nullptr, 10); | 
 | 263 |         if (num == 0) | 
 | 264 |         { | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 265 |             lg2::error( | 
 | 266 |                 "Invalid symptom ID field {FIELD} in message registry, error name = {ERROR}", | 
 | 267 |                 "FIELD", field, "ERROR", name); | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 268 |  | 
 | 269 |             throw std::runtime_error("Invalid symptom ID in message registry"); | 
 | 270 |         } | 
 | 271 |         symptomIDFields.push_back(num); | 
 | 272 |     } | 
 | 273 |     if (!symptomIDFields.empty()) | 
 | 274 |     { | 
 | 275 |         return symptomIDFields; | 
 | 276 |     } | 
 | 277 |  | 
 | 278 |     return std::nullopt; | 
 | 279 | } | 
 | 280 |  | 
 | 281 | uint16_t getComponentID(uint8_t srcType, uint16_t reasonCode, | 
 | 282 |                         const nlohmann::json& pelEntry, const std::string& name) | 
 | 283 | { | 
 | 284 |     uint16_t id = 0; | 
 | 285 |  | 
 | 286 |     // If the ComponentID field is there, use that.  Otherwise, if it's a | 
 | 287 |     // 0xBD BMC error SRC, use the reasoncode. | 
| Matt Spinler | 3ace0cf | 2020-04-09 15:16:57 -0500 | [diff] [blame] | 288 |     if (pelEntry.contains("ComponentID")) | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 289 |     { | 
 | 290 |         std::string componentID = pelEntry["ComponentID"]; | 
 | 291 |         id = strtoul(componentID.c_str(), nullptr, 16); | 
 | 292 |     } | 
 | 293 |     else | 
 | 294 |     { | 
 | 295 |         // On BMC error SRCs (BD), can just get the component ID from | 
 | 296 |         // the first byte of the reason code. | 
 | 297 |         if (srcType == static_cast<uint8_t>(SRCType::bmcError)) | 
 | 298 |         { | 
 | 299 |             id = reasonCode & 0xFF00; | 
 | 300 |         } | 
 | 301 |         else | 
 | 302 |         { | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 303 |             lg2::error( | 
 | 304 |                 "Missing component ID field in message registry, error name = {ERROR}", | 
 | 305 |                 "ERROR", name); | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 306 |  | 
 | 307 |             throw std::runtime_error( | 
 | 308 |                 "Missing component ID field in message registry"); | 
 | 309 |         } | 
 | 310 |     } | 
 | 311 |  | 
 | 312 |     return id; | 
 | 313 | } | 
 | 314 |  | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 315 | /** | 
 | 316 |  * @brief Says if the JSON is the format that contains AdditionalData keys | 
 | 317 |  *        as in index into them. | 
 | 318 |  * | 
 | 319 |  * @param[in] json - The highest level callout JSON | 
 | 320 |  * | 
 | 321 |  * @return bool - If it is the AdditionalData format or not | 
 | 322 |  */ | 
 | 323 | bool calloutUsesAdditionalData(const nlohmann::json& json) | 
 | 324 | { | 
 | 325 |     return (json.contains("ADName") && | 
 | 326 |             json.contains("CalloutsWithTheirADValues")); | 
 | 327 | } | 
 | 328 |  | 
 | 329 | /** | 
 | 330 |  * @brief Finds the callouts to use when there is no AdditionalData, | 
 | 331 |  *        but the system type may be used as a key. | 
 | 332 |  * | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 333 |  * A sample calloutList array looks like the following.  The System and Systems | 
 | 334 |  * key are optional. | 
 | 335 |  * | 
 | 336 |  * System key - Value of the key will be the system name as a string. The | 
 | 337 |  * callouts for a specific system can define under this key. | 
 | 338 |  * | 
 | 339 |  * Systems key - Value of the key will be an array of system names in the form | 
 | 340 |  * of string. The callouts common to the systems mentioned in the array can | 
 | 341 |  * define under this key. | 
 | 342 |  * | 
 | 343 |  * If both System and Systems not present it means that entry applies to every | 
 | 344 |  * configuration that doesn't have another entry with a matching System and | 
 | 345 |  * Systems key. | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 346 |  * | 
 | 347 |  *    { | 
 | 348 |  *        "System": "system1", | 
 | 349 |  *        "CalloutList": | 
 | 350 |  *        [ | 
 | 351 |  *            { | 
 | 352 |  *                "Priority": "high", | 
 | 353 |  *                "LocCode": "P1-C1" | 
 | 354 |  *            }, | 
 | 355 |  *            { | 
 | 356 |  *                "Priority": "low", | 
 | 357 |  *                "LocCode": "P1" | 
 | 358 |  *            } | 
 | 359 |  *        ] | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 360 |  *    }, | 
 | 361 |  *    { | 
 | 362 |  *        "Systems": ["system1", 'system2"], | 
 | 363 |  *        "CalloutList": | 
 | 364 |  *        [ | 
 | 365 |  *            { | 
 | 366 |  *                "Priority": "high", | 
 | 367 |  *                "LocCode": "P0-C1" | 
 | 368 |  *            }, | 
 | 369 |  *            { | 
 | 370 |  *                "Priority": "low", | 
 | 371 |  *                "LocCode": "P0" | 
 | 372 |  *            } | 
 | 373 |  *        ] | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 374 |  *    } | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 375 |  * | 
 | 376 |  * @param[in] json - The callout JSON | 
 | 377 |  * @param[in] systemNames - List of compatible system type names | 
 | 378 |  * @param[out] calloutLists - The JSON array which will hold the calloutlist to | 
 | 379 |  * use specific to the system. | 
 | 380 |  * | 
 | 381 |  * @return - Throws runtime exception if json is not an array or if calloutLists | 
 | 382 |  *           is empty. | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 383 |  */ | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 384 | static void findCalloutList(const nlohmann::json& json, | 
 | 385 |                             const std::vector<std::string>& systemNames, | 
 | 386 |                             nlohmann::json& calloutLists) | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 387 | { | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 388 |     if (!json.is_array()) | 
 | 389 |     { | 
 | 390 |         throw std::runtime_error{"findCalloutList was not passed a JSON array"}; | 
 | 391 |     } | 
 | 392 |  | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 393 |     // Flag to indicate whether system specific callouts found or not | 
 | 394 |     bool foundCallouts = false; | 
 | 395 |  | 
 | 396 |     for (const auto& callouts : json) | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 397 |     { | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 398 |         if (callouts.contains("System")) | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 399 |         { | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 400 |             if (std::ranges::find(systemNames, | 
 | 401 |                                   callouts["System"].get<std::string>()) != | 
| Matt Spinler | 6ea4d5f | 2020-05-20 13:31:07 -0500 | [diff] [blame] | 402 |                 systemNames.end()) | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 403 |             { | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 404 |                 calloutLists.insert(calloutLists.end(), | 
 | 405 |                                     callouts["CalloutList"].begin(), | 
 | 406 |                                     callouts["CalloutList"].end()); | 
 | 407 |                 foundCallouts = true; | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 408 |             } | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 409 |             continue; | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 410 |         } | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 411 |  | 
 | 412 |         if (callouts.contains("Systems")) | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 413 |         { | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 414 |             std::vector<std::string> systems = | 
 | 415 |                 callouts["Systems"].get<std::vector<std::string>>(); | 
 | 416 |             auto inSystemNames = [systemNames](const auto& system) { | 
 | 417 |                 return (std::ranges::find(systemNames, system) != | 
 | 418 |                         systemNames.end()); | 
 | 419 |             }; | 
 | 420 |             if (std::ranges::any_of(systems, inSystemNames)) | 
 | 421 |             { | 
 | 422 |                 calloutLists.insert(calloutLists.end(), | 
 | 423 |                                     callouts["CalloutList"].begin(), | 
 | 424 |                                     callouts["CalloutList"].end()); | 
 | 425 |                 foundCallouts = true; | 
 | 426 |             } | 
 | 427 |             continue; | 
 | 428 |         } | 
 | 429 |  | 
 | 430 |         // Any entry if neither System/Systems key matches with system name | 
 | 431 |         if (!foundCallouts) | 
 | 432 |         { | 
 | 433 |             calloutLists.insert(calloutLists.end(), | 
 | 434 |                                 callouts["CalloutList"].begin(), | 
 | 435 |                                 callouts["CalloutList"].end()); | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 436 |         } | 
 | 437 |     } | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 438 |     if (calloutLists.empty()) | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 439 |     { | 
| Matt Spinler | 6ea4d5f | 2020-05-20 13:31:07 -0500 | [diff] [blame] | 440 |         std::string types; | 
 | 441 |         std::for_each(systemNames.begin(), systemNames.end(), | 
 | 442 |                       [&types](const auto& t) { types += t + '|'; }); | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 443 |         lg2::warning( | 
| Matt Spinler | 6ea4d5f | 2020-05-20 13:31:07 -0500 | [diff] [blame] | 444 |             "No matching system name entry or default system name entry " | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 445 |             " for PEL callout list, names = {TYPES}", | 
 | 446 |             "TYPES", types); | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 447 |  | 
 | 448 |         throw std::runtime_error{ | 
| Matt Spinler | 6ea4d5f | 2020-05-20 13:31:07 -0500 | [diff] [blame] | 449 |             "Could not find a CalloutList JSON for this error and system name"}; | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 450 |     } | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 451 | } | 
 | 452 |  | 
 | 453 | /** | 
 | 454 |  * @brief Creates a RegistryCallout based on the input JSON. | 
 | 455 |  * | 
 | 456 |  * The JSON looks like: | 
 | 457 |  *     { | 
 | 458 |  *          "Priority": "high", | 
 | 459 |  *          "LocCode": "E1" | 
 | 460 |  *          ... | 
 | 461 |  *     } | 
 | 462 |  * | 
 | 463 |  * Schema validation enforces what keys are present. | 
 | 464 |  * | 
 | 465 |  * @param[in] json - The JSON dictionary entry for a callout | 
 | 466 |  * | 
 | 467 |  * @return RegistryCallout - A filled in RegistryCallout | 
 | 468 |  */ | 
 | 469 | RegistryCallout makeRegistryCallout(const nlohmann::json& json) | 
 | 470 | { | 
 | 471 |     RegistryCallout callout; | 
 | 472 |  | 
 | 473 |     callout.priority = "high"; | 
| Matt Spinler | f00f9d0 | 2020-10-23 09:14:22 -0500 | [diff] [blame] | 474 |     callout.useInventoryLocCode = false; | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 475 |  | 
 | 476 |     if (json.contains("Priority")) | 
 | 477 |     { | 
 | 478 |         callout.priority = json["Priority"].get<std::string>(); | 
 | 479 |     } | 
 | 480 |  | 
 | 481 |     if (json.contains("LocCode")) | 
 | 482 |     { | 
 | 483 |         callout.locCode = json["LocCode"].get<std::string>(); | 
 | 484 |     } | 
 | 485 |  | 
 | 486 |     if (json.contains("Procedure")) | 
 | 487 |     { | 
 | 488 |         callout.procedure = json["Procedure"].get<std::string>(); | 
 | 489 |     } | 
 | 490 |     else if (json.contains("SymbolicFRU")) | 
 | 491 |     { | 
 | 492 |         callout.symbolicFRU = json["SymbolicFRU"].get<std::string>(); | 
 | 493 |     } | 
 | 494 |     else if (json.contains("SymbolicFRUTrusted")) | 
 | 495 |     { | 
 | 496 |         callout.symbolicFRUTrusted = | 
 | 497 |             json["SymbolicFRUTrusted"].get<std::string>(); | 
 | 498 |     } | 
 | 499 |  | 
| Matt Spinler | f00f9d0 | 2020-10-23 09:14:22 -0500 | [diff] [blame] | 500 |     if (json.contains("UseInventoryLocCode")) | 
 | 501 |     { | 
 | 502 |         callout.useInventoryLocCode = json["UseInventoryLocCode"].get<bool>(); | 
 | 503 |     } | 
 | 504 |  | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 505 |     return callout; | 
 | 506 | } | 
 | 507 |  | 
 | 508 | /** | 
 | 509 |  * @brief Returns the callouts to use when an AdditionalData key is | 
 | 510 |  *        required to find the correct entries. | 
 | 511 |  * | 
 | 512 |  *       The System property is used to find which CalloutList to use. | 
 | 513 |  *       If System is missing, then that CalloutList is valid for | 
 | 514 |  *       everything. | 
 | 515 |  * | 
 | 516 |  * The JSON looks like: | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 517 |  *    { | 
 | 518 |  *        "System": "system1", | 
 | 519 |  *        "CalloutList": | 
 | 520 |  *        [ | 
 | 521 |  *            { | 
 | 522 |  *                "Priority": "high", | 
 | 523 |  *                "LocCode": "P1-C1" | 
 | 524 |  *            }, | 
 | 525 |  *            { | 
 | 526 |  *                "Priority": "low", | 
 | 527 |  *                "LocCode": "P1" | 
 | 528 |  *            } | 
 | 529 |  *        ] | 
 | 530 |  *    }, | 
 | 531 |  *    { | 
 | 532 |  *        "Systems": ["system1", 'system2"], | 
 | 533 |  *        "CalloutList": | 
 | 534 |  *        [ | 
 | 535 |  *            { | 
 | 536 |  *                "Priority": "high", | 
 | 537 |  *                "LocCode": "P0-C1" | 
 | 538 |  *            }, | 
 | 539 |  *            { | 
 | 540 |  *                "Priority": "low", | 
 | 541 |  *                "LocCode": "P0" | 
 | 542 |  *            } | 
 | 543 |  *        ] | 
 | 544 |  *    } | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 545 |  * | 
 | 546 |  * @param[in] json - The callout JSON | 
| Matt Spinler | 6ea4d5f | 2020-05-20 13:31:07 -0500 | [diff] [blame] | 547 |  * @param[in] systemNames - List of compatible system type names | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 548 |  * | 
 | 549 |  * @return std::vector<RegistryCallout> - The callouts to use | 
 | 550 |  */ | 
| Patrick Williams | 075c792 | 2024-08-16 15:19:49 -0400 | [diff] [blame] | 551 | std::vector<RegistryCallout> getCalloutsWithoutAD( | 
 | 552 |     const nlohmann::json& json, const std::vector<std::string>& systemNames) | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 553 | { | 
 | 554 |     std::vector<RegistryCallout> calloutEntries; | 
 | 555 |  | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 556 |     nlohmann::json calloutLists = nlohmann::json::array(); | 
 | 557 |  | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 558 |     // Find the CalloutList to use based on the system type | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 559 |     findCalloutList(json, systemNames, calloutLists); | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 560 |  | 
 | 561 |     // We finally found the callouts, make the objects. | 
| Arya K Padman | 1537029 | 2024-05-14 01:48:22 -0500 | [diff] [blame] | 562 |     for (const auto& callout : calloutLists) | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 563 |     { | 
| Matt Spinler | f904caf | 2025-05-09 11:46:45 -0500 | [diff] [blame] | 564 |         calloutEntries.push_back(makeRegistryCallout(callout)); | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 565 |     } | 
 | 566 |  | 
 | 567 |     return calloutEntries; | 
 | 568 | } | 
 | 569 |  | 
 | 570 | /** | 
 | 571 |  * @brief Returns the callouts to use when an AdditionalData key is | 
 | 572 |  *        required to find the correct entries. | 
 | 573 |  * | 
 | 574 |  * The JSON looks like: | 
 | 575 |  *    { | 
 | 576 |  *        "ADName": "PROC_NUM", | 
 | 577 |  *        "CalloutsWithTheirADValues": | 
 | 578 |  *        [ | 
 | 579 |  *            { | 
 | 580 |  *                "ADValue": "0", | 
 | 581 |  *                "Callouts": | 
 | 582 |  *                [ | 
 | 583 |  *                    { | 
 | 584 |  *                        "CalloutList": | 
 | 585 |  *                        [ | 
 | 586 |  *                            { | 
 | 587 |  *                                "Priority": "high", | 
 | 588 |  *                                "LocCode": "P1-C5" | 
 | 589 |  *                            } | 
 | 590 |  *                        ] | 
 | 591 |  *                    } | 
 | 592 |  *                ] | 
 | 593 |  *            } | 
 | 594 |  *        ] | 
 | 595 |  *     } | 
 | 596 |  * | 
 | 597 |  * Note that the "Callouts" entry above is the same as the top level | 
 | 598 |  * entry used when there is no AdditionalData key. | 
 | 599 |  * | 
 | 600 |  * @param[in] json - The callout JSON | 
| Matt Spinler | 6ea4d5f | 2020-05-20 13:31:07 -0500 | [diff] [blame] | 601 |  * @param[in] systemNames - List of compatible system type names | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 602 |  * @param[in] additionalData - The AdditionalData property | 
 | 603 |  * | 
 | 604 |  * @return std::vector<RegistryCallout> - The callouts to use | 
 | 605 |  */ | 
| Patrick Williams | 075c792 | 2024-08-16 15:19:49 -0400 | [diff] [blame] | 606 | std::vector<RegistryCallout> getCalloutsUsingAD( | 
 | 607 |     const nlohmann::json& json, const std::vector<std::string>& systemNames, | 
 | 608 |     const AdditionalData& additionalData) | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 609 | { | 
 | 610 |     // This indicates which AD field we'll be using | 
 | 611 |     auto keyName = json["ADName"].get<std::string>(); | 
 | 612 |  | 
 | 613 |     // Get the actual value from the AD data | 
 | 614 |     auto adValue = additionalData.getValue(keyName); | 
 | 615 |  | 
 | 616 |     if (!adValue) | 
 | 617 |     { | 
 | 618 |         // The AdditionalData did not contain the necessary key | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 619 |         lg2::warning("The PEL message registry callouts JSON " | 
 | 620 |                      "said to use an AdditionalData key that isn't in the " | 
 | 621 |                      "AdditionalData event log property, key = {KEY}", | 
 | 622 |                      "KEY", keyName); | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 623 |         throw std::runtime_error{ | 
 | 624 |             "Missing AdditionalData entry for this callout"}; | 
 | 625 |     } | 
 | 626 |  | 
 | 627 |     const auto& callouts = json["CalloutsWithTheirADValues"]; | 
 | 628 |  | 
 | 629 |     // find the entry with that AD value | 
| Patrick Williams | 075c792 | 2024-08-16 15:19:49 -0400 | [diff] [blame] | 630 |     auto it = std::find_if( | 
 | 631 |         callouts.begin(), callouts.end(), [adValue](const nlohmann::json& j) { | 
 | 632 |             return *adValue == j["ADValue"].get<std::string>(); | 
 | 633 |         }); | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 634 |  | 
 | 635 |     if (it == callouts.end()) | 
 | 636 |     { | 
| Matt Spinler | f397afc | 2021-01-29 11:21:44 -0600 | [diff] [blame] | 637 |         // This can happen if not all possible values were in the | 
| Matt Spinler | 3d92331 | 2022-08-01 09:52:55 -0500 | [diff] [blame] | 638 |         // message registry and that's fine.  There may be a | 
 | 639 |         // "CalloutsWhenNoADMatch" section that contains callouts | 
 | 640 |         // to use in this case. | 
 | 641 |         if (json.contains("CalloutsWhenNoADMatch")) | 
 | 642 |         { | 
 | 643 |             return getCalloutsWithoutAD(json["CalloutsWhenNoADMatch"], | 
 | 644 |                                         systemNames); | 
 | 645 |         } | 
| Matt Spinler | f397afc | 2021-01-29 11:21:44 -0600 | [diff] [blame] | 646 |         return std::vector<RegistryCallout>{}; | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 647 |     } | 
 | 648 |  | 
 | 649 |     // Proceed to find the callouts possibly based on system type. | 
| Matt Spinler | 6ea4d5f | 2020-05-20 13:31:07 -0500 | [diff] [blame] | 650 |     return getCalloutsWithoutAD((*it)["Callouts"], systemNames); | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 651 | } | 
 | 652 |  | 
| Matt Spinler | 711f112 | 2022-12-15 11:41:20 -0600 | [diff] [blame] | 653 | /** | 
 | 654 |  * @brief Returns the journal capture information | 
 | 655 |  * | 
 | 656 |  *  The JSON looks like: | 
 | 657 |  *    "JournalCapture": { | 
 | 658 |  *        "NumLines": 30 | 
 | 659 |  *    } | 
 | 660 |  * | 
 | 661 |  *    "JournalCapture": | 
 | 662 |  *    { | 
 | 663 |  *        "Sections": [ | 
 | 664 |  *            { | 
 | 665 |  *                "SyslogID": "phosphor-log-manager", | 
 | 666 |  *                "NumLines": 20 | 
 | 667 |  *            } | 
 | 668 |  *        ] | 
 | 669 |  *    } | 
 | 670 |  * | 
 | 671 |  * @param json - The journal capture JSON | 
 | 672 |  * @return JournalCapture - The filled in variant | 
 | 673 |  */ | 
 | 674 | JournalCapture getJournalCapture(const nlohmann::json& json) | 
 | 675 | { | 
 | 676 |     JournalCapture capt; | 
 | 677 |  | 
 | 678 |     // Primary key is either NumLines or Sections. | 
 | 679 |     if (json.contains("NumLines")) | 
 | 680 |     { | 
 | 681 |         capt = json.at("NumLines").get<size_t>(); | 
 | 682 |     } | 
 | 683 |     else if (json.contains("Sections")) | 
 | 684 |     { | 
 | 685 |         AppCaptureList captures; | 
 | 686 |         for (const auto& capture : json.at("Sections")) | 
 | 687 |         { | 
 | 688 |             AppCapture ac; | 
 | 689 |             ac.syslogID = capture.at("SyslogID").get<std::string>(); | 
 | 690 |             ac.numLines = capture.at("NumLines").get<size_t>(); | 
 | 691 |             captures.push_back(std::move(ac)); | 
 | 692 |         } | 
 | 693 |  | 
 | 694 |         capt = captures; | 
 | 695 |     } | 
 | 696 |     else | 
 | 697 |     { | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 698 |         lg2::error("JournalCapture section not the right format"); | 
| Matt Spinler | 711f112 | 2022-12-15 11:41:20 -0600 | [diff] [blame] | 699 |         throw std::runtime_error{"JournalCapture section not the right format"}; | 
 | 700 |     } | 
 | 701 |  | 
 | 702 |     return capt; | 
 | 703 | } | 
 | 704 |  | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 705 | } // namespace helper | 
 | 706 |  | 
| Harisuddin Mohamed Isa | 0f717e1 | 2020-01-15 20:05:33 +0800 | [diff] [blame] | 707 | std::optional<Entry> Registry::lookup(const std::string& name, LookupType type, | 
 | 708 |                                       bool toCache) | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 709 | { | 
| Harisuddin Mohamed Isa | 0f717e1 | 2020-01-15 20:05:33 +0800 | [diff] [blame] | 710 |     std::optional<nlohmann::json> registryTmp; | 
 | 711 |     auto& registryOpt = (_registry) ? _registry : registryTmp; | 
 | 712 |     if (!registryOpt) | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 713 |     { | 
| Harisuddin Mohamed Isa | 0f717e1 | 2020-01-15 20:05:33 +0800 | [diff] [blame] | 714 |         registryOpt = readRegistry(_registryFile); | 
 | 715 |         if (!registryOpt) | 
 | 716 |         { | 
 | 717 |             return std::nullopt; | 
 | 718 |         } | 
 | 719 |         else if (toCache) | 
 | 720 |         { | 
 | 721 |             // Save message registry in memory for peltool | 
 | 722 |             _registry = std::move(registryTmp); | 
 | 723 |         } | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 724 |     } | 
| Harisuddin Mohamed Isa | 0f717e1 | 2020-01-15 20:05:33 +0800 | [diff] [blame] | 725 |     auto& reg = (_registry) ? _registry : registryTmp; | 
 | 726 |     const auto& registry = reg.value(); | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 727 |     // Find an entry with this name in the PEL array. | 
| Patrick Williams | 075c792 | 2024-08-16 15:19:49 -0400 | [diff] [blame] | 728 |     auto e = std::find_if( | 
 | 729 |         registry["PELs"].begin(), registry["PELs"].end(), | 
 | 730 |         [&name, &type](const nlohmann::json& j) { | 
 | 731 |             return ((name == j.at("Name").get<std::string>() && | 
 | 732 |                      type == LookupType::name) || | 
 | 733 |                     (name == j.at("SRC").at("ReasonCode").get<std::string>() && | 
 | 734 |                      type == LookupType::reasonCode)); | 
 | 735 |         }); | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 736 |  | 
 | 737 |     if (e != registry["PELs"].end()) | 
 | 738 |     { | 
 | 739 |         // Fill in the Entry structure from the JSON.  Most, but not all, fields | 
 | 740 |         // are optional. | 
 | 741 |  | 
 | 742 |         try | 
 | 743 |         { | 
 | 744 |             Entry entry; | 
 | 745 |             entry.name = (*e)["Name"]; | 
| Matt Spinler | 23970b0 | 2022-02-25 16:34:46 -0600 | [diff] [blame] | 746 |  | 
 | 747 |             if (e->contains("Subsystem")) | 
 | 748 |             { | 
 | 749 |                 entry.subsystem = helper::getSubsystem((*e)["Subsystem"]); | 
 | 750 |             } | 
| Matt Spinler | e07f915 | 2019-11-01 10:48:36 -0500 | [diff] [blame] | 751 |  | 
| Matt Spinler | 3ace0cf | 2020-04-09 15:16:57 -0500 | [diff] [blame] | 752 |             if (e->contains("ActionFlags")) | 
| Matt Spinler | e07f915 | 2019-11-01 10:48:36 -0500 | [diff] [blame] | 753 |             { | 
 | 754 |                 entry.actionFlags = helper::getActionFlags((*e)["ActionFlags"]); | 
 | 755 |             } | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 756 |  | 
| Matt Spinler | 3ace0cf | 2020-04-09 15:16:57 -0500 | [diff] [blame] | 757 |             if (e->contains("MfgActionFlags")) | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 758 |             { | 
 | 759 |                 entry.mfgActionFlags = | 
 | 760 |                     helper::getActionFlags((*e)["MfgActionFlags"]); | 
 | 761 |             } | 
 | 762 |  | 
| Matt Spinler | 3ace0cf | 2020-04-09 15:16:57 -0500 | [diff] [blame] | 763 |             if (e->contains("Severity")) | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 764 |             { | 
| Matt Spinler | aadccc8 | 2020-04-10 14:33:42 -0500 | [diff] [blame] | 765 |                 entry.severity = helper::getSeverities((*e)["Severity"]); | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 766 |             } | 
 | 767 |  | 
| Matt Spinler | 3ace0cf | 2020-04-09 15:16:57 -0500 | [diff] [blame] | 768 |             if (e->contains("MfgSeverity")) | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 769 |             { | 
| Matt Spinler | aadccc8 | 2020-04-10 14:33:42 -0500 | [diff] [blame] | 770 |                 entry.mfgSeverity = helper::getSeverities((*e)["MfgSeverity"]); | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 771 |             } | 
 | 772 |  | 
| Matt Spinler | 3ace0cf | 2020-04-09 15:16:57 -0500 | [diff] [blame] | 773 |             if (e->contains("EventType")) | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 774 |             { | 
 | 775 |                 entry.eventType = helper::getEventType((*e)["EventType"]); | 
 | 776 |             } | 
 | 777 |  | 
| Matt Spinler | 3ace0cf | 2020-04-09 15:16:57 -0500 | [diff] [blame] | 778 |             if (e->contains("EventScope")) | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 779 |             { | 
 | 780 |                 entry.eventScope = helper::getEventScope((*e)["EventScope"]); | 
 | 781 |             } | 
 | 782 |  | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 783 |             auto& src = (*e)["SRC"]; | 
 | 784 |             entry.src.reasonCode = helper::getSRCReasonCode(src, name); | 
 | 785 |  | 
| Matt Spinler | 3ace0cf | 2020-04-09 15:16:57 -0500 | [diff] [blame] | 786 |             if (src.contains("Type")) | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 787 |             { | 
 | 788 |                 entry.src.type = helper::getSRCType(src, name); | 
 | 789 |             } | 
 | 790 |             else | 
 | 791 |             { | 
 | 792 |                 entry.src.type = static_cast<uint8_t>(SRCType::bmcError); | 
 | 793 |             } | 
 | 794 |  | 
 | 795 |             // Now that we know the SRC type and reason code, | 
 | 796 |             // we can get the component ID. | 
 | 797 |             entry.componentID = helper::getComponentID( | 
 | 798 |                 entry.src.type, entry.src.reasonCode, *e, name); | 
 | 799 |  | 
| Matt Spinler | 3ace0cf | 2020-04-09 15:16:57 -0500 | [diff] [blame] | 800 |             if (src.contains("Words6To9")) | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 801 |             { | 
| Patrick Williams | 075c792 | 2024-08-16 15:19:49 -0400 | [diff] [blame] | 802 |                 entry.src.hexwordADFields = | 
 | 803 |                     helper::getSRCHexwordFields(src, name); | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 804 |             } | 
 | 805 |  | 
| Matt Spinler | 3ace0cf | 2020-04-09 15:16:57 -0500 | [diff] [blame] | 806 |             if (src.contains("SymptomIDFields")) | 
| Matt Spinler | 93e2932 | 2019-09-20 11:16:15 -0500 | [diff] [blame] | 807 |             { | 
 | 808 |                 entry.src.symptomID = helper::getSRCSymptomIDFields(src, name); | 
 | 809 |             } | 
 | 810 |  | 
| Matt Spinler | 3fe93e9 | 2023-04-14 14:06:59 -0500 | [diff] [blame] | 811 |             if (src.contains("DeconfigFlag")) | 
 | 812 |             { | 
 | 813 |                 entry.src.deconfigFlag = helper::getSRCDeconfigFlag(src); | 
 | 814 |             } | 
 | 815 |  | 
| Matt Spinler | da5b76b | 2023-06-01 15:56:57 -0500 | [diff] [blame] | 816 |             if (src.contains("CheckstopFlag")) | 
 | 817 |             { | 
 | 818 |                 entry.src.checkstopFlag = helper::getSRCCheckstopFlag(src); | 
 | 819 |             } | 
 | 820 |  | 
| Harisuddin Mohamed Isa | 0f717e1 | 2020-01-15 20:05:33 +0800 | [diff] [blame] | 821 |             auto& doc = (*e)["Documentation"]; | 
 | 822 |             entry.doc.message = doc["Message"]; | 
 | 823 |             entry.doc.description = doc["Description"]; | 
| Matt Spinler | 3ace0cf | 2020-04-09 15:16:57 -0500 | [diff] [blame] | 824 |             if (doc.contains("MessageArgSources")) | 
| Harisuddin Mohamed Isa | 0f717e1 | 2020-01-15 20:05:33 +0800 | [diff] [blame] | 825 |             { | 
| Matt Spinler | 3bb15b9 | 2022-04-27 09:32:10 -0500 | [diff] [blame] | 826 |                 entry.doc.messageArgSources = doc["MessageArgSources"]; | 
| Harisuddin Mohamed Isa | 0f717e1 | 2020-01-15 20:05:33 +0800 | [diff] [blame] | 827 |             } | 
 | 828 |  | 
| Matt Spinler | d8e2900 | 2020-04-09 09:11:22 -0500 | [diff] [blame] | 829 |             // If there are callouts defined, save the JSON for later | 
 | 830 |             if (_loadCallouts) | 
 | 831 |             { | 
 | 832 |                 if (e->contains("Callouts")) | 
 | 833 |                 { | 
 | 834 |                     entry.callouts = (*e)["Callouts"]; | 
 | 835 |                 } | 
 | 836 |                 else if (e->contains("CalloutsUsingAD")) | 
 | 837 |                 { | 
 | 838 |                     entry.callouts = (*e)["CalloutsUsingAD"]; | 
 | 839 |                 } | 
 | 840 |             } | 
 | 841 |  | 
| Matt Spinler | 711f112 | 2022-12-15 11:41:20 -0600 | [diff] [blame] | 842 |             if (e->contains("JournalCapture")) | 
 | 843 |             { | 
 | 844 |                 entry.journalCapture = | 
 | 845 |                     helper::getJournalCapture((*e)["JournalCapture"]); | 
 | 846 |             } | 
 | 847 |  | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 848 |             return entry; | 
 | 849 |         } | 
| Matt Spinler | 45796e8 | 2022-07-01 11:25:27 -0500 | [diff] [blame] | 850 |         catch (const std::exception& ex) | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 851 |         { | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 852 |             lg2::error("Found invalid message registry field. Error: {ERROR}", | 
 | 853 |                        "ERROR", ex); | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 854 |         } | 
 | 855 |     } | 
 | 856 |  | 
 | 857 |     return std::nullopt; | 
 | 858 | } | 
 | 859 |  | 
| Patrick Williams | 2529115 | 2025-02-01 08:21:42 -0500 | [diff] [blame] | 860 | std::optional<nlohmann::json> Registry::readRegistry( | 
 | 861 |     const std::filesystem::path& registryFile) | 
| Harisuddin Mohamed Isa | 0f717e1 | 2020-01-15 20:05:33 +0800 | [diff] [blame] | 862 | { | 
 | 863 |     // Look in /etc first in case someone put a test file there | 
 | 864 |     fs::path debugFile{fs::path{debugFilePath} / registryFileName}; | 
 | 865 |     nlohmann::json registry; | 
 | 866 |     std::ifstream file; | 
 | 867 |  | 
 | 868 |     if (fs::exists(debugFile)) | 
 | 869 |     { | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 870 |         lg2::info("Using debug PEL message registry"); | 
| Harisuddin Mohamed Isa | 0f717e1 | 2020-01-15 20:05:33 +0800 | [diff] [blame] | 871 |         file.open(debugFile); | 
 | 872 |     } | 
 | 873 |     else | 
 | 874 |     { | 
 | 875 |         file.open(registryFile); | 
 | 876 |     } | 
 | 877 |  | 
 | 878 |     try | 
 | 879 |     { | 
 | 880 |         registry = nlohmann::json::parse(file); | 
 | 881 |     } | 
| Patrick Williams | 66491c6 | 2021-10-06 12:23:37 -0500 | [diff] [blame] | 882 |     catch (const std::exception& e) | 
| Harisuddin Mohamed Isa | 0f717e1 | 2020-01-15 20:05:33 +0800 | [diff] [blame] | 883 |     { | 
| Matt Spinler | 4f46031 | 2023-07-07 16:24:20 -0500 | [diff] [blame] | 884 |         lg2::error("Error parsing message registry JSON. Error: {ERROR}", | 
 | 885 |                    "ERROR", e); | 
| Harisuddin Mohamed Isa | 0f717e1 | 2020-01-15 20:05:33 +0800 | [diff] [blame] | 886 |         return std::nullopt; | 
 | 887 |     } | 
 | 888 |     return registry; | 
 | 889 | } | 
 | 890 |  | 
| Patrick Williams | 2529115 | 2025-02-01 08:21:42 -0500 | [diff] [blame] | 891 | std::vector<RegistryCallout> Registry::getCallouts( | 
 | 892 |     const nlohmann::json& calloutJSON, | 
 | 893 |     const std::vector<std::string>& systemNames, | 
 | 894 |     const AdditionalData& additionalData) | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 895 | { | 
 | 896 |     // The JSON may either use an AdditionalData key | 
 | 897 |     // as an index, or not. | 
 | 898 |     if (helper::calloutUsesAdditionalData(calloutJSON)) | 
 | 899 |     { | 
| Matt Spinler | 6ea4d5f | 2020-05-20 13:31:07 -0500 | [diff] [blame] | 900 |         return helper::getCalloutsUsingAD(calloutJSON, systemNames, | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 901 |                                           additionalData); | 
 | 902 |     } | 
 | 903 |  | 
| Matt Spinler | 6ea4d5f | 2020-05-20 13:31:07 -0500 | [diff] [blame] | 904 |     return helper::getCalloutsWithoutAD(calloutJSON, systemNames); | 
| Matt Spinler | 6b427cc | 2020-04-09 09:42:59 -0500 | [diff] [blame] | 905 | } | 
 | 906 |  | 
| Matt Spinler | 367144c | 2019-09-19 15:33:52 -0500 | [diff] [blame] | 907 | } // namespace message | 
 | 908 | } // namespace pels | 
 | 909 | } // namespace openpower |