blob: daf872cf269ad019c6bd5823a62c6dedd776cabb [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 */
38template<typename T>
39optional_ns::optional<T> getProperty(
40 const DbusPropertyMap& properties,
41 const std::string& name)
42{
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 */
64optional_ns::optional<std::string> getAdditionalDataItem(
65 const std::vector<std::string>& additionalData,
66 const std::string& name)
67{
68 for (const auto& item : additionalData)
69 {
70 if (item.find(name+"=") != std::string::npos)
71 {
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 */
94auto getSearchModifier(
95 const DbusPropertyMap& properties)
96{
Matt Spinlere3be64f2018-03-27 15:04:33 -050097 // The modifier may be one of several things within the
98 // AdditionalData property. Try them all until one
99 // is found.
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500100
Matt Spinlere3be64f2018-03-27 15:04:33 -0500101 auto data =
102 getProperty<std::vector<std::string>>(properties, "AdditionalData");
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500103
Matt Spinlere3be64f2018-03-27 15:04:33 -0500104 if (!data)
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500105 {
Matt Spinlere3be64f2018-03-27 15:04:33 -0500106 return std::string{};
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500107 }
108
Matt Spinlere3be64f2018-03-27 15:04:33 -0500109 // AdditionalData fields where the value is the modifier
110 static const std::vector<std::string> ADFields{"CALLOUT_INVENTORY_PATH",
111 "RAIL_NAME", "INPUT_NAME"};
112
113 optional_ns::optional<std::string> mod;
114 for (const auto& field : ADFields)
115 {
116 mod = getAdditionalDataItem(*data, field);
117 if (mod && !(*mod).empty())
118 {
119 return *mod;
120 }
121 }
122
123 // Next are the AdditionalData fields where the value needs
124 // to be massaged to get the modifier.
125
126 // A device path, but we only care about the type
127 mod = getAdditionalDataItem(*data, "CALLOUT_DEVICE_PATH");
128 if (mod)
129 {
130 // The table only handles I2C and FSI
131 if ((*mod).find("i2c") != std::string::npos)
132 {
133 return std::string{"I2C"};
134 }
135 else if ((*mod).find("fsi") != std::string::npos)
136 {
137 return std::string{"FSI"};
138 }
139 }
140
141 // A hostboot procedure ID
142 mod = getAdditionalDataItem(*data, "PROCEDURE");
143 if (mod)
144 {
145 // Convert decimal (e.g. 109) to hex (e.g. 6D)
146 std::ostringstream stream;
147 try
148 {
149 stream << std::hex << std::stoul((*mod).c_str());
150 auto value = stream.str();
151
152 if (!value.empty())
153 {
154 std::transform(
155 value.begin(), value.end(), value.begin(), toupper);
156 return value;
157 }
158 }
159 catch (std::exception& e)
160 {
161 using namespace phosphor::logging;
162 log<level::ERR>("Invalid PROCEDURE value found",
163 entry("PROCEDURE=%s", *mod));
164 }
165 }
166
167 return std::string{};
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500168}
169
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500170PolicyProps find(
171 const policy::Table& policy,
172 const DbusPropertyMap& errorLogProperties)
173{
Matt Spinler8e24dbc2018-03-27 14:48:17 -0500174 auto errorMsg = getProperty<std::string>(
175 errorLogProperties, "Message"); //e.g. xyz.X.Error.Y
176 if (errorMsg)
177 {
178 auto modifier = getSearchModifier(errorLogProperties);
179
180 auto result = policy.find(*errorMsg, modifier);
181
182 if (result)
183 {
184 return {(*result).get().ceid, (*result).get().msg};
185 }
186 }
187 else
188 {
189 using namespace phosphor::logging;
190 log<level::ERR>("No Message metadata found in an error");
191 }
Matt Spinler4a6ea6a2018-03-27 14:25:12 -0500192
193 return {policy.defaultEID(), policy.defaultMsg()};
194}
195
196}
197}
198}