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