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