xref: /openbmc/telemetry/src/trigger.cpp (revision b4ef22e4d365bde35a7fce7950033c9271c68ce7)
1 #include "trigger.hpp"
2 
3 #include "trigger_manager.hpp"
4 #include "types/report_types.hpp"
5 #include "types/trigger_types.hpp"
6 #include "utils/conversion_trigger.hpp"
7 #include "utils/transform.hpp"
8 
9 #include <phosphor-logging/log.hpp>
10 
11 Trigger::Trigger(
12     boost::asio::io_context& ioc,
13     const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
14     const std::string& idIn, const std::string& nameIn,
15     const std::vector<TriggerAction>& triggerActionsIn,
16     const std::shared_ptr<std::vector<std::string>> reportIdsIn,
17     std::vector<std::shared_ptr<interfaces::Threshold>>&& thresholdsIn,
18     interfaces::TriggerManager& triggerManager,
19     interfaces::JsonStorage& triggerStorageIn,
20     const interfaces::TriggerFactory& triggerFactory, Sensors sensorsIn,
21     interfaces::ReportManager& reportManagerIn) :
22     id(idIn),
23     name(nameIn), triggerActions(std::move(triggerActionsIn)),
24     path(triggerDir + id), reportIds(std::move(reportIdsIn)),
25     thresholds(std::move(thresholdsIn)),
26     fileName(std::to_string(std::hash<std::string>{}(id))),
27     triggerStorage(triggerStorageIn), sensors(std::move(sensorsIn)),
28     reportManager(reportManagerIn)
29 {
30     deleteIface = objServer->add_unique_interface(
31         path, deleteIfaceName, [this, &ioc, &triggerManager](auto& dbusIface) {
32             dbusIface.register_method("Delete", [this, &ioc, &triggerManager] {
33                 if (persistent)
34                 {
35                     triggerStorage.remove(fileName);
36                 }
37                 for (const auto& reportId : *reportIds)
38                 {
39                     reportManager.updateTriggerIds(reportId, id,
40                                                    TriggerIdUpdate::Remove);
41                 }
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                     triggerFactory.updateThresholds(thresholds, triggerActions,
79                                                     reportIds, sensors,
80                                                     newThresholdParams);
81                     oldVal = std::move(newVal);
82                     return 1;
83                 },
84                 [this](const auto&) {
85                     return fromLabeledThresholdParam(
86                         utils::transform(thresholds, [](const auto& threshold) {
87                             return threshold->getThresholdParam();
88                         }));
89                 });
90 
91             dbusIface.register_property_rw(
92                 "Sensors", SensorsInfo{},
93                 sdbusplus::vtable::property_::emits_change,
94                 [this, &triggerFactory](auto newVal, auto& oldVal) {
95                     auto labeledSensorInfo =
96                         triggerFactory.getLabeledSensorsInfo(newVal);
97                     triggerFactory.updateSensors(sensors, labeledSensorInfo);
98                     for (const auto& threshold : thresholds)
99                     {
100                         threshold->updateSensors(sensors);
101                     }
102                     oldVal = std::move(newVal);
103                     return 1;
104                 },
105                 [this](const auto&) {
106                     return utils::fromLabeledSensorsInfo(
107                         utils::transform(sensors, [](const auto& sensor) {
108                             return sensor->getLabeledSensorInfo();
109                         }));
110                 });
111 
112             dbusIface.register_property_rw(
113                 "ReportNames", std::vector<std::string>{},
114                 sdbusplus::vtable::property_::emits_change,
115                 [this](auto newVal, auto& oldVal) {
116                     TriggerManager::verifyReportIds(newVal);
117                     updateTriggerIdsInReports(newVal);
118                     reportIds->clear();
119                     std::copy(newVal.begin(), newVal.end(),
120                               std::back_inserter(*reportIds));
121                     oldVal = std::move(newVal);
122                     return 1;
123                 },
124                 [this](const auto&) { return *reportIds; });
125 
126             dbusIface.register_property_r(
127                 "Discrete", false, sdbusplus::vtable::property_::const_,
128                 [this](const auto& x) {
129                     return !std::holds_alternative<
130                         numeric::LabeledThresholdParam>(
131                         thresholds.back()->getThresholdParam());
132                 });
133 
134             dbusIface.register_property_rw(
135                 "Name", std::string(),
136                 sdbusplus::vtable::property_::emits_change,
137                 [this](auto newVal, auto& oldVal) {
138                     name = oldVal = newVal;
139                     return 1;
140                 },
141                 [this](const auto&) { return name; });
142 
143             dbusIface.register_property_r(
144                 "TriggerActions", std::vector<std::string>(),
145                 sdbusplus::vtable::property_::const_, [this](const auto&) {
146                     return utils::transform(triggerActions,
147                                             [](const auto& action) {
148                                                 return actionToString(action);
149                                             });
150                 });
151         });
152 
153     for (const auto& threshold : thresholds)
154     {
155         threshold->initialize();
156     }
157 
158     for (const auto& reportId : *reportIds)
159     {
160         reportManager.updateTriggerIds(reportId, id, TriggerIdUpdate::Add);
161     }
162 }
163 
164 bool Trigger::storeConfiguration() const
165 {
166     try
167     {
168         nlohmann::json data;
169 
170         auto labeledThresholdParams =
171             std::visit(utils::ToLabeledThresholdParamConversion(),
172                        fromLabeledThresholdParam(utils::transform(
173                            thresholds, [](const auto& threshold) {
174                                return threshold->getThresholdParam();
175                            })));
176 
177         data["Version"] = triggerVersion;
178         data["Id"] = id;
179         data["Name"] = name;
180         data["ThresholdParamsDiscriminator"] = labeledThresholdParams.index();
181         data["TriggerActions"] =
182             utils::transform(triggerActions, [](const auto& action) {
183                 return actionToString(action);
184             });
185         data["ThresholdParams"] =
186             utils::labeledThresholdParamsToJson(labeledThresholdParams);
187         data["ReportIds"] = *reportIds;
188         data["Sensors"] = utils::transform(sensors, [](const auto& sensor) {
189             return sensor->getLabeledSensorInfo();
190         });
191 
192         triggerStorage.store(fileName, data);
193     }
194     catch (const std::exception& e)
195     {
196         phosphor::logging::log<phosphor::logging::level::ERR>(
197             "Failed to store a trigger in storage",
198             phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
199         return false;
200     }
201     return true;
202 }
203 
204 void Trigger::updateTriggerIdsInReports(
205     const std::vector<std::string>& newReportIds)
206 {
207     std::vector<std::string> toBeRemoved, toBeAdded;
208     size_t maxSize = std::max(reportIds->size(), newReportIds.size());
209     toBeRemoved.reserve(maxSize);
210     toBeAdded.reserve(maxSize);
211     std::set_difference(reportIds->begin(), reportIds->end(),
212                         newReportIds.begin(), newReportIds.end(),
213                         std::back_inserter(toBeRemoved));
214     std::set_difference(newReportIds.begin(), newReportIds.end(),
215                         reportIds->begin(), reportIds->end(),
216                         std::back_inserter(toBeAdded));
217     for (auto& reportId : toBeRemoved)
218     {
219         reportManager.updateTriggerIds(reportId, id, TriggerIdUpdate::Remove);
220     }
221     for (auto& reportId : toBeAdded)
222     {
223         reportManager.updateTriggerIds(reportId, id, TriggerIdUpdate::Add);
224     }
225 }
226