xref: /openbmc/telemetry/src/trigger_manager.cpp (revision b4ef22e4)
176833cb5SWludzik, Jozef #include "trigger_manager.hpp"
276833cb5SWludzik, Jozef 
34416fce6SCezary Zwolak #include "trigger.hpp"
4dcc4e193SKrzysztof Grobelny #include "types/trigger_types.hpp"
54416fce6SCezary Zwolak #include "utils/conversion_trigger.hpp"
6b8cc78ddSKrzysztof Grobelny #include "utils/generate_id.hpp"
74416fce6SCezary Zwolak #include "utils/transform.hpp"
84416fce6SCezary Zwolak 
94416fce6SCezary Zwolak #include <phosphor-logging/log.hpp>
104416fce6SCezary Zwolak 
11*b4ef22e4SSzymon Dompke #include <unordered_set>
12*b4ef22e4SSzymon Dompke 
1376833cb5SWludzik, Jozef TriggerManager::TriggerManager(
1476833cb5SWludzik, Jozef     std::unique_ptr<interfaces::TriggerFactory> triggerFactoryIn,
15a4e67616SCezary Zwolak     std::unique_ptr<interfaces::JsonStorage> triggerStorageIn,
1676833cb5SWludzik, Jozef     const std::shared_ptr<sdbusplus::asio::object_server>& objServer) :
17a4e67616SCezary Zwolak     triggerFactory(std::move(triggerFactoryIn)),
18a4e67616SCezary Zwolak     triggerStorage(std::move(triggerStorageIn))
1976833cb5SWludzik, Jozef {
204416fce6SCezary Zwolak     loadFromPersistent();
214416fce6SCezary Zwolak 
2276833cb5SWludzik, Jozef     managerIface = objServer->add_unique_interface(
2376833cb5SWludzik, Jozef         triggerManagerPath, triggerManagerIfaceName, [this](auto& iface) {
2476833cb5SWludzik, Jozef             iface.register_method(
2576833cb5SWludzik, Jozef                 "AddTrigger",
26e28aa53dSSzymon Dompke                 [this](boost::asio::yield_context& yield, const std::string& id,
272001301aSSzymon Dompke                        const std::string& name,
282001301aSSzymon Dompke                        const std::vector<std::string>& triggerActions,
294416fce6SCezary Zwolak                        const SensorsInfo& sensors,
30b8cc78ddSKrzysztof Grobelny                        const std::vector<std::string>& reportIds,
314416fce6SCezary Zwolak                        const TriggerThresholdParamsExt& thresholds) {
324416fce6SCezary Zwolak                     LabeledTriggerThresholdParams
334416fce6SCezary Zwolak                         labeledTriggerThresholdParams = std::visit(
344416fce6SCezary Zwolak                             utils::ToLabeledThresholdParamConversion(),
354416fce6SCezary Zwolak                             thresholds);
3676833cb5SWludzik, Jozef 
374416fce6SCezary Zwolak                     std::vector<LabeledSensorInfo> labeledSensorsInfo =
384416fce6SCezary Zwolak                         triggerFactory->getLabeledSensorsInfo(yield, sensors);
3976833cb5SWludzik, Jozef 
40e28aa53dSSzymon Dompke                     return addTrigger(id, name, triggerActions,
41b8cc78ddSKrzysztof Grobelny                                       labeledSensorsInfo, reportIds,
424416fce6SCezary Zwolak                                       labeledTriggerThresholdParams)
434416fce6SCezary Zwolak                         .getPath();
4476833cb5SWludzik, Jozef                 });
4576833cb5SWludzik, Jozef         });
4676833cb5SWludzik, Jozef }
4776833cb5SWludzik, Jozef 
4876833cb5SWludzik, Jozef void TriggerManager::removeTrigger(const interfaces::Trigger* trigger)
4976833cb5SWludzik, Jozef {
5076833cb5SWludzik, Jozef     triggers.erase(
5176833cb5SWludzik, Jozef         std::remove_if(triggers.begin(), triggers.end(),
5276833cb5SWludzik, Jozef                        [trigger](const auto& x) { return trigger == x.get(); }),
5376833cb5SWludzik, Jozef         triggers.end());
5476833cb5SWludzik, Jozef }
554416fce6SCezary Zwolak 
56*b4ef22e4SSzymon Dompke void TriggerManager::verifyReportIds(
57*b4ef22e4SSzymon Dompke     const std::vector<std::string>& newReportIds)
58*b4ef22e4SSzymon Dompke {
59*b4ef22e4SSzymon Dompke     if (std::unordered_set(newReportIds.begin(), newReportIds.end()).size() !=
60*b4ef22e4SSzymon Dompke         newReportIds.size())
61*b4ef22e4SSzymon Dompke     {
62*b4ef22e4SSzymon Dompke         throw sdbusplus::exception::SdBusError(
63*b4ef22e4SSzymon Dompke             static_cast<int>(std::errc::invalid_argument),
64*b4ef22e4SSzymon Dompke             "Duplicate element in ReportIds");
65*b4ef22e4SSzymon Dompke     }
66*b4ef22e4SSzymon Dompke }
67*b4ef22e4SSzymon Dompke 
68*b4ef22e4SSzymon Dompke void TriggerManager::verifyAddTrigger(
69*b4ef22e4SSzymon Dompke     const std::string& triggerId, const std::string& triggerName,
70*b4ef22e4SSzymon Dompke     const std::vector<std::string>& newReportIds) const
714416fce6SCezary Zwolak {
724416fce6SCezary Zwolak     if (triggers.size() >= maxTriggers)
734416fce6SCezary Zwolak     {
744416fce6SCezary Zwolak         throw sdbusplus::exception::SdBusError(
754416fce6SCezary Zwolak             static_cast<int>(std::errc::too_many_files_open),
764416fce6SCezary Zwolak             "Reached maximal trigger count");
774416fce6SCezary Zwolak     }
784416fce6SCezary Zwolak 
79b8cc78ddSKrzysztof Grobelny     utils::verifyIdCharacters(triggerId);
80e28aa53dSSzymon Dompke 
814416fce6SCezary Zwolak     for (const auto& trigger : triggers)
824416fce6SCezary Zwolak     {
83e28aa53dSSzymon Dompke         if (trigger->getId() == triggerId)
844416fce6SCezary Zwolak         {
854416fce6SCezary Zwolak             throw sdbusplus::exception::SdBusError(
864416fce6SCezary Zwolak                 static_cast<int>(std::errc::file_exists), "Duplicate trigger");
874416fce6SCezary Zwolak         }
884416fce6SCezary Zwolak     }
89*b4ef22e4SSzymon Dompke 
90*b4ef22e4SSzymon Dompke     verifyReportIds(newReportIds);
914416fce6SCezary Zwolak }
924416fce6SCezary Zwolak 
934416fce6SCezary Zwolak interfaces::Trigger& TriggerManager::addTrigger(
94e28aa53dSSzymon Dompke     const std::string& triggerIdIn, const std::string& triggerNameIn,
952001301aSSzymon Dompke     const std::vector<std::string>& triggerActions,
964416fce6SCezary Zwolak     const std::vector<LabeledSensorInfo>& labeledSensorsInfo,
97b8cc78ddSKrzysztof Grobelny     const std::vector<std::string>& reportIds,
984416fce6SCezary Zwolak     const LabeledTriggerThresholdParams& labeledThresholdParams)
994416fce6SCezary Zwolak {
100a950e42bSKrzysztof Grobelny     const auto existingTriggerIds = utils::transform(
101a950e42bSKrzysztof Grobelny         triggers, [](const auto& trigger) { return trigger->getId(); });
102e28aa53dSSzymon Dompke 
103a950e42bSKrzysztof Grobelny     auto [id, name] =
104a950e42bSKrzysztof Grobelny         utils::generateId(triggerIdIn, triggerNameIn, triggerNameDefault,
105a950e42bSKrzysztof Grobelny                           existingTriggerIds, maxTriggerIdLength);
106e28aa53dSSzymon Dompke 
107*b4ef22e4SSzymon Dompke     verifyAddTrigger(id, name, reportIds);
1084416fce6SCezary Zwolak 
1094416fce6SCezary Zwolak     triggers.emplace_back(triggerFactory->make(
110a950e42bSKrzysztof Grobelny         id, name, triggerActions, reportIds, *this, *triggerStorage,
111a950e42bSKrzysztof Grobelny         labeledThresholdParams, labeledSensorsInfo));
1124416fce6SCezary Zwolak 
1134416fce6SCezary Zwolak     return *triggers.back();
1144416fce6SCezary Zwolak }
1154416fce6SCezary Zwolak 
1164416fce6SCezary Zwolak void TriggerManager::loadFromPersistent()
1174416fce6SCezary Zwolak {
1184416fce6SCezary Zwolak     std::vector<interfaces::JsonStorage::FilePath> paths =
1194416fce6SCezary Zwolak         triggerStorage->list();
1204416fce6SCezary Zwolak 
1214416fce6SCezary Zwolak     for (const auto& path : paths)
1224416fce6SCezary Zwolak     {
1234416fce6SCezary Zwolak         std::optional<nlohmann::json> data = triggerStorage->load(path);
1244416fce6SCezary Zwolak         try
1254416fce6SCezary Zwolak         {
1264416fce6SCezary Zwolak             if (!data.has_value())
1274416fce6SCezary Zwolak             {
1284416fce6SCezary Zwolak                 throw std::runtime_error("Empty storage");
1294416fce6SCezary Zwolak             }
1304416fce6SCezary Zwolak             size_t version = data->at("Version").get<size_t>();
1314416fce6SCezary Zwolak             if (version != Trigger::triggerVersion)
1324416fce6SCezary Zwolak             {
1334416fce6SCezary Zwolak                 throw std::runtime_error("Invalid version");
1344416fce6SCezary Zwolak             }
135e28aa53dSSzymon Dompke             const std::string& id = data->at("Id").get_ref<std::string&>();
1364416fce6SCezary Zwolak             const std::string& name = data->at("Name").get_ref<std::string&>();
1374416fce6SCezary Zwolak             int thresholdParamsDiscriminator =
1384416fce6SCezary Zwolak                 data->at("ThresholdParamsDiscriminator").get<int>();
1392001301aSSzymon Dompke             const std::vector<std::string> triggerActions =
1402001301aSSzymon Dompke                 data->at("TriggerActions").get<std::vector<std::string>>();
1414416fce6SCezary Zwolak 
1424416fce6SCezary Zwolak             LabeledTriggerThresholdParams labeledThresholdParams;
1434416fce6SCezary Zwolak             if (0 == thresholdParamsDiscriminator)
1444416fce6SCezary Zwolak             {
1454416fce6SCezary Zwolak                 labeledThresholdParams =
1464416fce6SCezary Zwolak                     data->at("ThresholdParams")
1474416fce6SCezary Zwolak                         .get<std::vector<numeric::LabeledThresholdParam>>();
1484416fce6SCezary Zwolak             }
1494416fce6SCezary Zwolak             else
1504416fce6SCezary Zwolak             {
1514416fce6SCezary Zwolak                 labeledThresholdParams =
1524416fce6SCezary Zwolak                     data->at("ThresholdParams")
1534416fce6SCezary Zwolak                         .get<std::vector<discrete::LabeledThresholdParam>>();
1544416fce6SCezary Zwolak             }
1554416fce6SCezary Zwolak 
156b8cc78ddSKrzysztof Grobelny             auto reportIds =
157b8cc78ddSKrzysztof Grobelny                 data->at("ReportIds").get<std::vector<std::string>>();
1584416fce6SCezary Zwolak 
1594416fce6SCezary Zwolak             auto labeledSensorsInfo =
1604416fce6SCezary Zwolak                 data->at("Sensors").get<std::vector<LabeledSensorInfo>>();
1614416fce6SCezary Zwolak 
162b8cc78ddSKrzysztof Grobelny             addTrigger(id, name, triggerActions, labeledSensorsInfo, reportIds,
163b8cc78ddSKrzysztof Grobelny                        labeledThresholdParams);
1644416fce6SCezary Zwolak         }
1654416fce6SCezary Zwolak         catch (const std::exception& e)
1664416fce6SCezary Zwolak         {
1674416fce6SCezary Zwolak             phosphor::logging::log<phosphor::logging::level::ERR>(
1684416fce6SCezary Zwolak                 "Failed to load trigger from storage",
1694416fce6SCezary Zwolak                 phosphor::logging::entry(
1704416fce6SCezary Zwolak                     "FILENAME=%s",
1714416fce6SCezary Zwolak                     static_cast<std::filesystem::path>(path).c_str()),
1724416fce6SCezary Zwolak                 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
1734416fce6SCezary Zwolak             triggerStorage->remove(path);
1744416fce6SCezary Zwolak         }
1754416fce6SCezary Zwolak     }
1764416fce6SCezary Zwolak }
177*b4ef22e4SSzymon Dompke 
178*b4ef22e4SSzymon Dompke std::vector<std::string>
179*b4ef22e4SSzymon Dompke     TriggerManager::getTriggerIdsForReport(const std::string& reportId) const
180*b4ef22e4SSzymon Dompke {
181*b4ef22e4SSzymon Dompke     std::vector<std::string> result;
182*b4ef22e4SSzymon Dompke     for (const auto& trigger : triggers)
183*b4ef22e4SSzymon Dompke     {
184*b4ef22e4SSzymon Dompke         const auto& reportIds = trigger->getReportIds();
185*b4ef22e4SSzymon Dompke         if (std::find(reportIds.begin(), reportIds.end(), reportId) !=
186*b4ef22e4SSzymon Dompke             reportIds.end())
187*b4ef22e4SSzymon Dompke         {
188*b4ef22e4SSzymon Dompke             result.emplace_back(trigger->getId());
189*b4ef22e4SSzymon Dompke         }
190*b4ef22e4SSzymon Dompke     }
191*b4ef22e4SSzymon Dompke     return result;
192*b4ef22e4SSzymon Dompke }
193