xref: /openbmc/telemetry/src/trigger_manager.cpp (revision 2001301a0f2ce71797cf171305a1d0eb0d288fe6)
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,
25                        const std::vector<std::string>& triggerActions,
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, triggerActions, labeledSensorsInfo,
38                                       reportNames,
39                                       labeledTriggerThresholdParams)
40                         .getPath();
41                 });
42         });
43 }
44 
45 void TriggerManager::removeTrigger(const interfaces::Trigger* trigger)
46 {
47     triggers.erase(
48         std::remove_if(triggers.begin(), triggers.end(),
49                        [trigger](const auto& x) { return trigger == x.get(); }),
50         triggers.end());
51 }
52 
53 void TriggerManager::verifyAddTrigger(const std::string& triggerName)
54 {
55     if (triggers.size() >= maxTriggers)
56     {
57         throw sdbusplus::exception::SdBusError(
58             static_cast<int>(std::errc::too_many_files_open),
59             "Reached maximal trigger count");
60     }
61 
62     for (const auto& trigger : triggers)
63     {
64         if (trigger->getName() == triggerName)
65         {
66             throw sdbusplus::exception::SdBusError(
67                 static_cast<int>(std::errc::file_exists), "Duplicate trigger");
68         }
69     }
70 }
71 
72 interfaces::Trigger& TriggerManager::addTrigger(
73     const std::string& triggerName,
74     const std::vector<std::string>& triggerActions,
75     const std::vector<LabeledSensorInfo>& labeledSensorsInfo,
76     const std::vector<std::string>& reportNames,
77     const LabeledTriggerThresholdParams& labeledThresholdParams)
78 {
79     verifyAddTrigger(triggerName);
80 
81     triggers.emplace_back(triggerFactory->make(
82         triggerName, triggerActions, reportNames, *this, *triggerStorage,
83         labeledThresholdParams, labeledSensorsInfo));
84 
85     return *triggers.back();
86 }
87 
88 void TriggerManager::loadFromPersistent()
89 {
90     std::vector<interfaces::JsonStorage::FilePath> paths =
91         triggerStorage->list();
92 
93     for (const auto& path : paths)
94     {
95         std::optional<nlohmann::json> data = triggerStorage->load(path);
96         try
97         {
98             if (!data.has_value())
99             {
100                 throw std::runtime_error("Empty storage");
101             }
102             size_t version = data->at("Version").get<size_t>();
103             if (version != Trigger::triggerVersion)
104             {
105                 throw std::runtime_error("Invalid version");
106             }
107             const std::string& name = data->at("Name").get_ref<std::string&>();
108             int thresholdParamsDiscriminator =
109                 data->at("ThresholdParamsDiscriminator").get<int>();
110             const std::vector<std::string> triggerActions =
111                 data->at("TriggerActions").get<std::vector<std::string>>();
112 
113             LabeledTriggerThresholdParams labeledThresholdParams;
114             if (0 == thresholdParamsDiscriminator)
115             {
116                 labeledThresholdParams =
117                     data->at("ThresholdParams")
118                         .get<std::vector<numeric::LabeledThresholdParam>>();
119             }
120             else
121             {
122                 labeledThresholdParams =
123                     data->at("ThresholdParams")
124                         .get<std::vector<discrete::LabeledThresholdParam>>();
125             }
126 
127             auto reportNames =
128                 data->at("ReportNames").get<std::vector<std::string>>();
129 
130             auto labeledSensorsInfo =
131                 data->at("Sensors").get<std::vector<LabeledSensorInfo>>();
132 
133             addTrigger(name, triggerActions, labeledSensorsInfo, reportNames,
134                        labeledThresholdParams);
135         }
136         catch (const std::exception& e)
137         {
138             phosphor::logging::log<phosphor::logging::level::ERR>(
139                 "Failed to load trigger from storage",
140                 phosphor::logging::entry(
141                     "FILENAME=%s",
142                     static_cast<std::filesystem::path>(path).c_str()),
143                 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
144             triggerStorage->remove(path);
145         }
146     }
147 }
148