blob: 797f7b8c254dd996eb52fb6d56b9d0efbe3396b0 [file] [log] [blame]
Matt Spinler4a6ea6a2018-03-27 14:25:12 -05001/**
2 * Copyright © 2018 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 Spinler66e07072018-09-12 10:36:14 -050016#include "policy_find.hpp"
17
Matt Spinler8e24dbc2018-03-27 14:48:17 -050018#include <phosphor-logging/log.hpp>
Matt Spinlere3be64f2018-03-27 15:04:33 -050019#include <sstream>
Matt Spinler4a6ea6a2018-03-27 14:25:12 -050020
21namespace ibm
22{
23namespace logging
24{
25namespace policy
26{
27
Matt Spinler8e24dbc2018-03-27 14:48:17 -050028namespace optional_ns = std::experimental;
29
30/**
31 * Returns a property value from a map of properties.
32 *
33 * @tparam - T the property data type
34 * @param[in] properties - the property map
35 * @param[in] name - the property name
36 *
37 * @return optional<T> - the property value
38 */
Matt Spinler259e7272018-03-29 10:57:17 -050039template <typename T>
40optional_ns::optional<T> getProperty(const DbusPropertyMap& properties,
41 const std::string& name)
Matt Spinler8e24dbc2018-03-27 14:48:17 -050042{
43 auto prop = properties.find(name);
44
45 if (prop != properties.end())
46 {
47 return prop->second.template get<T>();
48 }
49
50 return {};
51}
52
53/**
Matt Spinlere3be64f2018-03-27 15:04:33 -050054 * Finds a value in the AdditionalData property, which is
55 * an array of strings in the form of:
56 *
57 * NAME=VALUE
58 *
59 * @param[in] additionalData - the AdditionalData property contents
60 * @param[in] name - the name of the value to find
61 *
62 * @return optional<std::string> - the data value
63 */
Matt Spinler259e7272018-03-29 10:57:17 -050064optional_ns::optional<std::string>
65 getAdditionalDataItem(const std::vector<std::string>& additionalData,
66 const std::string& name)
Matt Spinlere3be64f2018-03-27 15:04:33 -050067{
68 for (const auto& item : additionalData)
69 {
Matt Spinler259e7272018-03-29 10:57:17 -050070 if (item.find(name + "=") != std::string::npos)
Matt Spinlere3be64f2018-03-27 15:04:33 -050071 {
72 return item.substr(item.find('=') + 1);
73 }
74 }
75
76 return {};
77}
78
79/**
Matt Spinler8e24dbc2018-03-27 14:48:17 -050080 * Returns the search modifier to use.
81 *
82 * The modifier is used when the error name itself isn't granular
83 * enough to find a policy table entry. The modifier is determined
84 * using rules provided by the IBM service team.
85 *
86 * Not all errors need a modifier, so this function isn't
87 * guaranteed to find one.
88 *
89 * @param[in] properties - the property map for the error
90 *
91 * @return string - the search modifier
92 * may be empty if none found
93 */
Matt Spinler259e7272018-03-29 10:57:17 -050094auto getSearchModifier(const DbusPropertyMap& properties)
Matt Spinler8e24dbc2018-03-27 14:48:17 -050095{
Matt Spinlere3be64f2018-03-27 15:04:33 -050096 // The modifier may be one of several things within the
97 // AdditionalData property. Try them all until one
98 // is found.
Matt Spinler8e24dbc2018-03-27 14:48:17 -050099
Matt Spinlere3be64f2018-03-27 15:04:33 -0500100 auto data =
101 getProperty<std::vector<std::string>>(properties, "AdditionalData");
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500102
Matt Spinlere3be64f2018-03-27 15:04:33 -0500103 if (!data)
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500104 {
Matt Spinlere3be64f2018-03-27 15:04:33 -0500105 return std::string{};
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500106 }
107
Matt Spinlere3be64f2018-03-27 15:04:33 -0500108 // AdditionalData fields where the value is the modifier
109 static const std::vector<std::string> ADFields{"CALLOUT_INVENTORY_PATH",
110 "RAIL_NAME", "INPUT_NAME"};
111
112 optional_ns::optional<std::string> mod;
113 for (const auto& field : ADFields)
114 {
115 mod = getAdditionalDataItem(*data, field);
116 if (mod && !(*mod).empty())
117 {
118 return *mod;
119 }
120 }
121
122 // Next are the AdditionalData fields where the value needs
123 // to be massaged to get the modifier.
124
125 // A device path, but we only care about the type
126 mod = getAdditionalDataItem(*data, "CALLOUT_DEVICE_PATH");
127 if (mod)
128 {
129 // The table only handles I2C and FSI
130 if ((*mod).find("i2c") != std::string::npos)
131 {
132 return std::string{"I2C"};
133 }
134 else if ((*mod).find("fsi") != std::string::npos)
135 {
136 return std::string{"FSI"};
137 }
138 }
139
140 // A hostboot procedure ID
141 mod = getAdditionalDataItem(*data, "PROCEDURE");
142 if (mod)
143 {
144 // Convert decimal (e.g. 109) to hex (e.g. 6D)
145 std::ostringstream stream;
146 try
147 {
148 stream << std::hex << std::stoul((*mod).c_str());
149 auto value = stream.str();
150
151 if (!value.empty())
152 {
Matt Spinler259e7272018-03-29 10:57:17 -0500153 std::transform(value.begin(), value.end(), value.begin(),
154 toupper);
Matt Spinlere3be64f2018-03-27 15:04:33 -0500155 return value;
156 }
157 }
158 catch (std::exception& e)
159 {
160 using namespace phosphor::logging;
161 log<level::ERR>("Invalid PROCEDURE value found",
Joseph Reynolds53530262018-05-17 13:45:13 -0500162 entry("PROCEDURE=%s", mod->c_str()));
Matt Spinlere3be64f2018-03-27 15:04:33 -0500163 }
164 }
165
166 return std::string{};
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500167}
168
Matt Spinler259e7272018-03-29 10:57:17 -0500169PolicyProps find(const policy::Table& policy,
170 const DbusPropertyMap& errorLogProperties)
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500171{
Matt Spinler259e7272018-03-29 10:57:17 -0500172 auto errorMsg = getProperty<std::string>(errorLogProperties,
173 "Message"); // e.g. xyz.X.Error.Y
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500174 if (errorMsg)
175 {
176 auto modifier = getSearchModifier(errorLogProperties);
177
178 auto result = policy.find(*errorMsg, modifier);
179
180 if (result)
181 {
182 return {(*result).get().ceid, (*result).get().msg};
183 }
184 }
185 else
186 {
187 using namespace phosphor::logging;
188 log<level::ERR>("No Message metadata found in an error");
189 }
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500190
191 return {policy.defaultEID(), policy.defaultMsg()};
192}
Matt Spinler66e07072018-09-12 10:36:14 -0500193} // namespace policy
194} // namespace logging
195} // namespace ibm