blob: b80afa7c15a94e453e0f0d38c3481827f7490d7f [file] [log] [blame]
#include "trigger.hpp"
#include "messages/collect_trigger_id.hpp"
#include "messages/trigger_presence_changed_ind.hpp"
#include "trigger_manager.hpp"
#include "types/report_types.hpp"
#include "types/trigger_types.hpp"
#include "utils/contains.hpp"
#include "utils/conversion_trigger.hpp"
#include "utils/dbus_path_utils.hpp"
#include "utils/transform.hpp"
#include <phosphor-logging/log.hpp>
Trigger::Trigger(
boost::asio::io_context& ioc,
const std::shared_ptr<sdbusplus::asio::object_server>& objServer,
TriggerId&& idIn, const std::string& nameIn,
const std::vector<TriggerAction>& triggerActionsIn,
const std::shared_ptr<std::vector<std::string>> reportIdsIn,
std::vector<std::shared_ptr<interfaces::Threshold>>&& thresholdsIn,
interfaces::TriggerManager& triggerManager,
interfaces::JsonStorage& triggerStorageIn,
const interfaces::TriggerFactory& triggerFactory, Sensors sensorsIn) :
id(std::move(idIn)),
path(utils::pathAppend(utils::constants::triggerDirPath, *id)),
name(nameIn), triggerActions(std::move(triggerActionsIn)),
reportIds(std::move(reportIdsIn)), thresholds(std::move(thresholdsIn)),
fileName(std::to_string(std::hash<std::string>{}(*id))),
triggerStorage(triggerStorageIn), sensors(std::move(sensorsIn)),
messanger(ioc)
{
deleteIface = objServer->add_unique_interface(
path, deleteIfaceName, [this, &ioc, &triggerManager](auto& dbusIface) {
dbusIface.register_method("Delete", [this, &ioc, &triggerManager] {
if (persistent)
{
triggerStorage.remove(fileName);
}
messanger.send(messages::TriggerPresenceChangedInd{
messages::Presence::Removed, *id, {}});
boost::asio::post(ioc, [this, &triggerManager] {
triggerManager.removeTrigger(this);
});
});
});
triggerIface = objServer->add_unique_interface(
path, triggerIfaceName, [this, &triggerFactory](auto& dbusIface) {
persistent = storeConfiguration();
dbusIface.register_property_rw(
"Persistent", persistent,
sdbusplus::vtable::property_::emits_change,
[this](bool newVal, const auto&) {
if (newVal == persistent)
{
return 1;
}
if (newVal)
{
persistent = storeConfiguration();
}
else
{
triggerStorage.remove(fileName);
persistent = false;
}
return 1;
},
[this](const auto&) { return persistent; });
dbusIface.register_property_rw(
"Thresholds", TriggerThresholdParams{},
sdbusplus::vtable::property_::emits_change,
[this, &triggerFactory](auto newVal, auto& oldVal) {
auto newThresholdParams =
std::visit(utils::ToLabeledThresholdParamConversion(), newVal);
TriggerManager::verifyThresholdParams(newThresholdParams);
triggerFactory.updateThresholds(thresholds, *id, triggerActions,
reportIds, sensors,
newThresholdParams);
oldVal = std::move(newVal);
return 1;
},
[this](const auto&) {
return fromLabeledThresholdParam(getLabeledThresholds());
});
dbusIface.register_property_rw(
"Sensors", SensorsInfo{},
sdbusplus::vtable::property_::emits_change,
[this, &triggerFactory](auto newVal, auto& oldVal) {
auto labeledSensorInfo =
triggerFactory.getLabeledSensorsInfo(newVal);
triggerFactory.updateSensors(sensors, labeledSensorInfo);
for (const auto& threshold : thresholds)
{
threshold->updateSensors(sensors);
}
oldVal = std::move(newVal);
return 1;
},
[this](const auto&) {
return utils::fromLabeledSensorsInfo(getLabeledSensorInfo());
});
dbusIface.register_property_rw(
"Reports", std::vector<sdbusplus::message::object_path>(),
sdbusplus::vtable::property_::emits_change,
[this](auto newVal, auto& oldVal) {
auto newReportIds = utils::transform<std::vector>(
newVal,
[](const auto& path) { return utils::reportPathToId(path); });
TriggerManager::verifyReportIds(newReportIds);
*reportIds = newReportIds;
messanger.send(messages::TriggerPresenceChangedInd{
messages::Presence::Exist, *id, *reportIds});
oldVal = std::move(newVal);
return 1;
},
[this](const auto&) {
return utils::transform<std::vector>(*reportIds,
[](const auto& id) {
return utils::pathAppend(utils::constants::reportDirPath, id);
});
});
dbusIface.register_property_r(
"Discrete", isDiscreate(), sdbusplus::vtable::property_::const_,
[this](const auto& x) { return isDiscreate(); });
dbusIface.register_property_rw(
"Name", name, sdbusplus::vtable::property_::emits_change,
[this](auto newVal, auto& oldVal) {
if (newVal.length() > utils::constants::maxIdNameLength)
{
throw errors::InvalidArgument("Name", "Name is too long.");
}
name = oldVal = newVal;
return 1;
},
[this](const auto&) { return name; });
dbusIface.register_property_r(
"TriggerActions", std::vector<std::string>(),
sdbusplus::vtable::property_::const_, [this](const auto&) {
return utils::transform(triggerActions, [](const auto& action) {
return actionToString(action);
});
});
});
for (const auto& threshold : thresholds)
{
threshold->initialize();
}
messanger.on_receive<messages::CollectTriggerIdReq>(
[this](const auto& msg) {
if (utils::contains(*reportIds, msg.reportId))
{
messanger.send(messages::CollectTriggerIdResp{*id});
}
});
messanger.send(messages::TriggerPresenceChangedInd{
messages::Presence::Exist, *id, *reportIds});
}
bool Trigger::storeConfiguration() const
{
try
{
nlohmann::json data;
auto labeledThresholdParams =
std::visit(utils::ToLabeledThresholdParamConversion(),
fromLabeledThresholdParam(getLabeledThresholds()));
data["Version"] = triggerVersion;
data["Id"] = *id;
data["Name"] = name;
data["ThresholdParamsDiscriminator"] = labeledThresholdParams.index();
data["TriggerActions"] = utils::transform(
triggerActions,
[](const auto& action) { return actionToString(action); });
data["ThresholdParams"] =
utils::labeledThresholdParamsToJson(labeledThresholdParams);
data["ReportIds"] = *reportIds;
data["Sensors"] = getLabeledSensorInfo();
triggerStorage.store(fileName, data);
}
catch (const std::exception& e)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
"Failed to store a trigger in storage",
phosphor::logging::entry("EXCEPTION_MSG=%s", e.what()));
return false;
}
return true;
}
std::vector<LabeledSensorInfo> Trigger::getLabeledSensorInfo() const
{
return utils::transform(sensors, [](const auto& sensor) {
return sensor->getLabeledSensorInfo();
});
}
std::vector<LabeledThresholdParam> Trigger::getLabeledThresholds() const
{
return utils::transform(thresholds, [](const auto& threshold) {
return threshold->getThresholdParam();
});
}
bool Trigger::isDiscreate() const
{
const auto labeledThresholds = getLabeledThresholds();
return utils::isFirstElementOfType<std::monostate>(labeledThresholds) ||
utils::isFirstElementOfType<discrete::LabeledThresholdParam>(
labeledThresholds);
}