xref: /openbmc/telemetry/src/trigger_factory.cpp (revision b4ef22e4d365bde35a7fce7950033c9271c68ce7)
1 #include "trigger_factory.hpp"
2 
3 #include "discrete_threshold.hpp"
4 #include "numeric_threshold.hpp"
5 #include "on_change_threshold.hpp"
6 #include "sensor.hpp"
7 #include "trigger.hpp"
8 #include "trigger_actions.hpp"
9 #include "utils/dbus_mapper.hpp"
10 #include "utils/transform.hpp"
11 
12 namespace ts = utils::tstring;
13 
14 TriggerFactory::TriggerFactory(
15     std::shared_ptr<sdbusplus::asio::connection> bus,
16     std::shared_ptr<sdbusplus::asio::object_server> objServer,
17     SensorCache& sensorCache, interfaces::ReportManager& reportManager) :
18     bus(std::move(bus)),
19     objServer(std::move(objServer)), sensorCache(sensorCache),
20     reportManager(reportManager)
21 {}
22 
23 void TriggerFactory::updateDiscreteThresholds(
24     std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds,
25     const std::vector<TriggerAction>& triggerActions,
26     const std::shared_ptr<std::vector<std::string>>& reportIds,
27     const Sensors& sensors,
28     const std::vector<discrete::LabeledThresholdParam>& newParams) const
29 {
30     auto oldThresholds = currentThresholds;
31     std::vector<std::shared_ptr<interfaces::Threshold>> newThresholds;
32 
33     bool isCurrentOnChange = false;
34     if (oldThresholds.size() == 1 &&
35         std::holds_alternative<std::monostate>(
36             oldThresholds.back()->getThresholdParam()))
37     {
38         isCurrentOnChange = true;
39     }
40 
41     newThresholds.reserve(newParams.size());
42 
43     if (!isCurrentOnChange)
44     {
45         for (const auto& labeledThresholdParam : newParams)
46         {
47             auto paramChecker = [labeledThresholdParam](auto threshold) {
48                 return labeledThresholdParam ==
49                        std::get<discrete::LabeledThresholdParam>(
50                            threshold->getThresholdParam());
51             };
52             if (auto existing = std::find_if(oldThresholds.begin(),
53                                              oldThresholds.end(), paramChecker);
54                 existing != oldThresholds.end())
55             {
56                 newThresholds.emplace_back(*existing);
57                 oldThresholds.erase(existing);
58                 continue;
59             }
60 
61             makeDiscreteThreshold(newThresholds, triggerActions, reportIds,
62                                   sensors, labeledThresholdParam);
63         }
64     }
65     else
66     {
67         for (const auto& labeledThresholdParam : newParams)
68         {
69             makeDiscreteThreshold(newThresholds, triggerActions, reportIds,
70                                   sensors, labeledThresholdParam);
71         }
72     }
73     if (newParams.empty())
74     {
75         if (isCurrentOnChange)
76         {
77             newThresholds.emplace_back(*oldThresholds.begin());
78         }
79         else
80         {
81             makeOnChangeThreshold(newThresholds, triggerActions, reportIds,
82                                   sensors);
83         }
84     }
85     currentThresholds = std::move(newThresholds);
86 }
87 
88 void TriggerFactory::updateNumericThresholds(
89     std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds,
90     const std::vector<TriggerAction>& triggerActions,
91     const std::shared_ptr<std::vector<std::string>>& reportIds,
92     const Sensors& sensors,
93     const std::vector<numeric::LabeledThresholdParam>& newParams) const
94 {
95     auto oldThresholds = currentThresholds;
96     std::vector<std::shared_ptr<interfaces::Threshold>> newThresholds;
97 
98     newThresholds.reserve(newParams.size());
99 
100     for (const auto& labeledThresholdParam : newParams)
101     {
102         auto paramChecker = [labeledThresholdParam](auto threshold) {
103             return labeledThresholdParam ==
104                    std::get<numeric::LabeledThresholdParam>(
105                        threshold->getThresholdParam());
106         };
107         if (auto existing = std::find_if(oldThresholds.begin(),
108                                          oldThresholds.end(), paramChecker);
109             existing != oldThresholds.end())
110         {
111             newThresholds.emplace_back(*existing);
112             oldThresholds.erase(existing);
113             continue;
114         }
115 
116         makeNumericThreshold(newThresholds, triggerActions, reportIds, sensors,
117                              labeledThresholdParam);
118     }
119     currentThresholds = std::move(newThresholds);
120 }
121 
122 void TriggerFactory::updateThresholds(
123     std::vector<std::shared_ptr<interfaces::Threshold>>& currentThresholds,
124     const std::vector<TriggerAction>& triggerActions,
125     const std::shared_ptr<std::vector<std::string>>& reportIds,
126     const Sensors& sensors,
127     const LabeledTriggerThresholdParams& newParams) const
128 {
129     if (isTriggerThresholdDiscrete(newParams))
130     {
131         const auto& labeledDiscreteThresholdParams =
132             std::get<std::vector<discrete::LabeledThresholdParam>>(newParams);
133 
134         updateDiscreteThresholds(currentThresholds, triggerActions, reportIds,
135                                  sensors, labeledDiscreteThresholdParams);
136     }
137     else
138     {
139         const auto& labeledNumericThresholdParams =
140             std::get<std::vector<numeric::LabeledThresholdParam>>(newParams);
141 
142         updateNumericThresholds(currentThresholds, triggerActions, reportIds,
143                                 sensors, labeledNumericThresholdParams);
144     }
145 }
146 
147 void TriggerFactory::makeDiscreteThreshold(
148     std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds,
149     const std::vector<TriggerAction>& triggerActions,
150     const std::shared_ptr<std::vector<std::string>>& reportIds,
151     const Sensors& sensors,
152     const discrete::LabeledThresholdParam& thresholdParam) const
153 {
154     std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
155 
156     std::string thresholdName = thresholdParam.at_label<ts::UserId>();
157     discrete::Severity severity = thresholdParam.at_label<ts::Severity>();
158     auto dwellTime = Milliseconds(thresholdParam.at_label<ts::DwellTime>());
159     std::string thresholdValue = thresholdParam.at_label<ts::ThresholdValue>();
160 
161     action::discrete::fillActions(actions, triggerActions, severity,
162                                   reportManager, reportIds);
163 
164     thresholds.emplace_back(std::make_shared<DiscreteThreshold>(
165         bus->get_io_context(), sensors, std::move(actions),
166         Milliseconds(dwellTime), std::stod(thresholdValue), thresholdName,
167         severity));
168 }
169 
170 void TriggerFactory::makeNumericThreshold(
171     std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds,
172     const std::vector<TriggerAction>& triggerActions,
173     const std::shared_ptr<std::vector<std::string>>& reportIds,
174     const Sensors& sensors,
175     const numeric::LabeledThresholdParam& thresholdParam) const
176 {
177     std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
178 
179     auto type = thresholdParam.at_label<ts::Type>();
180     auto dwellTime = Milliseconds(thresholdParam.at_label<ts::DwellTime>());
181     auto direction = thresholdParam.at_label<ts::Direction>();
182     auto thresholdValue = double{thresholdParam.at_label<ts::ThresholdValue>()};
183 
184     action::numeric::fillActions(actions, triggerActions, type, thresholdValue,
185                                  reportManager, reportIds);
186 
187     thresholds.emplace_back(std::make_shared<NumericThreshold>(
188         bus->get_io_context(), sensors, std::move(actions), dwellTime,
189         direction, thresholdValue, type));
190 }
191 
192 void TriggerFactory::makeOnChangeThreshold(
193     std::vector<std::shared_ptr<interfaces::Threshold>>& thresholds,
194     const std::vector<TriggerAction>& triggerActions,
195     const std::shared_ptr<std::vector<std::string>>& reportIds,
196     const Sensors& sensors) const
197 {
198     std::vector<std::unique_ptr<interfaces::TriggerAction>> actions;
199 
200     action::discrete::onChange::fillActions(actions, triggerActions,
201                                             reportManager, reportIds);
202 
203     thresholds.emplace_back(
204         std::make_shared<OnChangeThreshold>(sensors, std::move(actions)));
205 }
206 
207 std::unique_ptr<interfaces::Trigger> TriggerFactory::make(
208     const std::string& id, const std::string& name,
209     const std::vector<std::string>& triggerActionsIn,
210     const std::vector<std::string>& reportIdsIn,
211     interfaces::TriggerManager& triggerManager,
212     interfaces::JsonStorage& triggerStorage,
213     const LabeledTriggerThresholdParams& labeledThresholdParams,
214     const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const
215 {
216     const auto& sensors = getSensors(labeledSensorsInfo);
217     auto triggerActions =
218         utils::transform(triggerActionsIn, [](const auto& triggerActionStr) {
219             return toTriggerAction(triggerActionStr);
220         });
221     std::vector<std::shared_ptr<interfaces::Threshold>> thresholds;
222 
223     auto reportIds = std::make_shared<std::vector<std::string>>(reportIdsIn);
224 
225     updateThresholds(thresholds, triggerActions, reportIds, sensors,
226                      labeledThresholdParams);
227 
228     return std::make_unique<Trigger>(
229         bus->get_io_context(), objServer, id, name, triggerActions, reportIds,
230         std::move(thresholds), triggerManager, triggerStorage, *this, sensors,
231         reportManager);
232 }
233 
234 Sensors TriggerFactory::getSensors(
235     const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const
236 {
237     Sensors sensors;
238     updateSensors(sensors, labeledSensorsInfo);
239     return sensors;
240 }
241 
242 void TriggerFactory::updateSensors(
243     Sensors& currentSensors,
244     const std::vector<LabeledSensorInfo>& labeledSensorsInfo) const
245 {
246     Sensors oldSensors = currentSensors;
247     Sensors newSensors;
248 
249     for (const auto& labeledSensorInfo : labeledSensorsInfo)
250     {
251         auto existing = std::find_if(oldSensors.begin(), oldSensors.end(),
252                                      [labeledSensorInfo](auto sensor) {
253                                          return labeledSensorInfo ==
254                                                 sensor->getLabeledSensorInfo();
255                                      });
256 
257         if (existing != oldSensors.end())
258         {
259             newSensors.emplace_back(*existing);
260             oldSensors.erase(existing);
261             continue;
262         }
263 
264         const auto& service = labeledSensorInfo.at_label<ts::Service>();
265         const auto& sensorPath = labeledSensorInfo.at_label<ts::Path>();
266         const auto& metadata = labeledSensorInfo.at_label<ts::Metadata>();
267 
268         newSensors.emplace_back(sensorCache.makeSensor<Sensor>(
269             service, sensorPath, metadata, bus->get_io_context(), bus));
270     }
271 
272     currentSensors = std::move(newSensors);
273 }
274 
275 std::vector<LabeledSensorInfo>
276     TriggerFactory::getLabeledSensorsInfo(boost::asio::yield_context& yield,
277                                           const SensorsInfo& sensorsInfo) const
278 {
279     if (sensorsInfo.empty())
280     {
281         return {};
282     }
283     auto tree = utils::getSubTreeSensors(yield, bus);
284     return parseSensorTree(tree, sensorsInfo);
285 }
286 
287 std::vector<LabeledSensorInfo>
288     TriggerFactory::getLabeledSensorsInfo(const SensorsInfo& sensorsInfo) const
289 {
290     if (sensorsInfo.empty())
291     {
292         return {};
293     }
294     auto tree = utils::getSubTreeSensors(bus);
295     return parseSensorTree(tree, sensorsInfo);
296 }
297 
298 std::vector<LabeledSensorInfo>
299     TriggerFactory::parseSensorTree(const std::vector<utils::SensorTree>& tree,
300                                     const SensorsInfo& sensorsInfo)
301 {
302     return utils::transform(sensorsInfo, [&tree](const auto& item) {
303         const auto& [sensorPath, metadata] = item;
304         auto found = std::find_if(
305             tree.begin(), tree.end(),
306             [path = sensorPath](const auto& x) { return x.first == path; });
307 
308         if (tree.end() != found)
309         {
310             const auto& [service, ifaces] = found->second.front();
311             return LabeledSensorInfo(service, sensorPath, metadata);
312         }
313         throw std::runtime_error("Not found");
314     });
315 }
316