blob: ac0fba54e7b5bb6d084f0ed4fa91099b8688f21e [file] [log] [blame]
Wludzik, Jozef76833cb2020-12-21 14:42:41 +01001#include "trigger_manager.hpp"
2
Cezary Zwolak4416fce2021-03-17 03:21:06 +01003#include "trigger.hpp"
Krzysztof Grobelnydcc4e192021-03-08 09:09:34 +00004#include "types/trigger_types.hpp"
Cezary Zwolak4416fce2021-03-17 03:21:06 +01005#include "utils/conversion_trigger.hpp"
6#include "utils/transform.hpp"
7
8#include <phosphor-logging/log.hpp>
9
Wludzik, Jozef76833cb2020-12-21 14:42:41 +010010TriggerManager::TriggerManager(
11 std::unique_ptr<interfaces::TriggerFactory> triggerFactoryIn,
Cezary Zwolaka4e67612021-02-18 13:16:16 +010012 std::unique_ptr<interfaces::JsonStorage> triggerStorageIn,
Wludzik, Jozef76833cb2020-12-21 14:42:41 +010013 const std::shared_ptr<sdbusplus::asio::object_server>& objServer) :
Cezary Zwolaka4e67612021-02-18 13:16:16 +010014 triggerFactory(std::move(triggerFactoryIn)),
15 triggerStorage(std::move(triggerStorageIn))
Wludzik, Jozef76833cb2020-12-21 14:42:41 +010016{
Cezary Zwolak4416fce2021-03-17 03:21:06 +010017 loadFromPersistent();
18
Wludzik, Jozef76833cb2020-12-21 14:42:41 +010019 managerIface = objServer->add_unique_interface(
20 triggerManagerPath, triggerManagerIfaceName, [this](auto& iface) {
21 iface.register_method(
22 "AddTrigger",
Szymon Dompkee28aa532021-10-27 12:33:12 +020023 [this](boost::asio::yield_context& yield, const std::string& id,
Szymon Dompke20013012021-07-23 09:54:20 +020024 const std::string& name,
25 const std::vector<std::string>& triggerActions,
Cezary Zwolak4416fce2021-03-17 03:21:06 +010026 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);
Wludzik, Jozef76833cb2020-12-21 14:42:41 +010033
Cezary Zwolak4416fce2021-03-17 03:21:06 +010034 std::vector<LabeledSensorInfo> labeledSensorsInfo =
35 triggerFactory->getLabeledSensorsInfo(yield, sensors);
Wludzik, Jozef76833cb2020-12-21 14:42:41 +010036
Szymon Dompkee28aa532021-10-27 12:33:12 +020037 return addTrigger(id, name, triggerActions,
38 labeledSensorsInfo, reportNames,
Cezary Zwolak4416fce2021-03-17 03:21:06 +010039 labeledTriggerThresholdParams)
40 .getPath();
Wludzik, Jozef76833cb2020-12-21 14:42:41 +010041 });
42 });
43}
44
45void 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}
Cezary Zwolak4416fce2021-03-17 03:21:06 +010052
Szymon Dompkee28aa532021-10-27 12:33:12 +020053void TriggerManager::verifyAddTrigger(const std::string& triggerId,
54 const std::string& triggerName) const
Cezary Zwolak4416fce2021-03-17 03:21:06 +010055{
56 if (triggers.size() >= maxTriggers)
57 {
58 throw sdbusplus::exception::SdBusError(
59 static_cast<int>(std::errc::too_many_files_open),
60 "Reached maximal trigger count");
61 }
62
Szymon Dompkee28aa532021-10-27 12:33:12 +020063 verifyTriggerIdLength(triggerId);
64 verifyIdCharacters(triggerId);
65
Cezary Zwolak4416fce2021-03-17 03:21:06 +010066 for (const auto& trigger : triggers)
67 {
Szymon Dompkee28aa532021-10-27 12:33:12 +020068 if (trigger->getId() == triggerId)
Cezary Zwolak4416fce2021-03-17 03:21:06 +010069 {
70 throw sdbusplus::exception::SdBusError(
71 static_cast<int>(std::errc::file_exists), "Duplicate trigger");
72 }
73 }
74}
75
Szymon Dompkee28aa532021-10-27 12:33:12 +020076void TriggerManager::verifyTriggerIdLength(const std::string& triggerId)
77{
78 if (triggerId.length() > maxTriggerIdLength)
79 {
80 throw sdbusplus::exception::SdBusError(
81 static_cast<int>(std::errc::invalid_argument),
82 "Trigger id exceeds maximum length");
83 }
84}
85
86void TriggerManager::verifyIdCharacters(const std::string& triggerId)
87{
88 if (triggerId.find_first_not_of(allowedCharactersInId) != std::string::npos)
89 {
90 throw sdbusplus::exception::SdBusError(
91 static_cast<int>(std::errc::invalid_argument),
92 "Invalid character in trigger id");
93 }
94}
95
96std::string TriggerManager::generateId(const std::string& prefix,
97 const std::string& triggerName) const
98{
99 verifyIdCharacters(prefix);
100 std::string strippedId(triggerName);
101 strippedId.erase(std::remove_if(strippedId.begin(), strippedId.end(),
102 [](char c) {
103 return c == '/' ||
104 allowedCharactersInId.find(c) ==
105 std::string_view::npos;
106 }),
107 strippedId.end());
108
109 strippedId = prefix + strippedId;
110 strippedId = strippedId.substr(
111 0, maxTriggerIdLength - std::to_string(maxTriggers - 1).length());
112
113 size_t idx = 0;
114 std::string tmpId(strippedId);
115 while (std::find_if(triggers.begin(), triggers.end(),
116 [&tmpId](const auto& trigger) {
117 return trigger->getId() == tmpId;
118 }) != triggers.end())
119 {
120 tmpId = strippedId + std::to_string(idx++);
121 }
122 return tmpId;
123}
124
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100125interfaces::Trigger& TriggerManager::addTrigger(
Szymon Dompkee28aa532021-10-27 12:33:12 +0200126 const std::string& triggerIdIn, const std::string& triggerNameIn,
Szymon Dompke20013012021-07-23 09:54:20 +0200127 const std::vector<std::string>& triggerActions,
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100128 const std::vector<LabeledSensorInfo>& labeledSensorsInfo,
129 const std::vector<std::string>& reportNames,
130 const LabeledTriggerThresholdParams& labeledThresholdParams)
131{
Szymon Dompkee28aa532021-10-27 12:33:12 +0200132 std::string triggerName = triggerNameIn;
133 if (triggerName.empty())
134 {
135 triggerName = triggerNameDefault;
136 }
137
138 std::string triggerId = triggerIdIn;
139 if (triggerId.empty() || triggerId.ends_with('/'))
140 {
141 triggerId = generateId(triggerId, triggerName);
142 }
143
144 verifyAddTrigger(triggerId, triggerName);
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100145
146 triggers.emplace_back(triggerFactory->make(
Szymon Dompkee28aa532021-10-27 12:33:12 +0200147 triggerId, triggerName, triggerActions, reportNames, *this,
148 *triggerStorage, labeledThresholdParams, labeledSensorsInfo));
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100149
150 return *triggers.back();
151}
152
153void TriggerManager::loadFromPersistent()
154{
155 std::vector<interfaces::JsonStorage::FilePath> paths =
156 triggerStorage->list();
157
158 for (const auto& path : paths)
159 {
160 std::optional<nlohmann::json> data = triggerStorage->load(path);
161 try
162 {
163 if (!data.has_value())
164 {
165 throw std::runtime_error("Empty storage");
166 }
167 size_t version = data->at("Version").get<size_t>();
168 if (version != Trigger::triggerVersion)
169 {
170 throw std::runtime_error("Invalid version");
171 }
Szymon Dompkee28aa532021-10-27 12:33:12 +0200172 const std::string& id = data->at("Id").get_ref<std::string&>();
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100173 const std::string& name = data->at("Name").get_ref<std::string&>();
174 int thresholdParamsDiscriminator =
175 data->at("ThresholdParamsDiscriminator").get<int>();
Szymon Dompke20013012021-07-23 09:54:20 +0200176 const std::vector<std::string> triggerActions =
177 data->at("TriggerActions").get<std::vector<std::string>>();
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100178
179 LabeledTriggerThresholdParams labeledThresholdParams;
180 if (0 == thresholdParamsDiscriminator)
181 {
182 labeledThresholdParams =
183 data->at("ThresholdParams")
184 .get<std::vector<numeric::LabeledThresholdParam>>();
185 }
186 else
187 {
188 labeledThresholdParams =
189 data->at("ThresholdParams")
190 .get<std::vector<discrete::LabeledThresholdParam>>();
191 }
192
193 auto reportNames =
194 data->at("ReportNames").get<std::vector<std::string>>();
195
196 auto labeledSensorsInfo =
197 data->at("Sensors").get<std::vector<LabeledSensorInfo>>();
198
Szymon Dompkee28aa532021-10-27 12:33:12 +0200199 addTrigger(id, name, triggerActions, labeledSensorsInfo,
200 reportNames, labeledThresholdParams);
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100201 }
202 catch (const std::exception& e)
203 {
204 phosphor::logging::log<phosphor::logging::level::ERR>(
205 "Failed to load trigger from storage",
206 phosphor::logging::entry(
207 "FILENAME=%s",
208 static_cast<std::filesystem::path>(path).c_str()),
209 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
210 triggerStorage->remove(path);
211 }
212 }
213}