xref: /openbmc/telemetry/src/trigger.cpp (revision 2efa95d8faec80ee1eb2ce500e2cb08849cd478e)
1 #include "trigger.hpp"
2 
3 #include "messages/collect_trigger_id.hpp"
4 #include "messages/trigger_presence_changed_ind.hpp"
5 #include "trigger_manager.hpp"
6 #include "types/report_types.hpp"
7 #include "types/trigger_types.hpp"
8 #include "utils/contains.hpp"
9 #include "utils/conversion_trigger.hpp"
10 #include "utils/dbus_path_utils.hpp"
11 #include "utils/transform.hpp"
12 
13 #include <phosphor-logging/log.hpp>
14 
Trigger(boost::asio::io_context & ioc,const std::shared_ptr<sdbusplus::asio::object_server> & objServer,TriggerId && idIn,const std::string & nameIn,const std::vector<TriggerAction> & triggerActionsIn,const std::shared_ptr<std::vector<std::string>> reportIdsIn,std::vector<std::shared_ptr<interfaces::Threshold>> && thresholdsIn,interfaces::TriggerManager & triggerManager,interfaces::JsonStorage & triggerStorageIn,const interfaces::TriggerFactory & triggerFactory,Sensors sensorsIn)15 Trigger::Trigger(
16     boost::asio::io_context& ioc,
17     const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
18     TriggerId&& idIn, const std::string& nameIn,
19     const std::vector<TriggerAction>& triggerActionsIn,
20     const std::shared_ptr<std::vector<std::string>> reportIdsIn,
21     std::vector<std::shared_ptr<interfaces::Threshold>>&& thresholdsIn,
22     interfaces::TriggerManager& triggerManager,
23     interfaces::JsonStorage& triggerStorageIn,
24     const interfaces::TriggerFactory& triggerFactory, Sensors sensorsIn) :
25     id(std::move(idIn)),
26     path(utils::pathAppend(utils::constants::triggerDirPath, *id)),
27     name(nameIn), triggerActions(std::move(triggerActionsIn)),
28     reportIds(std::move(reportIdsIn)), thresholds(std::move(thresholdsIn)),
29     fileName(std::to_string(std::hash<std::string>{}(*id))),
30     triggerStorage(triggerStorageIn), sensors(std::move(sensorsIn)),
31     messanger(ioc)
32 {
33     deleteIface = objServer->add_unique_interface(
__anon5e4599b80102(auto& dbusIface) 34         path, deleteIfaceName, [this, &ioc, &triggerManager](auto& dbusIface) {
35         dbusIface.register_method("Delete", [this, &ioc, &triggerManager] {
36             if (persistent)
37             {
38                 triggerStorage.remove(fileName);
39             }
40             messanger.send(messages::TriggerPresenceChangedInd{
41                 messages::Presence::Removed, *id, {}});
42             boost::asio::post(ioc, [this, &triggerManager] {
43                 triggerManager.removeTrigger(this);
44             });
45         });
46     });
47 
48     triggerIface = objServer->add_unique_interface(
__anon5e4599b80402(auto& dbusIface) 49         path, triggerIfaceName, [this, &triggerFactory](auto& dbusIface) {
50         persistent = storeConfiguration();
51         dbusIface.register_property_rw(
52             "Persistent", persistent,
53             sdbusplus::vtable::property_::emits_change,
54             [this](bool newVal, const auto&) {
55             if (newVal == persistent)
56             {
57                 return 1;
58             }
59             if (newVal)
60             {
61                 persistent = storeConfiguration();
62             }
63             else
64             {
65                 triggerStorage.remove(fileName);
66                 persistent = false;
67             }
68             return 1;
69         }, [this](const auto&) { return persistent; });
70 
71         dbusIface.register_property_rw(
72             "Thresholds", TriggerThresholdParams{},
73             sdbusplus::vtable::property_::emits_change,
74             [this, &triggerFactory](auto newVal, auto& oldVal) {
75             auto newThresholdParams =
76                 std::visit(utils::ToLabeledThresholdParamConversion(), newVal);
77             TriggerManager::verifyThresholdParams(newThresholdParams);
78             triggerFactory.updateThresholds(thresholds, *id, triggerActions,
79                                             reportIds, sensors,
80                                             newThresholdParams);
81             oldVal = std::move(newVal);
82             return 1;
83         }, [this](const auto&) {
84             return fromLabeledThresholdParam(getLabeledThresholds());
85         });
86 
87         dbusIface.register_property_rw(
88             "DiscreteThresholds", std::vector<discrete::ThresholdParam>{},
89             sdbusplus::vtable::property_::emits_change,
90             [this, &triggerFactory](
91                 const std::vector<discrete::ThresholdParam>& newVal,
92                 std::vector<discrete::ThresholdParam>& oldVal) {
93             LabeledTriggerThresholdParams newThresholdParams =
94                 utils::ToLabeledThresholdParamConversion()(newVal);
95             TriggerManager::verifyThresholdParams(newThresholdParams);
96             triggerFactory.updateThresholds(thresholds, *id, triggerActions,
97                                             reportIds, sensors,
98                                             newThresholdParams);
99             oldVal = std::move(newVal);
100             return 1;
101         },
102             [this](const auto&) {
103             TriggerThresholdParams unlabeled =
104                 fromLabeledThresholdParam(getLabeledThresholds());
105             auto* ptr =
106                 std::get_if<std::vector<discrete::ThresholdParam>>(&unlabeled);
107             if (ptr == nullptr)
108             {
109                 // If internal type doesn't match, return empty set
110                 return std::vector<discrete::ThresholdParam>{};
111             }
112             return *ptr;
113         });
114 
115         dbusIface.register_property_rw(
116             "NumericThresholds", std::vector<numeric::ThresholdParam>{},
117             sdbusplus::vtable::property_::emits_change,
118             [this, &triggerFactory](
119                 const std::vector<numeric::ThresholdParam>& newVal,
120                 std::vector<numeric::ThresholdParam>& oldVal) {
121             LabeledTriggerThresholdParams newThresholdParams =
122                 utils::ToLabeledThresholdParamConversion()(newVal);
123             TriggerManager::verifyThresholdParams(newThresholdParams);
124             triggerFactory.updateThresholds(thresholds, *id, triggerActions,
125                                             reportIds, sensors,
126                                             newThresholdParams);
127             oldVal = std::move(newVal);
128             return 1;
129         },
130             [this](const auto&) {
131             TriggerThresholdParams unlabeled =
132                 fromLabeledThresholdParam(getLabeledThresholds());
133             auto* ptr =
134                 std::get_if<std::vector<numeric::ThresholdParam>>(&unlabeled);
135             if (ptr == nullptr)
136             {
137                 // If internal type doesn't match, return empty set
138                 return std::vector<numeric::ThresholdParam>{};
139             }
140             return *ptr;
141         });
142         dbusIface.register_property_rw(
143             "Sensors", SensorsInfo{},
144             sdbusplus::vtable::property_::emits_change,
145             [this, &triggerFactory](auto newVal, auto& oldVal) {
146             auto labeledSensorInfo =
147                 triggerFactory.getLabeledSensorsInfo(newVal);
148             triggerFactory.updateSensors(sensors, labeledSensorInfo);
149             for (const auto& threshold : thresholds)
150             {
151                 threshold->updateSensors(sensors);
152             }
153             oldVal = std::move(newVal);
154             return 1;
155         }, [this](const auto&) {
156             return utils::fromLabeledSensorsInfo(getLabeledSensorInfo());
157         });
158 
159         dbusIface.register_property_rw(
160             "Reports", std::vector<sdbusplus::message::object_path>(),
161             sdbusplus::vtable::property_::emits_change,
162             [this](auto newVal, auto& oldVal) {
163             auto newReportIds = utils::transform<std::vector>(
164                 newVal,
165                 [](const auto& path) { return utils::reportPathToId(path); });
166             TriggerManager::verifyReportIds(newReportIds);
167             *reportIds = newReportIds;
168             messanger.send(messages::TriggerPresenceChangedInd{
169                 messages::Presence::Exist, *id, *reportIds});
170             oldVal = std::move(newVal);
171             return 1;
172         }, [this](const auto&) {
173             return utils::transform<std::vector>(*reportIds,
174                                                  [](const auto& id) {
175                 return utils::pathAppend(utils::constants::reportDirPath, id);
176             });
177         });
178 
179         dbusIface.register_property_r(
180             "Discrete", isDiscreate(), sdbusplus::vtable::property_::const_,
181             [this](const auto& x) { return isDiscreate(); });
182 
183         dbusIface.register_property_rw(
184             "Name", name, sdbusplus::vtable::property_::emits_change,
185             [this](auto newVal, auto& oldVal) {
186             if (newVal.length() > utils::constants::maxIdNameLength)
187             {
188                 throw errors::InvalidArgument("Name", "Name is too long.");
189             }
190             name = oldVal = newVal;
191             return 1;
192         }, [this](const auto&) { return name; });
193 
194         dbusIface.register_property_r(
195             "TriggerActions", std::vector<std::string>(),
196             sdbusplus::vtable::property_::const_, [this](const auto&) {
197             return utils::transform(triggerActions, [](const auto& action) {
198                 return actionToString(action);
199             });
200         });
201     });
202 
203     for (const auto& threshold : thresholds)
204     {
205         threshold->initialize();
206     }
207 
208     messanger.on_receive<messages::CollectTriggerIdReq>(
__anon5e4599b81802(const auto& msg) 209         [this](const auto& msg) {
210         if (utils::contains(*reportIds, msg.reportId))
211         {
212             messanger.send(messages::CollectTriggerIdResp{*id});
213         }
214     });
215 
216     messanger.send(messages::TriggerPresenceChangedInd{
217         messages::Presence::Exist, *id, *reportIds});
218 }
219 
storeConfiguration() const220 bool Trigger::storeConfiguration() const
221 {
222     try
223     {
224         nlohmann::json data;
225 
226         auto labeledThresholdParams =
227             std::visit(utils::ToLabeledThresholdParamConversion(),
228                        fromLabeledThresholdParam(getLabeledThresholds()));
229 
230         data["Version"] = triggerVersion;
231         data["Id"] = *id;
232         data["Name"] = name;
233         data["ThresholdParamsDiscriminator"] = labeledThresholdParams.index();
234         data["TriggerActions"] = utils::transform(
235             triggerActions,
236             [](const auto& action) { return actionToString(action); });
237         data["ThresholdParams"] =
238             utils::labeledThresholdParamsToJson(labeledThresholdParams);
239         data["ReportIds"] = *reportIds;
240         data["Sensors"] = getLabeledSensorInfo();
241 
242         triggerStorage.store(fileName, data);
243     }
244     catch (const std::exception& e)
245     {
246         phosphor::logging::log<phosphor::logging::level::ERR>(
247             "Failed to store a trigger in storage",
248             phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
249         return false;
250     }
251     return true;
252 }
253 
getLabeledSensorInfo() const254 std::vector<LabeledSensorInfo> Trigger::getLabeledSensorInfo() const
255 {
256     return utils::transform(sensors, [](const auto& sensor) {
257         return sensor->getLabeledSensorInfo();
258     });
259 }
260 
getLabeledThresholds() const261 std::vector<LabeledThresholdParam> Trigger::getLabeledThresholds() const
262 {
263     return utils::transform(thresholds, [](const auto& threshold) {
264         return threshold->getThresholdParam();
265     });
266 }
267 
isDiscreate() const268 bool Trigger::isDiscreate() const
269 {
270     const auto labeledThresholds = getLabeledThresholds();
271 
272     return utils::isFirstElementOfType<std::monostate>(labeledThresholds) ||
273            utils::isFirstElementOfType<discrete::LabeledThresholdParam>(
274                labeledThresholds);
275 }
276