blob: d31f487ab0f3f00288fa053a11cacbdf2a0138e0 [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>
7
8static constexpr bool DEBUG = false;
9constexpr size_t MAX_THRESHOLDS = 4;
10
11namespace thresholds
12{
13unsigned int toBusValue(const Level &level)
14{
15 switch (level)
16 {
17 case (Level::WARNING):
18 {
19 return 0;
20 }
21 case (Level::CRITICAL):
22 {
23 return 1;
24 }
25 default:
26 {
27 return -1;
28 }
29 }
30}
31
32std::string toBusValue(const Direction &direction)
33{
34 switch (direction)
35 {
36 case (Direction::LOW):
37 {
38 return "less than";
39 }
40 case (Direction::HIGH):
41 {
42 return "greater than";
43 }
44 default:
45 {
46 return "err";
47 }
48 }
49}
50
51bool ParseThresholdsFromConfig(
52 const SensorData &sensorData,
53 std::vector<thresholds::Threshold> &thresholdVector,
54 const std::string *matchLabel)
55{
56 for (const auto &item : sensorData)
57 {
58 if (item.first.find("Thresholds") == std::string::npos)
59 {
60 continue;
61 }
62 if (matchLabel != nullptr)
63 {
64 auto labelFind = item.second.find("Label");
65 if (labelFind == item.second.end())
66 continue;
67 if (mapbox::util::apply_visitor(VariantToStringVisitor(),
68 labelFind->second) != *matchLabel)
69 continue;
70 }
71 auto directionFind = item.second.find("Direction");
72 auto severityFind = item.second.find("Severity");
73 auto valueFind = item.second.find("Value");
74 if (valueFind == item.second.end() ||
75 severityFind == item.second.end() ||
76 directionFind == item.second.end())
77 {
78 std::cerr << "Malformed threshold in configuration\n";
79 return false;
80 }
81 Level level;
82 Direction direction;
83 if (mapbox::util::apply_visitor(VariantToUnsignedIntVisitor(),
84 severityFind->second) == 0)
85 {
86 level = Level::WARNING;
87 }
88 else
89 {
90 level = Level::CRITICAL;
91 }
92 if (mapbox::util::apply_visitor(VariantToStringVisitor(),
93 directionFind->second) == "less than")
94 {
95 direction = Direction::LOW;
96 }
97 else
98 {
99 direction = Direction::HIGH;
100 }
101 float val = mapbox::util::apply_visitor(VariantToFloatVisitor(),
102 valueFind->second);
103
104 thresholdVector.emplace_back(level, direction, val);
105 }
106 return true;
107}
108
109void persistThreshold(const std::string &path, const std::string &baseInterface,
110 const thresholds::Threshold &threshold,
111 std::shared_ptr<sdbusplus::asio::connection> &conn)
112{
113 for (int ii = 0; ii < MAX_THRESHOLDS; ii++)
114 {
115 std::string thresholdInterface =
116 baseInterface + ".Thresholds" + std::to_string(ii);
117 conn->async_method_call(
118 [&, path, threshold, thresholdInterface](
119 const boost::system::error_code &ec,
120 const boost::container::flat_map<std::string, BasicVariantType>
121 &result) {
122 if (ec)
123 {
124 return; // threshold not supported
125 }
126
127 auto directionFind = result.find("Direction");
128 auto severityFind = result.find("Severity");
129 auto valueFind = result.find("Value");
130 if (valueFind == result.end() || severityFind == result.end() ||
131 directionFind == result.end())
132 {
133 std::cerr << "Malformed threshold in configuration\n";
134 return;
135 }
136 unsigned int level = mapbox::util::apply_visitor(
137 VariantToUnsignedIntVisitor(), severityFind->second);
138
139 std::string dir = mapbox::util::apply_visitor(
140 VariantToStringVisitor(), directionFind->second);
141 if ((toBusValue(threshold.level) != level) ||
142 (toBusValue(threshold.direction) != dir))
143 {
144 return; // not the droid we're looking for
145 }
146
147 sdbusplus::message::variant<double> value(threshold.value);
148 conn->async_method_call(
149 [](const boost::system::error_code &ec) {
150 if (ec)
151 {
152 std::cerr << "Error setting threshold " << ec
153 << "\n";
154 }
155 },
156 ENTITY_MANAGER_NAME, path,
157 "org.freedesktop.DBus.Properties", "Set",
158 thresholdInterface, "Value", value);
159 },
160 ENTITY_MANAGER_NAME, path, "org.freedesktop.DBus.Properties",
161 "GetAll", thresholdInterface);
162 }
163}
164
165static constexpr std::array<const char *, 4> ATTR_TYPES = {"lcrit", "min",
166 "max", "crit"};
167
168bool ParseThresholdsFromAttr(
169 std::vector<thresholds::Threshold> &threshold_vector,
170 const std::string &input_path, const double scale_factor)
171{
172 for (auto &type : ATTR_TYPES)
173 {
174 auto attr_path = boost::replace_all_copy(input_path, "input", type);
175 std::ifstream attr_file(attr_path);
176 if (!attr_file.good())
177 continue;
178 std::string attr;
179 std::getline(attr_file, attr);
180 attr_file.close();
181
182 Level level;
183 Direction direction;
184 double val = std::stod(attr) / scale_factor;
185 if (type == "min" || type == "max")
186 level = Level::WARNING;
187 else
188 level = Level::CRITICAL;
189 if (type == "min" || type == "lcrit")
190 direction = Direction::LOW;
191 else
192 direction = Direction::HIGH;
193
194 if (DEBUG)
195 std::cout << "Threshold: " << attr_path << ": " << val << "\n";
196
197 threshold_vector.emplace_back(level, direction, val);
198 }
199 // no thresholds is allowed, not an error so return true always
200 return true;
201}
202
203bool HasCriticalInterface(
204 const std::vector<thresholds::Threshold> &threshold_vector)
205{
206 for (auto &threshold : threshold_vector)
207 {
208 if (threshold.level == Level::CRITICAL)
209 return true;
210 }
211 return false;
212}
213
214bool HasWarningInterface(
215 const std::vector<thresholds::Threshold> &threshold_vector)
216{
217 for (auto &threshold : threshold_vector)
218 {
219 if (threshold.level == Level::WARNING)
220 return true;
221 }
222 return false;
223}
224} // namespace thresholds