blob: 1e5d9647af82ded426813fc3292cb3f9d9a434b8 [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"
Szymon Dompke1cdd7e42022-06-08 14:43:13 +02006#include "utils/dbus_path_utils.hpp"
Szymon Dompke32305f12022-07-05 15:37:21 +02007#include "utils/make_id_name.hpp"
Cezary Zwolak4416fce2021-03-17 03:21:06 +01008#include "utils/transform.hpp"
Szymon Dompke32305f12022-07-05 15:37:21 +02009#include "utils/tstring.hpp"
Cezary Zwolak4416fce2021-03-17 03:21:06 +010010
11#include <phosphor-logging/log.hpp>
Alexander Hansen6d276f62026-01-14 01:58:28 +010012#include <xyz/openbmc_project/Telemetry/TriggerManager/common.hpp>
Cezary Zwolak4416fce2021-03-17 03:21:06 +010013
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +010014#include <unordered_set>
15
Alexander Hansen6d276f62026-01-14 01:58:28 +010016using TelemetryTriggerManager =
17 sdbusplus::common::xyz::openbmc_project::telemetry::TriggerManager;
18
Wludzik, Jozef76833cb2020-12-21 14:42:41 +010019TriggerManager::TriggerManager(
20 std::unique_ptr<interfaces::TriggerFactory> triggerFactoryIn,
Cezary Zwolaka4e67612021-02-18 13:16:16 +010021 std::unique_ptr<interfaces::JsonStorage> triggerStorageIn,
Wludzik, Jozef76833cb2020-12-21 14:42:41 +010022 const std::shared_ptr<sdbusplus::asio::object_server>& objServer) :
Cezary Zwolaka4e67612021-02-18 13:16:16 +010023 triggerFactory(std::move(triggerFactoryIn)),
24 triggerStorage(std::move(triggerStorageIn))
Wludzik, Jozef76833cb2020-12-21 14:42:41 +010025{
Cezary Zwolak4416fce2021-03-17 03:21:06 +010026 loadFromPersistent();
27
Patrick Williamsc7935fa2023-10-20 11:19:30 -050028 managerIface = objServer->add_unique_interface(
Alexander Hansen6d276f62026-01-14 01:58:28 +010029 triggerManagerPath, TelemetryTriggerManager::interface,
30 [this](auto& iface) {
Patrick Williams583ba442025-02-03 14:28:19 -050031 iface.register_method(
Alexander Hansen6d276f62026-01-14 01:58:28 +010032 TelemetryTriggerManager::method_names::add_trigger,
Patrick Williams583ba442025-02-03 14:28:19 -050033 [this](
34 boost::asio::yield_context& yield, const std::string& id,
35 const std::string& name,
36 const std::vector<std::string>& triggerActions,
37 const SensorsInfo& sensors,
38 const std::vector<sdbusplus::message::object_path>& reports,
39 const std::vector<numeric::ThresholdParam>&
40 numericThresholds,
41 const std::vector<discrete::ThresholdParam>&
42 discreteThresholds) {
43 LabeledTriggerThresholdParams labeledTriggerThresholdParams;
44 if (!numericThresholds.empty())
45 {
46 labeledTriggerThresholdParams =
47 utils::ToLabeledThresholdParamConversion()(
48 numericThresholds);
49 }
50 if (!discreteThresholds.empty())
51 {
52 labeledTriggerThresholdParams =
53 utils::ToLabeledThresholdParamConversion()(
54 discreteThresholds);
55 }
56 std::vector<LabeledSensorInfo> labeledSensorsInfo =
57 triggerFactory->getLabeledSensorsInfo(yield, sensors);
Wludzik, Jozef76833cb2020-12-21 14:42:41 +010058
Patrick Williams583ba442025-02-03 14:28:19 -050059 auto reportIds = utils::transform<std::vector>(
60 reports, [](const auto& item) {
61 return utils::reportPathToId(item);
62 });
Szymon Dompke1cdd7e42022-06-08 14:43:13 +020063
Patrick Williams583ba442025-02-03 14:28:19 -050064 return addTrigger(id, name, triggerActions,
65 labeledSensorsInfo, reportIds,
66 labeledTriggerThresholdParams)
67 .getPath();
68 });
Patrick Williamsc7935fa2023-10-20 11:19:30 -050069 });
Wludzik, Jozef76833cb2020-12-21 14:42:41 +010070}
71
72void TriggerManager::removeTrigger(const interfaces::Trigger* trigger)
73{
74 triggers.erase(
75 std::remove_if(triggers.begin(), triggers.end(),
76 [trigger](const auto& x) { return trigger == x.get(); }),
77 triggers.end());
78}
Cezary Zwolak4416fce2021-03-17 03:21:06 +010079
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +010080void TriggerManager::verifyReportIds(
81 const std::vector<std::string>& newReportIds)
82{
83 if (std::unordered_set(newReportIds.begin(), newReportIds.end()).size() !=
84 newReportIds.size())
85 {
86 throw sdbusplus::exception::SdBusError(
87 static_cast<int>(std::errc::invalid_argument),
88 "Duplicate element in ReportIds");
89 }
90}
91
Szymon Dompke32305f12022-07-05 15:37:21 +020092void TriggerManager::verifyThresholdParams(
93 const LabeledTriggerThresholdParams& thresholdParams)
94{
95 namespace ts = utils::tstring;
96
97 if (auto discreteParams =
98 std::get_if<std::vector<discrete::LabeledThresholdParam>>(
99 &thresholdParams);
100 discreteParams != nullptr)
101 {
102 for (auto discreteParam : *discreteParams)
103 {
104 if (discreteParam.at_label<ts::UserId>().length() >
105 utils::constants::maxIdNameLength)
106 {
Krzysztof Grobelny62c08e92022-09-16 10:28:53 +0200107 throw errors::InvalidArgument("ThresholdParams.Id",
108 "UserId too long.");
Szymon Dompke32305f12022-07-05 15:37:21 +0200109 }
110 }
111 }
112}
113
Szymon Dompkeb4ef22e2022-02-07 15:15:12 +0100114void TriggerManager::verifyAddTrigger(
Szymon Dompke32305f12022-07-05 15:37:21 +0200115 const std::vector<std::string>& reportIds,
116 const LabeledTriggerThresholdParams& thresholdParams) const
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100117{
118 if (triggers.size() >= maxTriggers)
119 {
120 throw sdbusplus::exception::SdBusError(
121 static_cast<int>(std::errc::too_many_files_open),
122 "Reached maximal trigger count");
123 }
124
Szymon Dompke32305f12022-07-05 15:37:21 +0200125 verifyReportIds(reportIds);
126 verifyThresholdParams(thresholdParams);
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100127}
128
129interfaces::Trigger& TriggerManager::addTrigger(
Szymon Dompkee28aa532021-10-27 12:33:12 +0200130 const std::string& triggerIdIn, const std::string& triggerNameIn,
Szymon Dompke20013012021-07-23 09:54:20 +0200131 const std::vector<std::string>& triggerActions,
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100132 const std::vector<LabeledSensorInfo>& labeledSensorsInfo,
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100133 const std::vector<std::string>& reportIds,
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100134 const LabeledTriggerThresholdParams& labeledThresholdParams)
135{
Krzysztof Grobelnya950e422021-12-31 13:49:00 +0100136 const auto existingTriggerIds = utils::transform(
137 triggers, [](const auto& trigger) { return trigger->getId(); });
Szymon Dompkee28aa532021-10-27 12:33:12 +0200138
Szymon Dompke32305f12022-07-05 15:37:21 +0200139 auto [id, name] = utils::makeIdName(triggerIdIn, triggerNameIn,
140 triggerNameDefault, existingTriggerIds);
Szymon Dompkee28aa532021-10-27 12:33:12 +0200141
Szymon Dompke32305f12022-07-05 15:37:21 +0200142 verifyAddTrigger(reportIds, labeledThresholdParams);
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100143
144 triggers.emplace_back(triggerFactory->make(
Krzysztof Grobelnya950e422021-12-31 13:49:00 +0100145 id, name, triggerActions, reportIds, *this, *triggerStorage,
146 labeledThresholdParams, labeledSensorsInfo));
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100147
148 return *triggers.back();
149}
150
151void TriggerManager::loadFromPersistent()
152{
153 std::vector<interfaces::JsonStorage::FilePath> paths =
154 triggerStorage->list();
155
156 for (const auto& path : paths)
157 {
158 std::optional<nlohmann::json> data = triggerStorage->load(path);
159 try
160 {
161 if (!data.has_value())
162 {
163 throw std::runtime_error("Empty storage");
164 }
165 size_t version = data->at("Version").get<size_t>();
166 if (version != Trigger::triggerVersion)
167 {
168 throw std::runtime_error("Invalid version");
169 }
Szymon Dompkee28aa532021-10-27 12:33:12 +0200170 const std::string& id = data->at("Id").get_ref<std::string&>();
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100171 const std::string& name = data->at("Name").get_ref<std::string&>();
172 int thresholdParamsDiscriminator =
173 data->at("ThresholdParamsDiscriminator").get<int>();
Szymon Dompke20013012021-07-23 09:54:20 +0200174 const std::vector<std::string> triggerActions =
175 data->at("TriggerActions").get<std::vector<std::string>>();
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100176
177 LabeledTriggerThresholdParams labeledThresholdParams;
178 if (0 == thresholdParamsDiscriminator)
179 {
180 labeledThresholdParams =
181 data->at("ThresholdParams")
182 .get<std::vector<numeric::LabeledThresholdParam>>();
183 }
184 else
185 {
186 labeledThresholdParams =
187 data->at("ThresholdParams")
188 .get<std::vector<discrete::LabeledThresholdParam>>();
189 }
190
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100191 auto reportIds =
192 data->at("ReportIds").get<std::vector<std::string>>();
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100193
194 auto labeledSensorsInfo =
195 data->at("Sensors").get<std::vector<LabeledSensorInfo>>();
196
Krzysztof Grobelnyb8cc78d2021-11-29 15:54:53 +0100197 addTrigger(id, name, triggerActions, labeledSensorsInfo, reportIds,
198 labeledThresholdParams);
Cezary Zwolak4416fce2021-03-17 03:21:06 +0100199 }
200 catch (const std::exception& e)
201 {
202 phosphor::logging::log<phosphor::logging::level::ERR>(
203 "Failed to load trigger from storage",
204 phosphor::logging::entry(
205 "FILENAME=%s",
206 static_cast<std::filesystem::path>(path).c_str()),
207 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
208 triggerStorage->remove(path);
209 }
210 }
211}