blob: e337bcac91d9d895a93d34c17f8c63ef39d5ec7a [file] [log] [blame]
#include "trigger_manager.hpp"
#include "trigger.hpp"
#include "types/trigger_types.hpp"
#include "utils/conversion_trigger.hpp"
#include "utils/dbus_path_utils.hpp"
#include "utils/make_id_name.hpp"
#include "utils/transform.hpp"
#include "utils/tstring.hpp"
#include <phosphor-logging/log.hpp>
#include <unordered_set>
TriggerManager::TriggerManager(
std::unique_ptr<interfaces::TriggerFactory> triggerFactoryIn,
std::unique_ptr<interfaces::JsonStorage> triggerStorageIn,
const std::shared_ptr<sdbusplus::asio::object_server>& objServer) :
triggerFactory(std::move(triggerFactoryIn)),
triggerStorage(std::move(triggerStorageIn))
{
loadFromPersistent();
managerIface = objServer->add_unique_interface(
triggerManagerPath, triggerManagerIfaceName, [this](auto& iface) {
iface.register_method(
"AddTrigger",
[this](
boost::asio::yield_context& yield, const std::string& id,
const std::string& name,
const std::vector<std::string>& triggerActions,
const SensorsInfo& sensors,
const std::vector<sdbusplus::message::object_path>& reports,
const TriggerThresholdParamsExt& thresholds) {
LabeledTriggerThresholdParams
labeledTriggerThresholdParams = std::visit(
utils::ToLabeledThresholdParamConversion(),
thresholds);
std::vector<LabeledSensorInfo> labeledSensorsInfo =
triggerFactory->getLabeledSensorsInfo(yield, sensors);
auto reportIds = utils::transform<std::vector>(
reports, [](const auto& item) {
return utils::reportPathToId(item);
});
return addTrigger(id, name, triggerActions,
labeledSensorsInfo, reportIds,
labeledTriggerThresholdParams)
.getPath();
});
});
}
void TriggerManager::removeTrigger(const interfaces::Trigger* trigger)
{
triggers.erase(
std::remove_if(triggers.begin(), triggers.end(),
[trigger](const auto& x) { return trigger == x.get(); }),
triggers.end());
}
void TriggerManager::verifyReportIds(
const std::vector<std::string>& newReportIds)
{
if (std::unordered_set(newReportIds.begin(), newReportIds.end()).size() !=
newReportIds.size())
{
throw sdbusplus::exception::SdBusError(
static_cast<int>(std::errc::invalid_argument),
"Duplicate element in ReportIds");
}
}
void TriggerManager::verifyThresholdParams(
const LabeledTriggerThresholdParams& thresholdParams)
{
namespace ts = utils::tstring;
if (auto discreteParams =
std::get_if<std::vector<discrete::LabeledThresholdParam>>(
&thresholdParams);
discreteParams != nullptr)
{
for (auto discreteParam : *discreteParams)
{
if (discreteParam.at_label<ts::UserId>().length() >
utils::constants::maxIdNameLength)
{
throw sdbusplus::exception::SdBusError(
static_cast<int>(std::errc::invalid_argument),
"UserId too long");
}
}
}
}
void TriggerManager::verifyAddTrigger(
const std::vector<std::string>& reportIds,
const LabeledTriggerThresholdParams& thresholdParams) const
{
if (triggers.size() >= maxTriggers)
{
throw sdbusplus::exception::SdBusError(
static_cast<int>(std::errc::too_many_files_open),
"Reached maximal trigger count");
}
verifyReportIds(reportIds);
verifyThresholdParams(thresholdParams);
}
interfaces::Trigger& TriggerManager::addTrigger(
const std::string& triggerIdIn, const std::string& triggerNameIn,
const std::vector<std::string>& triggerActions,
const std::vector<LabeledSensorInfo>& labeledSensorsInfo,
const std::vector<std::string>& reportIds,
const LabeledTriggerThresholdParams& labeledThresholdParams)
{
const auto existingTriggerIds = utils::transform(
triggers, [](const auto& trigger) { return trigger->getId(); });
auto [id, name] = utils::makeIdName(triggerIdIn, triggerNameIn,
triggerNameDefault, existingTriggerIds);
verifyAddTrigger(reportIds, labeledThresholdParams);
triggers.emplace_back(triggerFactory->make(
id, name, triggerActions, reportIds, *this, *triggerStorage,
labeledThresholdParams, labeledSensorsInfo));
return *triggers.back();
}
void TriggerManager::loadFromPersistent()
{
std::vector<interfaces::JsonStorage::FilePath> paths =
triggerStorage->list();
for (const auto& path : paths)
{
std::optional<nlohmann::json> data = triggerStorage->load(path);
try
{
if (!data.has_value())
{
throw std::runtime_error("Empty storage");
}
size_t version = data->at("Version").get<size_t>();
if (version != Trigger::triggerVersion)
{
throw std::runtime_error("Invalid version");
}
const std::string& id = data->at("Id").get_ref<std::string&>();
const std::string& name = data->at("Name").get_ref<std::string&>();
int thresholdParamsDiscriminator =
data->at("ThresholdParamsDiscriminator").get<int>();
const std::vector<std::string> triggerActions =
data->at("TriggerActions").get<std::vector<std::string>>();
LabeledTriggerThresholdParams labeledThresholdParams;
if (0 == thresholdParamsDiscriminator)
{
labeledThresholdParams =
data->at("ThresholdParams")
.get<std::vector<numeric::LabeledThresholdParam>>();
}
else
{
labeledThresholdParams =
data->at("ThresholdParams")
.get<std::vector<discrete::LabeledThresholdParam>>();
}
auto reportIds =
data->at("ReportIds").get<std::vector<std::string>>();
auto labeledSensorsInfo =
data->at("Sensors").get<std::vector<LabeledSensorInfo>>();
addTrigger(id, name, triggerActions, labeledSensorsInfo, reportIds,
labeledThresholdParams);
}
catch (const std::exception& e)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"Failed to load trigger from storage",
phosphor::logging::entry(
"FILENAME=%s",
static_cast<std::filesystem::path>(path).c_str()),
phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
triggerStorage->remove(path);
}
}
}