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/generate_id.hpp" 7 #include "utils/transform.hpp" 8 9 #include <phosphor-logging/log.hpp> 10 11 #include <unordered_set> 12 13 TriggerManager::TriggerManager( 14 std::unique_ptr<interfaces::TriggerFactory> triggerFactoryIn, 15 std::unique_ptr<interfaces::JsonStorage> triggerStorageIn, 16 const std::shared_ptr<sdbusplus::asio::object_server>& objServer) : 17 triggerFactory(std::move(triggerFactoryIn)), 18 triggerStorage(std::move(triggerStorageIn)) 19 { 20 loadFromPersistent(); 21 22 managerIface = objServer->add_unique_interface( 23 triggerManagerPath, triggerManagerIfaceName, [this](auto& iface) { 24 iface.register_method( 25 "AddTrigger", 26 [this](boost::asio::yield_context& yield, const std::string& id, 27 const std::string& name, 28 const std::vector<std::string>& triggerActions, 29 const SensorsInfo& sensors, 30 const std::vector<std::string>& reportIds, 31 const TriggerThresholdParamsExt& thresholds) { 32 LabeledTriggerThresholdParams 33 labeledTriggerThresholdParams = std::visit( 34 utils::ToLabeledThresholdParamConversion(), 35 thresholds); 36 37 std::vector<LabeledSensorInfo> labeledSensorsInfo = 38 triggerFactory->getLabeledSensorsInfo(yield, sensors); 39 40 return addTrigger(id, name, triggerActions, 41 labeledSensorsInfo, reportIds, 42 labeledTriggerThresholdParams) 43 .getPath(); 44 }); 45 }); 46 } 47 48 void TriggerManager::removeTrigger(const interfaces::Trigger* trigger) 49 { 50 triggers.erase( 51 std::remove_if(triggers.begin(), triggers.end(), 52 [trigger](const auto& x) { return trigger == x.get(); }), 53 triggers.end()); 54 } 55 56 void TriggerManager::verifyReportIds( 57 const std::vector<std::string>& newReportIds) 58 { 59 if (std::unordered_set(newReportIds.begin(), newReportIds.end()).size() != 60 newReportIds.size()) 61 { 62 throw sdbusplus::exception::SdBusError( 63 static_cast<int>(std::errc::invalid_argument), 64 "Duplicate element in ReportIds"); 65 } 66 } 67 68 void TriggerManager::verifyAddTrigger( 69 const std::string& triggerId, const std::string& triggerName, 70 const std::vector<std::string>& newReportIds) const 71 { 72 if (triggers.size() >= maxTriggers) 73 { 74 throw sdbusplus::exception::SdBusError( 75 static_cast<int>(std::errc::too_many_files_open), 76 "Reached maximal trigger count"); 77 } 78 79 utils::verifyIdCharacters(triggerId); 80 81 for (const auto& trigger : triggers) 82 { 83 if (trigger->getId() == triggerId) 84 { 85 throw sdbusplus::exception::SdBusError( 86 static_cast<int>(std::errc::file_exists), "Duplicate trigger"); 87 } 88 } 89 90 verifyReportIds(newReportIds); 91 } 92 93 interfaces::Trigger& TriggerManager::addTrigger( 94 const std::string& triggerIdIn, const std::string& triggerNameIn, 95 const std::vector<std::string>& triggerActions, 96 const std::vector<LabeledSensorInfo>& labeledSensorsInfo, 97 const std::vector<std::string>& reportIds, 98 const LabeledTriggerThresholdParams& labeledThresholdParams) 99 { 100 const auto existingTriggerIds = utils::transform( 101 triggers, [](const auto& trigger) { return trigger->getId(); }); 102 103 auto [id, name] = 104 utils::generateId(triggerIdIn, triggerNameIn, triggerNameDefault, 105 existingTriggerIds, maxTriggerIdLength); 106 107 verifyAddTrigger(id, name, reportIds); 108 109 triggers.emplace_back(triggerFactory->make( 110 id, name, triggerActions, reportIds, *this, *triggerStorage, 111 labeledThresholdParams, labeledSensorsInfo)); 112 113 return *triggers.back(); 114 } 115 116 void TriggerManager::loadFromPersistent() 117 { 118 std::vector<interfaces::JsonStorage::FilePath> paths = 119 triggerStorage->list(); 120 121 for (const auto& path : paths) 122 { 123 std::optional<nlohmann::json> data = triggerStorage->load(path); 124 try 125 { 126 if (!data.has_value()) 127 { 128 throw std::runtime_error("Empty storage"); 129 } 130 size_t version = data->at("Version").get<size_t>(); 131 if (version != Trigger::triggerVersion) 132 { 133 throw std::runtime_error("Invalid version"); 134 } 135 const std::string& id = data->at("Id").get_ref<std::string&>(); 136 const std::string& name = data->at("Name").get_ref<std::string&>(); 137 int thresholdParamsDiscriminator = 138 data->at("ThresholdParamsDiscriminator").get<int>(); 139 const std::vector<std::string> triggerActions = 140 data->at("TriggerActions").get<std::vector<std::string>>(); 141 142 LabeledTriggerThresholdParams labeledThresholdParams; 143 if (0 == thresholdParamsDiscriminator) 144 { 145 labeledThresholdParams = 146 data->at("ThresholdParams") 147 .get<std::vector<numeric::LabeledThresholdParam>>(); 148 } 149 else 150 { 151 labeledThresholdParams = 152 data->at("ThresholdParams") 153 .get<std::vector<discrete::LabeledThresholdParam>>(); 154 } 155 156 auto reportIds = 157 data->at("ReportIds").get<std::vector<std::string>>(); 158 159 auto labeledSensorsInfo = 160 data->at("Sensors").get<std::vector<LabeledSensorInfo>>(); 161 162 addTrigger(id, name, triggerActions, labeledSensorsInfo, reportIds, 163 labeledThresholdParams); 164 } 165 catch (const std::exception& e) 166 { 167 phosphor::logging::log<phosphor::logging::level::ERR>( 168 "Failed to load trigger from storage", 169 phosphor::logging::entry( 170 "FILENAME=%s", 171 static_cast<std::filesystem::path>(path).c_str()), 172 phosphor::logging::entry("EXCEPTION_MSG=%s", e.what())); 173 triggerStorage->remove(path); 174 } 175 } 176 } 177