xref: /openbmc/telemetry/src/trigger.cpp (revision a4e6761643f2ff306d6928ea5537eb151fae79a0)
1 #include "trigger.hpp"
2 
3 #include "interfaces/types.hpp"
4 #include "utils/transform.hpp"
5 
6 #include <phosphor-logging/log.hpp>
7 
8 template <class... Ts>
9 struct overloaded : Ts...
10 {
11     using Ts::operator()...;
12 };
13 template <class... Ts>
14 overloaded(Ts...) -> overloaded<Ts...>;
15 
16 Trigger::Trigger(
17     boost::asio::io_context& ioc,
18     const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
19     const std::string& nameIn, const bool isDiscreteIn,
20     const bool logToJournalIn, const bool logToRedfishIn,
21     const bool updateReportIn, const TriggerSensors& sensorsIn,
22     const std::vector<std::string>& reportNamesIn,
23     const TriggerThresholdParams& thresholdParamsIn,
24     std::vector<std::shared_ptr<interfaces::Threshold>>&& thresholdsIn,
25     interfaces::TriggerManager& triggerManager,
26     interfaces::JsonStorage& triggerStorageIn) :
27     name(nameIn),
28     isDiscrete(isDiscreteIn), logToJournal(logToJournalIn),
29     logToRedfish(logToRedfishIn), updateReport(updateReportIn),
30     path(triggerDir + name), sensors(sensorsIn), reportNames(reportNamesIn),
31     thresholdParams(thresholdParamsIn), thresholds(std::move(thresholdsIn)),
32     fileName(std::to_string(std::hash<std::string>{}(name))),
33     triggerStorage(triggerStorageIn)
34 {
35     deleteIface = objServer->add_unique_interface(
36         path, deleteIfaceName, [this, &ioc, &triggerManager](auto& dbusIface) {
37             dbusIface.register_method("Delete", [this, &ioc, &triggerManager] {
38                 if (persistent)
39                 {
40                     triggerStorage.remove(fileName);
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,
50         [this, isDiscreteIn, logToJournalIn, logToRedfishIn,
51          updateReportIn](auto& dbusIface) {
52             persistent = storeConfiguration();
53             dbusIface.register_property_rw(
54                 "Persistent", persistent,
55                 sdbusplus::vtable::property_::emits_change,
56                 [this](bool newVal, const auto&) {
57                     if (newVal == persistent)
58                     {
59                         return true;
60                     }
61                     if (newVal)
62                     {
63                         persistent = storeConfiguration();
64                     }
65                     else
66                     {
67                         triggerStorage.remove(fileName);
68                         persistent = false;
69                     }
70                     return true;
71                 },
72                 [this](const auto&) { return persistent; });
73 
74             dbusIface.register_property_r(
75                 "Thresholds", thresholdParams,
76                 sdbusplus::vtable::property_::emits_change,
77                 [](const auto& x) { return x; });
78             dbusIface.register_property_r(
79                 "Sensors", sensors, sdbusplus::vtable::property_::emits_change,
80                 [](const auto& x) { return x; });
81             dbusIface.register_property_r(
82                 "ReportNames", reportNames,
83                 sdbusplus::vtable::property_::emits_change,
84                 [](const auto& x) { return x; });
85             dbusIface.register_property_r("Discrete", isDiscrete,
86                                           sdbusplus::vtable::property_::const_,
87                                           [](const auto& x) { return x; });
88             dbusIface.register_property_r("LogToJournal", logToJournal,
89                                           sdbusplus::vtable::property_::const_,
90                                           [](const auto& x) { return x; });
91             dbusIface.register_property_r("LogToRedfish", logToRedfish,
92                                           sdbusplus::vtable::property_::const_,
93                                           [](const auto& x) { return x; });
94             dbusIface.register_property_r("UpdateReport", updateReport,
95                                           sdbusplus::vtable::property_::const_,
96                                           [](const auto& x) { return x; });
97         });
98 
99     for (const auto& threshold : thresholds)
100     {
101         threshold->initialize();
102     }
103 }
104 
105 bool Trigger::storeConfiguration() const
106 {
107     try
108     {
109         nlohmann::json data;
110 
111         data["Version"] = triggerVersion;
112         data["Name"] = name;
113         data["ThresholdParamsDiscriminator"] = thresholdParams.index();
114         data["IsDiscrete"] = isDiscrete;
115         data["LogToJournal"] = logToJournal;
116         data["LogToRedfish"] = logToRedfish;
117         data["UpdateReport"] = updateReport;
118 
119         std::visit(
120             overloaded{
121                 [&](const std::vector<numeric::ThresholdParam>& arg) {
122                     data["ThresholdParams"] =
123                         utils::transform(arg, [](const auto& thresholdParam) {
124                             const auto& [type, dwellTime, direction,
125                                          thresholdValue] = thresholdParam;
126                             return numeric::LabeledThresholdParam(
127                                 numeric::stringToType(type), dwellTime,
128                                 numeric::stringToDirection(direction),
129                                 thresholdValue);
130                         });
131                 },
132                 [&](const std::vector<discrete::ThresholdParam>& arg) {
133                     data["ThresholdParams"] =
134                         utils::transform(arg, [](const auto& thresholdParam) {
135                             const auto& [userId, severity, dwellTime,
136                                          thresholdValue] = thresholdParam;
137                             return discrete::LabeledThresholdParam(
138                                 userId, discrete::stringToSeverity(severity),
139                                 dwellTime, thresholdValue);
140                         });
141                 },
142             },
143             thresholdParams);
144 
145         data["ReportNames"] = reportNames;
146 
147         data["Sensors"] = utils::transform(sensors, [](const auto& sensor) {
148             const auto& [sensorPath, sensorMetadata] = sensor;
149             return LabeledTriggerSensor(sensorPath, sensorMetadata);
150         });
151 
152         triggerStorage.store(fileName, data);
153     }
154     catch (const std::exception& e)
155     {
156         phosphor::logging::log<phosphor::logging::level::ERR>(
157             "Failed to store a trigger in storage",
158             phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
159         return false;
160     }
161     return true;
162 }