blob: 32244d79fb77e5c949693e097bff54a1aa6a3d85 [file] [log] [blame]
James Feist139cb572018-09-10 15:26:18 -07001#include <Thresholds.hpp>
2#include <VariantVisitors.hpp>
3#include <boost/algorithm/string/replace.hpp>
4#include <boost/lexical_cast.hpp>
5#include <fstream>
6#include <iostream>
James Feistaf79dd32018-09-12 12:54:15 -07007#include <sensor.hpp>
James Feist139cb572018-09-10 15:26:18 -07008
9static constexpr bool DEBUG = false;
10constexpr size_t MAX_THRESHOLDS = 4;
11
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070012namespace variant_ns = sdbusplus::message::variant_ns;
James Feist139cb572018-09-10 15:26:18 -070013namespace thresholds
14{
15unsigned int toBusValue(const Level &level)
16{
17 switch (level)
18 {
19 case (Level::WARNING):
20 {
21 return 0;
22 }
23 case (Level::CRITICAL):
24 {
25 return 1;
26 }
27 default:
28 {
29 return -1;
30 }
31 }
32}
33
34std::string toBusValue(const Direction &direction)
35{
36 switch (direction)
37 {
38 case (Direction::LOW):
39 {
40 return "less than";
41 }
42 case (Direction::HIGH):
43 {
44 return "greater than";
45 }
46 default:
47 {
48 return "err";
49 }
50 }
51}
52
53bool ParseThresholdsFromConfig(
54 const SensorData &sensorData,
55 std::vector<thresholds::Threshold> &thresholdVector,
56 const std::string *matchLabel)
57{
58 for (const auto &item : sensorData)
59 {
60 if (item.first.find("Thresholds") == std::string::npos)
61 {
62 continue;
63 }
64 if (matchLabel != nullptr)
65 {
66 auto labelFind = item.second.find("Label");
67 if (labelFind == item.second.end())
68 continue;
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070069 if (variant_ns::visit(VariantToStringVisitor(),
70 labelFind->second) != *matchLabel)
James Feist139cb572018-09-10 15:26:18 -070071 continue;
72 }
73 auto directionFind = item.second.find("Direction");
74 auto severityFind = item.second.find("Severity");
75 auto valueFind = item.second.find("Value");
76 if (valueFind == item.second.end() ||
77 severityFind == item.second.end() ||
78 directionFind == item.second.end())
79 {
80 std::cerr << "Malformed threshold in configuration\n";
81 return false;
82 }
83 Level level;
84 Direction direction;
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070085 if (variant_ns::visit(VariantToUnsignedIntVisitor(),
86 severityFind->second) == 0)
James Feist139cb572018-09-10 15:26:18 -070087 {
88 level = Level::WARNING;
89 }
90 else
91 {
92 level = Level::CRITICAL;
93 }
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -070094 if (variant_ns::visit(VariantToStringVisitor(),
95 directionFind->second) == "less than")
James Feist139cb572018-09-10 15:26:18 -070096 {
97 direction = Direction::LOW;
98 }
99 else
100 {
101 direction = Direction::HIGH;
102 }
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -0700103 float val =
104 variant_ns::visit(VariantToFloatVisitor(), valueFind->second);
James Feist139cb572018-09-10 15:26:18 -0700105
106 thresholdVector.emplace_back(level, direction, val);
107 }
108 return true;
109}
110
111void persistThreshold(const std::string &path, const std::string &baseInterface,
112 const thresholds::Threshold &threshold,
113 std::shared_ptr<sdbusplus::asio::connection> &conn)
114{
115 for (int ii = 0; ii < MAX_THRESHOLDS; ii++)
116 {
117 std::string thresholdInterface =
118 baseInterface + ".Thresholds" + std::to_string(ii);
119 conn->async_method_call(
120 [&, path, threshold, thresholdInterface](
121 const boost::system::error_code &ec,
122 const boost::container::flat_map<std::string, BasicVariantType>
123 &result) {
124 if (ec)
125 {
126 return; // threshold not supported
127 }
128
129 auto directionFind = result.find("Direction");
130 auto severityFind = result.find("Severity");
131 auto valueFind = result.find("Value");
132 if (valueFind == result.end() || severityFind == result.end() ||
133 directionFind == result.end())
134 {
135 std::cerr << "Malformed threshold in configuration\n";
136 return;
137 }
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -0700138 unsigned int level = variant_ns::visit(
James Feist139cb572018-09-10 15:26:18 -0700139 VariantToUnsignedIntVisitor(), severityFind->second);
140
Yoo, Jae Hyun625429b2018-10-17 18:19:02 -0700141 std::string dir = variant_ns::visit(VariantToStringVisitor(),
142 directionFind->second);
James Feist139cb572018-09-10 15:26:18 -0700143 if ((toBusValue(threshold.level) != level) ||
144 (toBusValue(threshold.direction) != dir))
145 {
146 return; // not the droid we're looking for
147 }
148
149 sdbusplus::message::variant<double> value(threshold.value);
150 conn->async_method_call(
151 [](const boost::system::error_code &ec) {
152 if (ec)
153 {
154 std::cerr << "Error setting threshold " << ec
155 << "\n";
156 }
157 },
158 ENTITY_MANAGER_NAME, path,
159 "org.freedesktop.DBus.Properties", "Set",
160 thresholdInterface, "Value", value);
161 },
162 ENTITY_MANAGER_NAME, path, "org.freedesktop.DBus.Properties",
163 "GetAll", thresholdInterface);
164 }
165}
166
James Feistaf79dd32018-09-12 12:54:15 -0700167void checkThresholds(Sensor *sensor)
168{
169
170 if (sensor->thresholds.empty())
171 {
172 return;
173 }
174 for (auto &threshold : sensor->thresholds)
175 {
176 if (threshold.direction == thresholds::Direction::HIGH)
177 {
178 if (sensor->value > threshold.value && !threshold.asserted)
179 {
180 assertThresholds(sensor, threshold.level, threshold.direction,
181 true);
182 threshold.asserted = true;
183 }
184 else if (sensor->value <= threshold.value && threshold.asserted)
185 {
186 assertThresholds(sensor, threshold.level, threshold.direction,
187 false);
188 threshold.asserted = false;
189 }
190 }
191 else
192 {
193 if (sensor->value < threshold.value && !threshold.asserted)
194 {
195 assertThresholds(sensor, threshold.level, threshold.direction,
196 true);
197 threshold.asserted = true;
198 }
199 else if (sensor->value >= threshold.value && threshold.asserted)
200 {
201 assertThresholds(sensor, threshold.level, threshold.direction,
202 false);
203 threshold.asserted = false;
204 }
205 }
206 }
207}
208
209void assertThresholds(Sensor *sensor, thresholds::Level level,
210 thresholds::Direction direction, bool assert)
211{
212 std::string property;
213 std::shared_ptr<sdbusplus::asio::dbus_interface> interface;
214 if (level == thresholds::Level::WARNING &&
215 direction == thresholds::Direction::HIGH)
216 {
217 property = "WarningAlarmHigh";
218 interface = sensor->thresholdInterfaceWarning;
219 }
220 else if (level == thresholds::Level::WARNING &&
221 direction == thresholds::Direction::LOW)
222 {
223 property = "WarningAlarmLow";
224 interface = sensor->thresholdInterfaceWarning;
225 }
226 else if (level == thresholds::Level::CRITICAL &&
227 direction == thresholds::Direction::HIGH)
228 {
229 property = "CriticalAlarmHigh";
230 interface = sensor->thresholdInterfaceCritical;
231 }
232 else if (level == thresholds::Level::CRITICAL &&
233 direction == thresholds::Direction::LOW)
234 {
235 property = "CriticalAlarmLow";
236 interface = sensor->thresholdInterfaceCritical;
237 }
238 else
239 {
240 std::cerr << "Unknown threshold, level " << level << "direction "
241 << direction << "\n";
242 return;
243 }
244 if (!interface)
245 {
246 std::cout << "trying to set uninitialized interface\n";
247 return;
248 }
249 interface->set_property(property, assert);
250}
251
James Feist139cb572018-09-10 15:26:18 -0700252static constexpr std::array<const char *, 4> ATTR_TYPES = {"lcrit", "min",
253 "max", "crit"};
254
255bool ParseThresholdsFromAttr(
256 std::vector<thresholds::Threshold> &threshold_vector,
Yoo, Jae Hyunac18e142018-10-09 16:38:58 -0700257 const std::string &input_path, const double &scale_factor)
James Feist139cb572018-09-10 15:26:18 -0700258{
259 for (auto &type : ATTR_TYPES)
260 {
261 auto attr_path = boost::replace_all_copy(input_path, "input", type);
262 std::ifstream attr_file(attr_path);
263 if (!attr_file.good())
264 continue;
265 std::string attr;
266 std::getline(attr_file, attr);
267 attr_file.close();
268
269 Level level;
270 Direction direction;
271 double val = std::stod(attr) / scale_factor;
272 if (type == "min" || type == "max")
273 level = Level::WARNING;
274 else
275 level = Level::CRITICAL;
276 if (type == "min" || type == "lcrit")
277 direction = Direction::LOW;
278 else
279 direction = Direction::HIGH;
280
281 if (DEBUG)
282 std::cout << "Threshold: " << attr_path << ": " << val << "\n";
283
284 threshold_vector.emplace_back(level, direction, val);
285 }
286 // no thresholds is allowed, not an error so return true always
287 return true;
288}
289
290bool HasCriticalInterface(
291 const std::vector<thresholds::Threshold> &threshold_vector)
292{
293 for (auto &threshold : threshold_vector)
294 {
295 if (threshold.level == Level::CRITICAL)
296 return true;
297 }
298 return false;
299}
300
301bool HasWarningInterface(
302 const std::vector<thresholds::Threshold> &threshold_vector)
303{
304 for (auto &threshold : threshold_vector)
305 {
306 if (threshold.level == Level::WARNING)
307 return true;
308 }
309 return false;
310}
311} // namespace thresholds