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 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 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 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 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 94 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 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 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