xref: /openbmc/telemetry/src/trigger.cpp (revision b7b7e1b603fd9df56a72547c8048d182a001d647)
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/transform.hpp"
11 
12 #include <phosphor-logging/log.hpp>
13 
14 Trigger::Trigger(
15     boost::asio::io_context& ioc,
16     const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
17     TriggerId&& idIn, const std::string& nameIn,
18     const std::vector<TriggerAction>& triggerActionsIn,
19     const std::shared_ptr<std::vector<std::string>> reportIdsIn,
20     std::vector<std::shared_ptr<interfaces::Threshold>>&& thresholdsIn,
21     interfaces::TriggerManager& triggerManager,
22     interfaces::JsonStorage& triggerStorageIn,
23     const interfaces::TriggerFactory& triggerFactory, Sensors sensorsIn) :
24     id(std::move(idIn)),
25     name(nameIn), triggerActions(std::move(triggerActionsIn)),
26     path(triggerDir + *id), reportIds(std::move(reportIdsIn)),
27     thresholds(std::move(thresholdsIn)),
28     fileName(std::to_string(std::hash<std::string>{}(*id))),
29     triggerStorage(triggerStorageIn), sensors(std::move(sensorsIn)),
30     messanger(ioc)
31 {
32     deleteIface = objServer->add_unique_interface(
33         path, deleteIfaceName, [this, &ioc, &triggerManager](auto& dbusIface) {
34             dbusIface.register_method("Delete", [this, &ioc, &triggerManager] {
35                 if (persistent)
36                 {
37                     triggerStorage.remove(fileName);
38                 }
39                 messanger.send(messages::TriggerPresenceChangedInd{
40                     messages::Presence::Removed, *id, {}});
41                 boost::asio::post(ioc, [this, &triggerManager] {
42                     triggerManager.removeTrigger(this);
43                 });
44             });
45         });
46 
47     triggerIface = objServer->add_unique_interface(
48         path, triggerIfaceName, [this, &triggerFactory](auto& dbusIface) {
49             persistent = storeConfiguration();
50             dbusIface.register_property_rw(
51                 "Persistent", persistent,
52                 sdbusplus::vtable::property_::emits_change,
53                 [this](bool newVal, const auto&) {
54                     if (newVal == persistent)
55                     {
56                         return 1;
57                     }
58                     if (newVal)
59                     {
60                         persistent = storeConfiguration();
61                     }
62                     else
63                     {
64                         triggerStorage.remove(fileName);
65                         persistent = false;
66                     }
67                     return 1;
68                 },
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 = std::visit(
76                         utils::ToLabeledThresholdParamConversion(), newVal);
77                     triggerFactory.updateThresholds(
78                         thresholds, *id, triggerActions, reportIds, sensors,
79                         newThresholdParams);
80                     oldVal = std::move(newVal);
81                     return 1;
82                 },
83                 [this](const auto&) {
84                     return fromLabeledThresholdParam(getLabeledThresholds());
85                 });
86 
87             dbusIface.register_property_rw(
88                 "Sensors", SensorsInfo{},
89                 sdbusplus::vtable::property_::emits_change,
90                 [this, &triggerFactory](auto newVal, auto& oldVal) {
91                     auto labeledSensorInfo =
92                         triggerFactory.getLabeledSensorsInfo(newVal);
93                     triggerFactory.updateSensors(sensors, labeledSensorInfo);
94                     for (const auto& threshold : thresholds)
95                     {
96                         threshold->updateSensors(sensors);
97                     }
98                     oldVal = std::move(newVal);
99                     return 1;
100                 },
101                 [this](const auto&) {
102                     return utils::fromLabeledSensorsInfo(
103                         getLabeledSensorInfo());
104                 });
105 
106             dbusIface.register_property_rw(
107                 "ReportNames", *reportIds,
108                 sdbusplus::vtable::property_::emits_change,
109                 [this](auto newVal, auto& oldVal) {
110                     TriggerManager::verifyReportIds(newVal);
111                     *reportIds = newVal;
112                     messanger.send(messages::TriggerPresenceChangedInd{
113                         messages::Presence::Exist, *id, *reportIds});
114                     oldVal = std::move(newVal);
115                     return 1;
116                 },
117                 [this](const auto&) { return *reportIds; });
118 
119             dbusIface.register_property_r(
120                 "Discrete", isDiscreate(), sdbusplus::vtable::property_::const_,
121                 [this](const auto& x) { return isDiscreate(); });
122 
123             dbusIface.register_property_rw(
124                 "Name", name, sdbusplus::vtable::property_::emits_change,
125                 [this](auto newVal, auto& oldVal) {
126                     name = oldVal = newVal;
127                     return 1;
128                 },
129                 [this](const auto&) { return name; });
130 
131             dbusIface.register_property_r(
132                 "TriggerActions", std::vector<std::string>(),
133                 sdbusplus::vtable::property_::const_, [this](const auto&) {
134                     return utils::transform(triggerActions,
135                                             [](const auto& action) {
136                                                 return actionToString(action);
137                                             });
138                 });
139         });
140 
141     for (const auto& threshold : thresholds)
142     {
143         threshold->initialize();
144     }
145 
146     messanger.on_receive<messages::CollectTriggerIdReq>(
147         [this](const auto& msg) {
148             if (utils::contains(*reportIds, msg.reportId))
149             {
150                 messanger.send(messages::CollectTriggerIdResp{*id});
151             }
152         });
153 
154     messanger.send(messages::TriggerPresenceChangedInd{
155         messages::Presence::Exist, *id, *reportIds});
156 }
157 
158 bool Trigger::storeConfiguration() const
159 {
160     try
161     {
162         nlohmann::json data;
163 
164         auto labeledThresholdParams =
165             std::visit(utils::ToLabeledThresholdParamConversion(),
166                        fromLabeledThresholdParam(getLabeledThresholds()));
167 
168         data["Version"] = triggerVersion;
169         data["Id"] = *id;
170         data["Name"] = name;
171         data["ThresholdParamsDiscriminator"] = labeledThresholdParams.index();
172         data["TriggerActions"] =
173             utils::transform(triggerActions, [](const auto& action) {
174                 return actionToString(action);
175             });
176         data["ThresholdParams"] =
177             utils::labeledThresholdParamsToJson(labeledThresholdParams);
178         data["ReportIds"] = *reportIds;
179         data["Sensors"] = getLabeledSensorInfo();
180 
181         triggerStorage.store(fileName, data);
182     }
183     catch (const std::exception& e)
184     {
185         phosphor::logging::log<phosphor::logging::level::ERR>(
186             "Failed to store a trigger in storage",
187             phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
188         return false;
189     }
190     return true;
191 }
192 
193 std::vector<LabeledSensorInfo> Trigger::getLabeledSensorInfo() const
194 {
195     return utils::transform(sensors, [](const auto& sensor) {
196         return sensor->getLabeledSensorInfo();
197     });
198 }
199 
200 std::vector<LabeledThresholdParam> Trigger::getLabeledThresholds() const
201 {
202     return utils::transform(thresholds, [](const auto& threshold) {
203         return threshold->getThresholdParam();
204     });
205 }
206 
207 bool Trigger::isDiscreate() const
208 {
209     const auto labeledThresholds = getLabeledThresholds();
210 
211     return utils::isFirstElementOfType<std::monostate>(labeledThresholds) ||
212            utils::isFirstElementOfType<discrete::LabeledThresholdParam>(
213                labeledThresholds);
214 }
215