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