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