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