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