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