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