xref: /openbmc/telemetry/src/trigger.cpp (revision 32305f14d8a7560980735c04fbb2067d633e08d8)
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 
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(
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(
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                 "Thresholds", TriggerThresholdParams{},
74                 sdbusplus::vtable::property_::emits_change,
75                 [this, &triggerFactory](auto newVal, auto& oldVal) {
76                     auto newThresholdParams = std::visit(
77                         utils::ToLabeledThresholdParamConversion(), newVal);
78                     TriggerManager::verifyThresholdParams(newThresholdParams);
79                     triggerFactory.updateThresholds(
80                         thresholds, *id, triggerActions, reportIds, sensors,
81                         newThresholdParams);
82                     oldVal = std::move(newVal);
83                     return 1;
84                 },
85                 [this](const auto&) {
86                     return fromLabeledThresholdParam(getLabeledThresholds());
87                 });
88 
89             dbusIface.register_property_rw(
90                 "Sensors", SensorsInfo{},
91                 sdbusplus::vtable::property_::emits_change,
92                 [this, &triggerFactory](auto newVal, auto& oldVal) {
93                     auto labeledSensorInfo =
94                         triggerFactory.getLabeledSensorsInfo(newVal);
95                     triggerFactory.updateSensors(sensors, labeledSensorInfo);
96                     for (const auto& threshold : thresholds)
97                     {
98                         threshold->updateSensors(sensors);
99                     }
100                     oldVal = std::move(newVal);
101                     return 1;
102                 },
103                 [this](const auto&) {
104                     return utils::fromLabeledSensorsInfo(
105                         getLabeledSensorInfo());
106                 });
107 
108             dbusIface.register_property_rw(
109                 "Reports", std::vector<sdbusplus::message::object_path>(),
110                 sdbusplus::vtable::property_::emits_change,
111                 [this](auto newVal, auto& oldVal) {
112                     auto newReportIds = utils::transform<std::vector>(
113                         newVal, [](const auto& path) {
114                             return utils::reportPathToId(path);
115                         });
116                     TriggerManager::verifyReportIds(newReportIds);
117                     *reportIds = newReportIds;
118                     messanger.send(messages::TriggerPresenceChangedInd{
119                         messages::Presence::Exist, *id, *reportIds});
120                     oldVal = std::move(newVal);
121                     return 1;
122                 },
123                 [this](const auto&) {
124                     return utils::transform<std::vector>(
125                         *reportIds, [](const auto& id) {
126                             return utils::pathAppend(
127                                 utils::constants::reportDirPath, id);
128                         });
129                 });
130 
131             dbusIface.register_property_r(
132                 "Discrete", isDiscreate(), sdbusplus::vtable::property_::const_,
133                 [this](const auto& x) { return isDiscreate(); });
134 
135             dbusIface.register_property_rw(
136                 "Name", name, sdbusplus::vtable::property_::emits_change,
137                 [this](auto newVal, auto& oldVal) {
138                     if (newVal.length() > utils::constants::maxIdNameLength)
139                     {
140                         throw sdbusplus::exception::SdBusError(
141                             static_cast<int>(std::errc::invalid_argument),
142                             "Name is too long");
143                     }
144                     name = oldVal = newVal;
145                     return 1;
146                 },
147                 [this](const auto&) { return name; });
148 
149             dbusIface.register_property_r(
150                 "TriggerActions", std::vector<std::string>(),
151                 sdbusplus::vtable::property_::const_, [this](const auto&) {
152                     return utils::transform(triggerActions,
153                                             [](const auto& action) {
154                                                 return actionToString(action);
155                                             });
156                 });
157         });
158 
159     for (const auto& threshold : thresholds)
160     {
161         threshold->initialize();
162     }
163 
164     messanger.on_receive<messages::CollectTriggerIdReq>(
165         [this](const auto& msg) {
166             if (utils::contains(*reportIds, msg.reportId))
167             {
168                 messanger.send(messages::CollectTriggerIdResp{*id});
169             }
170         });
171 
172     messanger.send(messages::TriggerPresenceChangedInd{
173         messages::Presence::Exist, *id, *reportIds});
174 }
175 
176 bool Trigger::storeConfiguration() const
177 {
178     try
179     {
180         nlohmann::json data;
181 
182         auto labeledThresholdParams =
183             std::visit(utils::ToLabeledThresholdParamConversion(),
184                        fromLabeledThresholdParam(getLabeledThresholds()));
185 
186         data["Version"] = triggerVersion;
187         data["Id"] = *id;
188         data["Name"] = name;
189         data["ThresholdParamsDiscriminator"] = labeledThresholdParams.index();
190         data["TriggerActions"] =
191             utils::transform(triggerActions, [](const auto& action) {
192                 return actionToString(action);
193             });
194         data["ThresholdParams"] =
195             utils::labeledThresholdParamsToJson(labeledThresholdParams);
196         data["ReportIds"] = *reportIds;
197         data["Sensors"] = getLabeledSensorInfo();
198 
199         triggerStorage.store(fileName, data);
200     }
201     catch (const std::exception& e)
202     {
203         phosphor::logging::log<phosphor::logging::level::ERR>(
204             "Failed to store a trigger in storage",
205             phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
206         return false;
207     }
208     return true;
209 }
210 
211 std::vector<LabeledSensorInfo> Trigger::getLabeledSensorInfo() const
212 {
213     return utils::transform(sensors, [](const auto& sensor) {
214         return sensor->getLabeledSensorInfo();
215     });
216 }
217 
218 std::vector<LabeledThresholdParam> Trigger::getLabeledThresholds() const
219 {
220     return utils::transform(thresholds, [](const auto& threshold) {
221         return threshold->getThresholdParam();
222     });
223 }
224 
225 bool Trigger::isDiscreate() const
226 {
227     const auto labeledThresholds = getLabeledThresholds();
228 
229     return utils::isFirstElementOfType<std::monostate>(labeledThresholds) ||
230            utils::isFirstElementOfType<discrete::LabeledThresholdParam>(
231                labeledThresholds);
232 }
233