xref: /openbmc/telemetry/src/trigger.cpp (revision 995ebe7ef29c9890e87aa4c0e6772f7a586146da)
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                 },
70                 [this](const auto&) { return persistent; });
71 
72             dbusIface.register_property_rw(
73                 "DiscreteThresholds", std::vector<discrete::ThresholdParam>{},
74                 sdbusplus::vtable::property_::emits_change,
75                 [this, &triggerFactory](
76                     const std::vector<discrete::ThresholdParam>& newVal,
77                     std::vector<discrete::ThresholdParam>& oldVal) {
78                     LabeledTriggerThresholdParams newThresholdParams =
79                         utils::ToLabeledThresholdParamConversion()(newVal);
80                     TriggerManager::verifyThresholdParams(newThresholdParams);
81                     triggerFactory.updateThresholds(
82                         thresholds, *id, triggerActions, reportIds, sensors,
83                         newThresholdParams);
84                     oldVal = std::move(newVal);
85                     return 1;
86                 },
87                 [this](const auto&) {
88                     TriggerThresholdParams unlabeled =
89                         fromLabeledThresholdParam(getLabeledThresholds());
90                     auto* ptr =
91                         std::get_if<std::vector<discrete::ThresholdParam>>(
92                             &unlabeled);
93                     if (ptr == nullptr)
94                     {
95                         // If internal type doesn't match, return empty set
96                         return std::vector<discrete::ThresholdParam>{};
97                     }
98                     return *ptr;
99                 });
100 
101             dbusIface.register_property_rw(
102                 "NumericThresholds", std::vector<numeric::ThresholdParam>{},
103                 sdbusplus::vtable::property_::emits_change,
104                 [this, &triggerFactory](
105                     const std::vector<numeric::ThresholdParam>& newVal,
106                     std::vector<numeric::ThresholdParam>& oldVal) {
107                     LabeledTriggerThresholdParams newThresholdParams =
108                         utils::ToLabeledThresholdParamConversion()(newVal);
109                     TriggerManager::verifyThresholdParams(newThresholdParams);
110                     triggerFactory.updateThresholds(
111                         thresholds, *id, triggerActions, reportIds, sensors,
112                         newThresholdParams);
113                     oldVal = std::move(newVal);
114                     return 1;
115                 },
116                 [this](const auto&) {
117                     TriggerThresholdParams unlabeled =
118                         fromLabeledThresholdParam(getLabeledThresholds());
119                     auto* ptr =
120                         std::get_if<std::vector<numeric::ThresholdParam>>(
121                             &unlabeled);
122                     if (ptr == nullptr)
123                     {
124                         // If internal type doesn't match, return empty set
125                         return std::vector<numeric::ThresholdParam>{};
126                     }
127                     return *ptr;
128                 });
129             dbusIface.register_property_rw(
130                 "Sensors", SensorsInfo{},
131                 sdbusplus::vtable::property_::emits_change,
132                 [this, &triggerFactory](auto newVal, auto& oldVal) {
133                     auto labeledSensorInfo =
134                         triggerFactory.getLabeledSensorsInfo(newVal);
135                     triggerFactory.updateSensors(sensors, labeledSensorInfo);
136                     for (const auto& threshold : thresholds)
137                     {
138                         threshold->updateSensors(sensors);
139                     }
140                     oldVal = std::move(newVal);
141                     return 1;
142                 },
143                 [this](const auto&) {
144                     return utils::fromLabeledSensorsInfo(
145                         getLabeledSensorInfo());
146                 });
147 
148             dbusIface.register_property_rw(
149                 "Reports", std::vector<sdbusplus::message::object_path>(),
150                 sdbusplus::vtable::property_::emits_change,
151                 [this](auto newVal, auto& oldVal) {
152                     auto newReportIds = utils::transform<std::vector>(
153                         newVal, [](const auto& path) {
154                             return utils::reportPathToId(path);
155                         });
156                     TriggerManager::verifyReportIds(newReportIds);
157                     *reportIds = newReportIds;
158                     messanger.send(messages::TriggerPresenceChangedInd{
159                         messages::Presence::Exist, *id, *reportIds});
160                     oldVal = std::move(newVal);
161                     return 1;
162                 },
163                 [this](const auto&) {
164                     return utils::transform<std::vector>(
165                         *reportIds, [](const auto& id) {
166                             return utils::pathAppend(
167                                 utils::constants::reportDirPath, id);
168                         });
169                 });
170 
171             dbusIface.register_property_r(
172                 "Discrete", isDiscrete(), sdbusplus::vtable::property_::const_,
173                 [this](const auto& x) { return isDiscrete(); });
174 
175             dbusIface.register_property_rw(
176                 "Name", name, sdbusplus::vtable::property_::emits_change,
177                 [this](auto newVal, auto& oldVal) {
178                     if (newVal.length() > utils::constants::maxIdNameLength)
179                     {
180                         throw errors::InvalidArgument("Name",
181                                                       "Name is too long.");
182                     }
183                     name = oldVal = newVal;
184                     return 1;
185                 },
186                 [this](const auto&) { return name; });
187 
188             dbusIface.register_property_r(
189                 "TriggerActions", std::vector<std::string>(),
190                 sdbusplus::vtable::property_::const_, [this](const auto&) {
191                     return utils::transform(triggerActions,
192                                             [](const auto& action) {
193                                                 return actionToString(action);
194                                             });
195                 });
196         });
197 
198     for (const auto& threshold : thresholds)
199     {
200         threshold->initialize();
201     }
202 
203     messanger.on_receive<messages::CollectTriggerIdReq>(
__anon5e4599b81602(const auto& msg) 204         [this](const auto& msg) {
205             if (utils::contains(*reportIds, msg.reportId))
206             {
207                 messanger.send(messages::CollectTriggerIdResp{*id});
208             }
209         });
210 
211     messanger.send(messages::TriggerPresenceChangedInd{
212         messages::Presence::Exist, *id, *reportIds});
213 }
214 
storeConfiguration() const215 bool Trigger::storeConfiguration() const
216 {
217     try
218     {
219         nlohmann::json data;
220 
221         auto labeledThresholdParams =
222             std::visit(utils::ToLabeledThresholdParamConversion(),
223                        fromLabeledThresholdParam(getLabeledThresholds()));
224 
225         data["Version"] = triggerVersion;
226         data["Id"] = *id;
227         data["Name"] = name;
228         data["ThresholdParamsDiscriminator"] = labeledThresholdParams.index();
229         data["TriggerActions"] =
230             utils::transform(triggerActions, [](const auto& action) {
231                 return actionToString(action);
232             });
233         data["ThresholdParams"] =
234             utils::labeledThresholdParamsToJson(labeledThresholdParams);
235         data["ReportIds"] = *reportIds;
236         data["Sensors"] = getLabeledSensorInfo();
237 
238         triggerStorage.store(fileName, data);
239     }
240     catch (const std::exception& e)
241     {
242         phosphor::logging::log<phosphor::logging::level::ERR>(
243             "Failed to store a trigger in storage",
244             phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
245         return false;
246     }
247     return true;
248 }
249 
getLabeledSensorInfo() const250 std::vector<LabeledSensorInfo> Trigger::getLabeledSensorInfo() const
251 {
252     return utils::transform(sensors, [](const auto& sensor) {
253         return sensor->getLabeledSensorInfo();
254     });
255 }
256 
getLabeledThresholds() const257 std::vector<LabeledThresholdParam> Trigger::getLabeledThresholds() const
258 {
259     return utils::transform(thresholds, [](const auto& threshold) {
260         return threshold->getThresholdParam();
261     });
262 }
263 
isDiscrete() const264 bool Trigger::isDiscrete() const
265 {
266     const auto labeledThresholds = getLabeledThresholds();
267     if (labeledThresholds.empty())
268     {
269         return true;
270     }
271 
272     return utils::isFirstElementOfType<std::monostate>(labeledThresholds) ||
273            utils::isFirstElementOfType<discrete::LabeledThresholdParam>(
274                labeledThresholds);
275 }
276