blob: b8b671aeedfad76f3e6984db12be0cac97685b8f [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 Spinler8e24dbc2018-03-27 14:48:17 -050016#include <phosphor-logging/log.hpp>
Matt Spinlere3be64f2018-03-27 15:04:33 -050017#include <sstream>
Matt Spinler4a6ea6a2018-03-27 14:25:12 -050018#include "policy_find.hpp"
19
20namespace ibm
21{
22namespace logging
23{
24namespace policy
25{
26
Matt Spinler8e24dbc2018-03-27 14:48:17 -050027namespace optional_ns = std::experimental;
28
29/**
30 * Returns a property value from a map of properties.
31 *
32 * @tparam - T the property data type
33 * @param[in] properties - the property map
34 * @param[in] name - the property name
35 *
36 * @return optional<T> - the property value
37 */
Matt Spinler259e7272018-03-29 10:57:17 -050038template <typename T>
39optional_ns::optional<T> getProperty(const DbusPropertyMap& properties,
40 const std::string& name)
Matt Spinler8e24dbc2018-03-27 14:48:17 -050041{
42 auto prop = properties.find(name);
43
44 if (prop != properties.end())
45 {
46 return prop->second.template get<T>();
47 }
48
49 return {};
50}
51
52/**
Matt Spinlere3be64f2018-03-27 15:04:33 -050053 * Finds a value in the AdditionalData property, which is
54 * an array of strings in the form of:
55 *
56 * NAME=VALUE
57 *
58 * @param[in] additionalData - the AdditionalData property contents
59 * @param[in] name - the name of the value to find
60 *
61 * @return optional<std::string> - the data value
62 */
Matt Spinler259e7272018-03-29 10:57:17 -050063optional_ns::optional<std::string>
64 getAdditionalDataItem(const std::vector<std::string>& additionalData,
65 const std::string& name)
Matt Spinlere3be64f2018-03-27 15:04:33 -050066{
67 for (const auto& item : additionalData)
68 {
Matt Spinler259e7272018-03-29 10:57:17 -050069 if (item.find(name + "=") != std::string::npos)
Matt Spinlere3be64f2018-03-27 15:04:33 -050070 {
71 return item.substr(item.find('=') + 1);
72 }
73 }
74
75 return {};
76}
77
78/**
Matt Spinler8e24dbc2018-03-27 14:48:17 -050079 * Returns the search modifier to use.
80 *
81 * The modifier is used when the error name itself isn't granular
82 * enough to find a policy table entry. The modifier is determined
83 * using rules provided by the IBM service team.
84 *
85 * Not all errors need a modifier, so this function isn't
86 * guaranteed to find one.
87 *
88 * @param[in] properties - the property map for the error
89 *
90 * @return string - the search modifier
91 * may be empty if none found
92 */
Matt Spinler259e7272018-03-29 10:57:17 -050093auto getSearchModifier(const DbusPropertyMap& properties)
Matt Spinler8e24dbc2018-03-27 14:48:17 -050094{
Matt Spinlere3be64f2018-03-27 15:04:33 -050095 // The modifier may be one of several things within the
96 // AdditionalData property. Try them all until one
97 // is found.
Matt Spinler8e24dbc2018-03-27 14:48:17 -050098
Matt Spinlere3be64f2018-03-27 15:04:33 -050099 auto data =
100 getProperty<std::vector<std::string>>(properties, "AdditionalData");
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500101
Matt Spinlere3be64f2018-03-27 15:04:33 -0500102 if (!data)
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500103 {
Matt Spinlere3be64f2018-03-27 15:04:33 -0500104 return std::string{};
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500105 }
106
Matt Spinlere3be64f2018-03-27 15:04:33 -0500107 // AdditionalData fields where the value is the modifier
108 static const std::vector<std::string> ADFields{"CALLOUT_INVENTORY_PATH",
109 "RAIL_NAME", "INPUT_NAME"};
110
111 optional_ns::optional<std::string> mod;
112 for (const auto& field : ADFields)
113 {
114 mod = getAdditionalDataItem(*data, field);
115 if (mod && !(*mod).empty())
116 {
117 return *mod;
118 }
119 }
120
121 // Next are the AdditionalData fields where the value needs
122 // to be massaged to get the modifier.
123
124 // A device path, but we only care about the type
125 mod = getAdditionalDataItem(*data, "CALLOUT_DEVICE_PATH");
126 if (mod)
127 {
128 // The table only handles I2C and FSI
129 if ((*mod).find("i2c") != std::string::npos)
130 {
131 return std::string{"I2C"};
132 }
133 else if ((*mod).find("fsi") != std::string::npos)
134 {
135 return std::string{"FSI"};
136 }
137 }
138
139 // A hostboot procedure ID
140 mod = getAdditionalDataItem(*data, "PROCEDURE");
141 if (mod)
142 {
143 // Convert decimal (e.g. 109) to hex (e.g. 6D)
144 std::ostringstream stream;
145 try
146 {
147 stream << std::hex << std::stoul((*mod).c_str());
148 auto value = stream.str();
149
150 if (!value.empty())
151 {
Matt Spinler259e7272018-03-29 10:57:17 -0500152 std::transform(value.begin(), value.end(), value.begin(),
153 toupper);
Matt Spinlere3be64f2018-03-27 15:04:33 -0500154 return value;
155 }
156 }
157 catch (std::exception& e)
158 {
159 using namespace phosphor::logging;
160 log<level::ERR>("Invalid PROCEDURE value found",
161 entry("PROCEDURE=%s", *mod));
162 }
163 }
164
165 return std::string{};
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500166}
167
Matt Spinler259e7272018-03-29 10:57:17 -0500168PolicyProps find(const policy::Table& policy,
169 const DbusPropertyMap& errorLogProperties)
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500170{
Matt Spinler259e7272018-03-29 10:57:17 -0500171 auto errorMsg = getProperty<std::string>(errorLogProperties,
172 "Message"); // e.g. xyz.X.Error.Y
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500173 if (errorMsg)
174 {
175 auto modifier = getSearchModifier(errorLogProperties);
176
177 auto result = policy.find(*errorMsg, modifier);
178
179 if (result)
180 {
181 return {(*result).get().ceid, (*result).get().msg};
182 }
183 }
184 else
185 {
186 using namespace phosphor::logging;
187 log<level::ERR>("No Message metadata found in an error");
188 }
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500189
190 return {policy.defaultEID(), policy.defaultMsg()};
191}
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500192}
193}
194}