diff options
-rw-r--r-- | redfish-core/include/utils/telemetry_utils.hpp | 19 | ||||
-rw-r--r-- | redfish-core/lib/metric_report_definition.hpp | 76 | ||||
-rw-r--r-- | redfish-core/lib/trigger.hpp | 718 |
3 files changed, 750 insertions, 63 deletions
diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp index fc045f6742..58ab1c9d28 100644 --- a/redfish-core/include/utils/telemetry_utils.hpp +++ b/redfish-core/include/utils/telemetry_utils.hpp @@ -34,6 +34,25 @@ inline std::string getDbusTriggerPath(const std::string& id) return {triggersPath / id}; } +inline std::optional<std::string> + getTriggerIdFromDbusPath(const std::string& dbusPath) +{ + sdbusplus::message::object_path converted(dbusPath); + + if (converted.parent_path() != + "/xyz/openbmc_project/Telemetry/Triggers/TelemetryService") + { + return std::nullopt; + } + + const std::string& id = converted.filename(); + if (id.empty()) + { + return std::nullopt; + } + return id; +} + struct IncorrectMetricUri { std::string uri; diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp index 6a03b7f043..fdd86d438f 100644 --- a/redfish-core/lib/metric_report_definition.hpp +++ b/redfish-core/lib/metric_report_definition.hpp @@ -743,6 +743,44 @@ class AddReport }; } // namespace telemetry +inline void handleMetricReportDelete( + App& app, const crow::Request& req, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) + +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + + const std::string reportPath = telemetry::getDbusReportPath(id); + + crow::connections::systemBus->async_method_call( + [asyncResp, id](const boost::system::error_code& ec) { + /* + * boost::system::errc and std::errc are missing value + * for EBADR error that is defined in Linux. + */ + if (ec.value() == EBADR) + { + messages::resourceNotFound(asyncResp->res, "MetricReportDefinition", + id); + return; + } + + if (ec) + { + BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; + messages::internalError(asyncResp->res); + return; + } + + asyncResp->res.result(boost::beast::http::status::no_content); + }, + telemetry::service, reportPath, "xyz.openbmc_project.Object.Delete", + "Delete"); +} + inline void requestRoutesMetricReportDefinitionCollection(App& app) { BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/") @@ -859,42 +897,6 @@ inline void requestRoutesMetricReportDefinition(App& app) "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/") .privileges(redfish::privileges::deleteMetricReportDefinitionCollection) .methods(boost::beast::http::verb::delete_)( - [&app](const crow::Request& req, - const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, - const std::string& id) - - { - if (!redfish::setUpRedfishRoute(app, req, asyncResp)) - { - return; - } - - const std::string reportPath = telemetry::getDbusReportPath(id); - - crow::connections::systemBus->async_method_call( - [asyncResp, id](const boost::system::error_code& ec) { - /* - * boost::system::errc and std::errc are missing value - * for EBADR error that is defined in Linux. - */ - if (ec.value() == EBADR) - { - messages::resourceNotFound(asyncResp->res, - "MetricReportDefinition", id); - return; - } - - if (ec) - { - BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; - messages::internalError(asyncResp->res); - return; - } - - asyncResp->res.result(boost::beast::http::status::no_content); - }, - telemetry::service, reportPath, "xyz.openbmc_project.Object.Delete", - "Delete"); - }); + std::bind_front(handleMetricReportDelete, std::ref(app))); } } // namespace redfish diff --git a/redfish-core/lib/trigger.hpp b/redfish-core/lib/trigger.hpp index 68d6dd2fad..33e3bdee72 100644 --- a/redfish-core/lib/trigger.hpp +++ b/redfish-core/lib/trigger.hpp @@ -1,8 +1,12 @@ #pragma once #include "app.hpp" +#include "generated/enums/resource.hpp" +#include "generated/enums/triggers.hpp" #include "query.hpp" #include "registries/privilege_registry.hpp" +#include "sensors.hpp" +#include "utility.hpp" #include "utils/collection.hpp" #include "utils/dbus_utils.hpp" #include "utils/telemetry_utils.hpp" @@ -31,6 +35,10 @@ using NumericThresholdParams = using DiscreteThresholdParams = std::tuple<std::string, std::string, uint64_t, std::string>; +using TriggerThresholdParams = + std::variant<std::vector<NumericThresholdParams>, + std::vector<DiscreteThresholdParams>>; + using TriggerThresholdParamsExt = std::variant<std::monostate, std::vector<NumericThresholdParams>, std::vector<DiscreteThresholdParams>>; @@ -43,48 +51,676 @@ using TriggerGetParamsVariant = TriggerSensorsParams, std::vector<std::string>, std::vector<sdbusplus::message::object_path>>; -inline std::optional<std::string> - getRedfishFromDbusAction(const std::string& dbusAction) +inline triggers::TriggerActionEnum + toRedfishTriggerAction(std::string_view dbusValue) +{ + if (dbusValue == + "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.UpdateReport") + { + return triggers::TriggerActionEnum::RedfishMetricReport; + } + if (dbusValue == + "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.LogToRedfishEventLog") + { + return triggers::TriggerActionEnum::RedfishEvent; + } + if (dbusValue == + "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.LogToJournal") + { + return triggers::TriggerActionEnum::LogToLogService; + } + return triggers::TriggerActionEnum::Invalid; +} + +inline std::string toDbusTriggerAction(std::string_view redfishValue) +{ + if (redfishValue == "RedfishMetricReport") + { + return "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.UpdateReport"; + } + if (redfishValue == "RedfishEvent") + { + return "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.LogToRedfishEventLog"; + } + if (redfishValue == "LogToLogService") + { + return "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.LogToJournal"; + } + return ""; +} + +inline std::string toDbusSeverity(std::string_view redfishValue) +{ + if (redfishValue == "OK") + { + return "xyz.openbmc_project.Telemetry.Trigger.Severity.OK"; + } + if (redfishValue == "Warning") + { + return "xyz.openbmc_project.Telemetry.Trigger.Severity.Warning"; + } + if (redfishValue == "Critical") + { + return "xyz.openbmc_project.Telemetry.Trigger.Severity.Critical"; + } + return ""; +} + +inline resource::Health toRedfishSeverity(std::string_view dbusValue) +{ + if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Severity.OK") + { + return resource::Health::OK; + } + if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Severity.Warning") + { + return resource::Health::Warning; + } + if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Severity.Critical") + { + return resource::Health::Critical; + } + return resource::Health::Invalid; +} + +inline std::string toDbusThresholdName(std::string_view redfishValue) +{ + if (redfishValue == "UpperCritical") + { + return "xyz.openbmc_project.Telemetry.Trigger.Type.UpperCritical"; + } + + if (redfishValue == "LowerCritical") + { + return "xyz.openbmc_project.Telemetry.Trigger.Type.LowerCritical"; + } + + if (redfishValue == "UpperWarning") + { + return "xyz.openbmc_project.Telemetry.Trigger.Type.UpperWarning"; + } + + if (redfishValue == "LowerWarning") + { + return "xyz.openbmc_project.Telemetry.Trigger.Type.LowerWarning"; + } + + return ""; +} + +inline std::string toRedfishThresholdName(std::string_view dbusValue) +{ + if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Type.UpperCritical") + { + return "UpperCritical"; + } + + if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Type.LowerCritical") + { + return "LowerCritical"; + } + + if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Type.UpperWarning") + { + return "UpperWarning"; + } + + if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Type.LowerWarning") + { + return "LowerWarning"; + } + + return ""; +} + +inline std::string toDbusActivation(std::string_view redfishValue) +{ + if (redfishValue == "Either") + { + return "xyz.openbmc_project.Telemetry.Trigger.Direction.Either"; + } + + if (redfishValue == "Decreasing") + { + return "xyz.openbmc_project.Telemetry.Trigger.Direction.Decreasing"; + } + + if (redfishValue == "Increasing") + { + return "xyz.openbmc_project.Telemetry.Trigger.Direction.Increasing"; + } + + return ""; +} + +inline triggers::ThresholdActivation + toRedfishActivation(std::string_view dbusValue) +{ + if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Direction.Either") + { + return triggers::ThresholdActivation::Either; + } + + if (dbusValue == + "xyz.openbmc_project.Telemetry.Trigger.Direction.Decreasing") + { + return triggers::ThresholdActivation::Decreasing; + } + + if (dbusValue == + "xyz.openbmc_project.Telemetry.Trigger.Direction.Increasing") + { + return triggers::ThresholdActivation::Increasing; + } + + return triggers::ThresholdActivation::Invalid; +} + +enum class MetricType +{ + Discrete, + Numeric +}; + +enum class DiscreteCondition +{ + Specified, + Changed +}; + +struct Context +{ + std::string id; + std::string name; + std::vector<std::string> actions; + std::vector<std::pair<sdbusplus::message::object_path, std::string>> + sensors; + std::vector<sdbusplus::message::object_path> reports; + TriggerThresholdParams thresholds; + + std::optional<DiscreteCondition> discreteCondition; + std::optional<MetricType> metricType; + std::optional<std::vector<std::string>> metricProperties; +}; + +inline std::optional<sdbusplus::message::object_path> + getReportPathFromReportDefinitionUri(const std::string& uri) +{ + boost::urls::result<boost::urls::url_view> parsed = + boost::urls::parse_relative_ref(uri); + + if (!parsed) + { + return std::nullopt; + } + + std::string id; + if (!crow::utility::readUrlSegments( + *parsed, "redfish", "v1", "TelemetryService", + "MetricReportDefinitions", std::ref(id))) + { + return std::nullopt; + } + + return sdbusplus::message::object_path( + "/xyz/openbmc_project/Telemetry/Reports") / + "TelemetryService" / id; +} + +inline std::optional<MetricType> getMetricType(const std::string& metricType) +{ + if (metricType == "Discrete") + { + return MetricType::Discrete; + } + if (metricType == "Numeric") + { + return MetricType::Numeric; + } + return std::nullopt; +} + +inline std::optional<DiscreteCondition> + getDiscreteCondition(const std::string& discreteTriggerCondition) +{ + if (discreteTriggerCondition == "Specified") + { + return DiscreteCondition::Specified; + } + if (discreteTriggerCondition == "Changed") + { + return DiscreteCondition::Changed; + } + return std::nullopt; +} + +inline bool parseNumericThresholds(crow::Response& res, + nlohmann::json& numericThresholds, + Context& ctx) +{ + nlohmann::json::object_t* obj = + numericThresholds.get_ptr<nlohmann::json::object_t*>(); + if (obj == nullptr) + { + messages::propertyValueTypeError(res, numericThresholds.dump(), + "NumericThresholds"); + return false; + } + + std::vector<NumericThresholdParams> parsedParams; + parsedParams.reserve(numericThresholds.size()); + + for (auto& key : *obj) + { + std::string dbusThresholdName = toDbusThresholdName(key.first); + if (dbusThresholdName.empty()) + { + messages::propertyUnknown(res, key.first); + return false; + } + + double reading = 0.0; + std::string activation; + std::string dwellTimeStr; + + if (!json_util::readJson(key.second, res, "Reading", reading, + "Activation", activation, "DwellTime", + dwellTimeStr)) + { + return false; + } + + std::string dbusActivation = toDbusActivation(activation); + + if (dbusActivation.empty()) + { + messages::propertyValueIncorrect(res, "Activation", activation); + return false; + } + + std::optional<std::chrono::milliseconds> dwellTime = + time_utils::fromDurationString(dwellTimeStr); + if (!dwellTime) + { + messages::propertyValueIncorrect(res, "DwellTime", dwellTimeStr); + return false; + } + + parsedParams.emplace_back(dbusThresholdName, + static_cast<uint64_t>(dwellTime->count()), + dbusActivation, reading); + } + + ctx.thresholds = std::move(parsedParams); + return true; +} + +inline bool parseDiscreteTriggers( + crow::Response& res, + std::optional<std::vector<nlohmann::json>>& discreteTriggers, Context& ctx) +{ + std::vector<DiscreteThresholdParams> parsedParams; + if (!discreteTriggers) + { + ctx.thresholds = std::move(parsedParams); + return true; + } + + parsedParams.reserve(discreteTriggers->size()); + for (nlohmann::json& thresholdInfo : *discreteTriggers) + { + std::optional<std::string> name = ""; + std::string value; + std::string dwellTimeStr; + std::string severity; + + if (!json_util::readJson(thresholdInfo, res, "Name", name, "Value", + value, "DwellTime", dwellTimeStr, "Severity", + severity)) + { + return false; + } + + std::optional<std::chrono::milliseconds> dwellTime = + time_utils::fromDurationString(dwellTimeStr); + if (!dwellTime) + { + messages::propertyValueIncorrect(res, "DwellTime", dwellTimeStr); + return false; + } + + std::string dbusSeverity = toDbusSeverity(severity); + if (dbusSeverity.empty()) + { + messages::propertyValueIncorrect(res, "Severity", severity); + return false; + } + + parsedParams.emplace_back(*name, dbusSeverity, + static_cast<uint64_t>(dwellTime->count()), + value); + } + + ctx.thresholds = std::move(parsedParams); + return true; +} + +inline bool parseTriggerThresholds( + crow::Response& res, + std::optional<std::vector<nlohmann::json>>& discreteTriggers, + std::optional<nlohmann::json>& numericThresholds, Context& ctx) +{ + if (discreteTriggers && numericThresholds) + { + messages::propertyValueConflict(res, "DiscreteTriggers", + "NumericThresholds"); + messages::propertyValueConflict(res, "NumericThresholds", + "DiscreteTriggers"); + return false; + } + + if (ctx.discreteCondition) + { + if (numericThresholds) + { + messages::propertyValueConflict(res, "DiscreteTriggerCondition", + "NumericThresholds"); + messages::propertyValueConflict(res, "NumericThresholds", + "DiscreteTriggerCondition"); + return false; + } + } + + if (ctx.metricType) + { + if (*ctx.metricType == MetricType::Discrete && numericThresholds) + { + messages::propertyValueConflict(res, "NumericThresholds", + "MetricType"); + return false; + } + if (*ctx.metricType == MetricType::Numeric && discreteTriggers) + { + messages::propertyValueConflict(res, "DiscreteTriggers", + "MetricType"); + return false; + } + if (*ctx.metricType == MetricType::Numeric && ctx.discreteCondition) + { + messages::propertyValueConflict(res, "DiscreteTriggers", + "DiscreteTriggerCondition"); + return false; + } + } + + if (discreteTriggers || ctx.discreteCondition || + (ctx.metricType && *ctx.metricType == MetricType::Discrete)) + { + if (ctx.discreteCondition) + { + if (*ctx.discreteCondition == DiscreteCondition::Specified && + !discreteTriggers) + { + messages::createFailedMissingReqProperties(res, + "DiscreteTriggers"); + return false; + } + if (discreteTriggers && + ((*ctx.discreteCondition == DiscreteCondition::Specified && + discreteTriggers->empty()) || + (*ctx.discreteCondition == DiscreteCondition::Changed && + !discreteTriggers->empty()))) + { + messages::propertyValueConflict(res, "DiscreteTriggers", + "DiscreteTriggerCondition"); + return false; + } + } + if (!parseDiscreteTriggers(res, discreteTriggers, ctx)) + { + return false; + } + } + else if (numericThresholds) + { + if (!parseNumericThresholds(res, *numericThresholds, ctx)) + { + return false; + } + } + else + { + messages::createFailedMissingReqProperties( + res, "'DiscreteTriggers', 'NumericThresholds', " + "'DiscreteTriggerCondition' or 'MetricType'"); + return false; + } + return true; +} + +inline bool parseLinks(crow::Response& res, nlohmann::json& links, Context& ctx) +{ + if (links.empty()) + { + return true; + } + + std::optional<std::vector<std::string>> metricReportDefinitions; + if (!json_util::readJson(links, res, "MetricReportDefinitions", + metricReportDefinitions)) + { + return false; + } + + if (metricReportDefinitions) + { + ctx.reports.reserve(metricReportDefinitions->size()); + for (std::string& reportDefinionUri : *metricReportDefinitions) + { + std::optional<sdbusplus::message::object_path> reportPath = + getReportPathFromReportDefinitionUri(reportDefinionUri); + if (!reportPath) + { + messages::propertyValueIncorrect(res, "MetricReportDefinitions", + reportDefinionUri); + return false; + } + ctx.reports.emplace_back(*reportPath); + } + } + return true; +} + +inline bool parseMetricProperties(crow::Response& res, Context& ctx) +{ + if (!ctx.metricProperties) + { + return true; + } + + ctx.sensors.reserve(ctx.metricProperties->size()); + + size_t uriIdx = 0; + for (const std::string& uriStr : *ctx.metricProperties) + { + boost::urls::result<boost::urls::url_view> uri = + boost::urls::parse_relative_ref(uriStr); + if (!uri) + { + messages::propertyValueIncorrect( + res, "MetricProperties/" + std::to_string(uriIdx), uriStr); + return false; + } + std::string chassisName; + std::string sensorName; + if (!crow::utility::readUrlSegments(*uri, "redfish", "v1", "Chassis", + std::ref(chassisName), "Sensors", + std::ref(sensorName))) + { + messages::propertyValueIncorrect( + res, "MetricProperties/" + std::to_string(uriIdx), uriStr); + return false; + } + + std::pair<std::string, std::string> split = + splitSensorNameAndType(sensorName); + if (split.first.empty() || split.second.empty()) + { + messages::propertyValueIncorrect( + res, "MetricProperties/" + std::to_string(uriIdx), uriStr); + return false; + } + + std::string sensorPath = "/xyz/openbmc_project/sensors/" + split.first + + '/' + split.second; + + ctx.sensors.emplace_back(sensorPath, uriStr); + uriIdx++; + } + return true; +} + +inline bool parsePostTriggerParams(crow::Response& res, + const crow::Request& req, Context& ctx) +{ + std::optional<std::string> id = ""; + std::optional<std::string> name = ""; + std::optional<std::string> metricType; + std::optional<std::vector<std::string>> triggerActions; + std::optional<std::string> discreteTriggerCondition; + std::optional<std::vector<nlohmann::json>> discreteTriggers; + std::optional<nlohmann::json> numericThresholds; + std::optional<nlohmann::json> links; + if (!json_util::readJsonPatch( + req, res, "Id", id, "Name", name, "MetricType", metricType, + "TriggerActions", triggerActions, "DiscreteTriggerCondition", + discreteTriggerCondition, "DiscreteTriggers", discreteTriggers, + "NumericThresholds", numericThresholds, "MetricProperties", + ctx.metricProperties, "Links", links)) + { + return false; + } + + ctx.id = *id; + ctx.name = *name; + + if (metricType) + { + if (!(ctx.metricType = getMetricType(*metricType))) + { + messages::propertyValueIncorrect(res, "MetricType", *metricType); + return false; + } + } + + if (discreteTriggerCondition) + { + if (!(ctx.discreteCondition = + getDiscreteCondition(*discreteTriggerCondition))) + { + messages::propertyValueIncorrect(res, "DiscreteTriggerCondition", + *discreteTriggerCondition); + return false; + } + } + + if (triggerActions) + { + ctx.actions.reserve(triggerActions->size()); + for (const std::string& action : *triggerActions) + { + std::string dbusAction = toDbusTriggerAction(action); + + if (dbusAction.empty()) + { + messages::propertyValueNotInList(res, action, "TriggerActions"); + return false; + } + + ctx.actions.emplace_back(dbusAction); + } + } + if (!parseMetricProperties(res, ctx)) + { + return false; + } + + if (!parseTriggerThresholds(res, discreteTriggers, numericThresholds, ctx)) + { + return false; + } + + if (links) + { + if (!parseLinks(res, *links, ctx)) + { + return false; + } + } + return true; +} + +inline void afterCreateTrigger( + const boost::system::error_code& ec, const std::string& dbusPath, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) { - std::optional<std::string> redfishAction = std::nullopt; - if (dbusAction == "UpdateReport") + if (ec == boost::system::errc::file_exists) { - redfishAction = "RedfishMetricReport"; + messages::resourceAlreadyExists(asyncResp->res, "Trigger", "Id", id); + return; } - if (dbusAction == "LogToRedfishEventLog") + if (ec == boost::system::errc::too_many_files_open) { - redfishAction = "RedfishEvent"; + messages::createLimitReachedForResource(asyncResp->res); + return; } - if (dbusAction == "LogToJournal") + if (ec) { - redfishAction = "LogToLogService"; + messages::internalError(asyncResp->res); + BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; + return; } - return redfishAction; + + const std::optional<std::string>& triggerId = + getTriggerIdFromDbusPath(dbusPath); + if (!triggerId) + { + messages::internalError(asyncResp->res); + BMCWEB_LOG_ERROR << "Unknown data returned by " + "AddTrigger DBus method"; + return; + } + + messages::created(asyncResp->res); + boost::urls::url locationUrl = boost::urls::format( + "/redfish/v1/TelemetryService/Triggers/{}", *triggerId); + asyncResp->res.addHeader("Location", locationUrl.buffer()); } -inline std::optional<std::vector<std::string>> +inline std::optional<nlohmann::json::array_t> getTriggerActions(const std::vector<std::string>& dbusActions) { - std::vector<std::string> triggerActions; + nlohmann::json::array_t triggerActions; for (const std::string& dbusAction : dbusActions) { - std::optional<std::string> redfishAction = - getRedfishFromDbusAction(dbusAction); + triggers::TriggerActionEnum redfishAction = + toRedfishTriggerAction(dbusAction); - if (!redfishAction) + if (redfishAction == triggers::TriggerActionEnum::Invalid) { return std::nullopt; } - triggerActions.push_back(*redfishAction); + triggerActions.emplace_back(redfishAction); } - return {std::move(triggerActions)}; + return triggerActions; } inline std::optional<nlohmann::json::array_t> getDiscreteTriggers(const TriggerThresholdParamsExt& thresholdParams) { + nlohmann::json::array_t triggers; const std::vector<DiscreteThresholdParams>* discreteParams = std::get_if<std::vector<DiscreteThresholdParams>>(&thresholdParams); @@ -93,7 +729,6 @@ inline std::optional<nlohmann::json::array_t> return std::nullopt; } - nlohmann::json::array_t triggers; for (const auto& [name, severity, dwellTime, value] : *discreteParams) { std::optional<std::string> duration = @@ -105,18 +740,19 @@ inline std::optional<nlohmann::json::array_t> } nlohmann::json::object_t trigger; trigger["Name"] = name; - trigger["Severity"] = severity; + trigger["Severity"] = toRedfishSeverity(severity); trigger["DwellTime"] = *duration; trigger["Value"] = value; triggers.emplace_back(std::move(trigger)); } - return {std::move(triggers)}; + return triggers; } inline std::optional<nlohmann::json> getNumericThresholds(const TriggerThresholdParamsExt& thresholdParams) { + nlohmann::json::object_t thresholds; const std::vector<NumericThresholdParams>* numericParams = std::get_if<std::vector<NumericThresholdParams>>(&thresholdParams); @@ -125,7 +761,6 @@ inline std::optional<nlohmann::json> return std::nullopt; } - nlohmann::json::object_t thresholds; for (const auto& [type, dwellTime, activation, reading] : *numericParams) { std::optional<std::string> duration = @@ -135,13 +770,13 @@ inline std::optional<nlohmann::json> { return std::nullopt; } - nlohmann::json& threshold = thresholds[type]; + nlohmann::json& threshold = thresholds[toRedfishThresholdName(type)]; threshold["Reading"] = reading; - threshold["Activation"] = activation; + threshold["Activation"] = toRedfishActivation(activation); threshold["DwellTime"] = *duration; } - return {std::move(thresholds)}; + return thresholds; } inline std::optional<nlohmann::json> getMetricReportDefinitions( @@ -208,7 +843,7 @@ inline bool fillTrigger( if (triggerActions != nullptr) { - std::optional<std::vector<std::string>> redfishTriggerActions = + std::optional<nlohmann::json::array_t> redfishTriggerActions = getTriggerActions(*triggerActions); if (!redfishTriggerActions) { @@ -216,7 +851,7 @@ inline bool fillTrigger( << "Property TriggerActions is invalid in Trigger: " << id; return false; } - json["TriggerActions"] = *triggerActions; + json["TriggerActions"] = *redfishTriggerActions; } if (reports != nullptr) @@ -290,6 +925,32 @@ inline bool fillTrigger( return true; } +inline void handleTriggerCollectionPost( + App& app, const crow::Request& req, + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) +{ + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } + + telemetry::Context ctx; + if (!telemetry::parsePostTriggerParams(asyncResp->res, req, ctx)) + { + return; + } + + crow::connections::systemBus->async_method_call( + [asyncResp, id = ctx.id](const boost::system::error_code& ec, + const std::string& dbusPath) { + afterCreateTrigger(ec, dbusPath, asyncResp, id); + }, + service, "/xyz/openbmc_project/Telemetry/Triggers", + "xyz.openbmc_project.Telemetry.TriggerManager", "AddTrigger", + "TelemetryService/" + ctx.id, ctx.name, ctx.actions, ctx.sensors, + ctx.reports, ctx.thresholds); +} + } // namespace telemetry inline void requestRoutesTriggerCollection(App& app) @@ -316,6 +977,11 @@ inline void requestRoutesTriggerCollection(App& app) interfaces, "/xyz/openbmc_project/Telemetry/Triggers/TelemetryService"); }); + + BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/Triggers/") + .privileges(redfish::privileges::postTriggersCollection) + .methods(boost::beast::http::verb::post)(std::bind_front( + telemetry::handleTriggerCollectionPost, std::ref(app))); } inline void requestRoutesTrigger(App& app) |