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