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