xref: /openbmc/telemetry/src/trigger_manager.cpp (revision dcc4e1936173a93251a02066432bc2bcbc386240)
1 #include "trigger_manager.hpp"
2 
3 #include "trigger.hpp"
4 #include "types/trigger_types.hpp"
5 #include "utils/conversion_trigger.hpp"
6 #include "utils/transform.hpp"
7 
8 #include <phosphor-logging/log.hpp>
9 
10 TriggerManager::TriggerManager(
11     std::unique_ptr<interfaces::TriggerFactory> triggerFactoryIn,
12     std::unique_ptr<interfaces::JsonStorage> triggerStorageIn,
13     const std::shared_ptr<sdbusplus::asio::object_server>& objServer) :
14     triggerFactory(std::move(triggerFactoryIn)),
15     triggerStorage(std::move(triggerStorageIn))
16 {
17     loadFromPersistent();
18 
19     managerIface = objServer->add_unique_interface(
20         triggerManagerPath, triggerManagerIfaceName, [this](auto& iface) {
21             iface.register_method(
22                 "AddTrigger",
23                 [this](boost::asio::yield_context& yield,
24                        const std::string& name, bool isDiscrete,
25                        bool logToJournal, bool logToRedfish, bool updateReport,
26                        const SensorsInfo& sensors,
27                        const std::vector<std::string>& reportNames,
28                        const TriggerThresholdParamsExt& thresholds) {
29                     LabeledTriggerThresholdParams
30                         labeledTriggerThresholdParams = std::visit(
31                             utils::ToLabeledThresholdParamConversion(),
32                             thresholds);
33 
34                     std::vector<LabeledSensorInfo> labeledSensorsInfo =
35                         triggerFactory->getLabeledSensorsInfo(yield, sensors);
36 
37                     return addTrigger(name, isDiscrete, logToJournal,
38                                       logToRedfish, updateReport,
39                                       labeledSensorsInfo, reportNames,
40                                       labeledTriggerThresholdParams)
41                         .getPath();
42                 });
43         });
44 }
45 
46 void TriggerManager::removeTrigger(const interfaces::Trigger* trigger)
47 {
48     triggers.erase(
49         std::remove_if(triggers.begin(), triggers.end(),
50                        [trigger](const auto& x) { return trigger == x.get(); }),
51         triggers.end());
52 }
53 
54 void TriggerManager::verifyAddTrigger(
55     const std::string& triggerName, bool isDiscrete,
56     const LabeledTriggerThresholdParams& thresholdParams)
57 {
58     if (triggers.size() >= maxTriggers)
59     {
60         throw sdbusplus::exception::SdBusError(
61             static_cast<int>(std::errc::too_many_files_open),
62             "Reached maximal trigger count");
63     }
64 
65     for (const auto& trigger : triggers)
66     {
67         if (trigger->getName() == triggerName)
68         {
69             throw sdbusplus::exception::SdBusError(
70                 static_cast<int>(std::errc::file_exists), "Duplicate trigger");
71         }
72     }
73 }
74 
75 interfaces::Trigger& TriggerManager::addTrigger(
76     const std::string& triggerName, bool isDiscrete, bool logToJournal,
77     bool logToRedfish, bool updateReport,
78     const std::vector<LabeledSensorInfo>& labeledSensorsInfo,
79     const std::vector<std::string>& reportNames,
80     const LabeledTriggerThresholdParams& labeledThresholdParams)
81 {
82     verifyAddTrigger(triggerName, isDiscrete, labeledThresholdParams);
83 
84     triggers.emplace_back(triggerFactory->make(
85         triggerName, isDiscrete, logToJournal, logToRedfish, updateReport,
86         reportNames, *this, *triggerStorage, labeledThresholdParams,
87         labeledSensorsInfo));
88 
89     return *triggers.back();
90 }
91 
92 void TriggerManager::loadFromPersistent()
93 {
94     std::vector<interfaces::JsonStorage::FilePath> paths =
95         triggerStorage->list();
96 
97     for (const auto& path : paths)
98     {
99         std::optional<nlohmann::json> data = triggerStorage->load(path);
100         try
101         {
102             if (!data.has_value())
103             {
104                 throw std::runtime_error("Empty storage");
105             }
106             size_t version = data->at("Version").get<size_t>();
107             if (version != Trigger::triggerVersion)
108             {
109                 throw std::runtime_error("Invalid version");
110             }
111             const std::string& name = data->at("Name").get_ref<std::string&>();
112             int thresholdParamsDiscriminator =
113                 data->at("ThresholdParamsDiscriminator").get<int>();
114             bool isDiscrete = data->at("IsDiscrete").get<bool>();
115             bool logToJournal = data->at("LogToJournal").get<bool>();
116             bool logToRedfish = data->at("LogToRedfish").get<bool>();
117             bool updateReport = data->at("UpdateReport").get<bool>();
118 
119             LabeledTriggerThresholdParams labeledThresholdParams;
120             if (0 == thresholdParamsDiscriminator)
121             {
122                 labeledThresholdParams =
123                     data->at("ThresholdParams")
124                         .get<std::vector<numeric::LabeledThresholdParam>>();
125             }
126             else
127             {
128                 labeledThresholdParams =
129                     data->at("ThresholdParams")
130                         .get<std::vector<discrete::LabeledThresholdParam>>();
131             }
132 
133             auto reportNames =
134                 data->at("ReportNames").get<std::vector<std::string>>();
135 
136             auto labeledSensorsInfo =
137                 data->at("Sensors").get<std::vector<LabeledSensorInfo>>();
138 
139             addTrigger(name, isDiscrete, logToJournal, logToRedfish,
140                        updateReport, labeledSensorsInfo, reportNames,
141                        labeledThresholdParams);
142         }
143         catch (const std::exception& e)
144         {
145             phosphor::logging::log<phosphor::logging::level::ERR>(
146                 "Failed to load trigger from storage",
147                 phosphor::logging::entry(
148                     "FILENAME=%s",
149                     static_cast<std::filesystem::path>(path).c_str()),
150                 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
151             triggerStorage->remove(path);
152         }
153     }
154 }
155