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