1*40e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 2*40e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 307148cf2SLukasz Kazmierczak #pragma once 407148cf2SLukasz Kazmierczak 53ccb3adbSEd Tanous #include "app.hpp" 6539d8c6bSEd Tanous #include "generated/enums/metric_definition.hpp" 7dd1c4a9cSSzymon Dompke #include "generated/enums/resource.hpp" 8dd1c4a9cSSzymon Dompke #include "generated/enums/triggers.hpp" 93ccb3adbSEd Tanous #include "query.hpp" 103ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 11dd1c4a9cSSzymon Dompke #include "utility.hpp" 1207148cf2SLukasz Kazmierczak #include "utils/collection.hpp" 133ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 145b90429aSEd Tanous #include "utils/json_utils.hpp" 151516c21bSJanet Adkins #include "utils/sensor_utils.hpp" 1607148cf2SLukasz Kazmierczak #include "utils/telemetry_utils.hpp" 173ccb3adbSEd Tanous #include "utils/time_utils.hpp" 1807148cf2SLukasz Kazmierczak 19ef4c65b7SEd Tanous #include <boost/url/format.hpp> 2089474494SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 2189474494SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 2207148cf2SLukasz Kazmierczak 237a1dbc48SGeorge Liu #include <array> 247a1dbc48SGeorge Liu #include <string_view> 251b7e696bSLukasz Kazmierczak #include <tuple> 261b7e696bSLukasz Kazmierczak #include <variant> 271b7e696bSLukasz Kazmierczak #include <vector> 281b7e696bSLukasz Kazmierczak 2907148cf2SLukasz Kazmierczak namespace redfish 3007148cf2SLukasz Kazmierczak { 3107148cf2SLukasz Kazmierczak namespace telemetry 3207148cf2SLukasz Kazmierczak { 3307148cf2SLukasz Kazmierczak constexpr const char* triggerInterface = 3407148cf2SLukasz Kazmierczak "xyz.openbmc_project.Telemetry.Trigger"; 3507148cf2SLukasz Kazmierczak 361b7e696bSLukasz Kazmierczak using NumericThresholdParams = 371b7e696bSLukasz Kazmierczak std::tuple<std::string, uint64_t, std::string, double>; 381b7e696bSLukasz Kazmierczak 391b7e696bSLukasz Kazmierczak using DiscreteThresholdParams = 401b7e696bSLukasz Kazmierczak std::tuple<std::string, std::string, uint64_t, std::string>; 411b7e696bSLukasz Kazmierczak 421b7e696bSLukasz Kazmierczak using TriggerSensorsParams = 431b7e696bSLukasz Kazmierczak std::vector<std::pair<sdbusplus::message::object_path, std::string>>; 441b7e696bSLukasz Kazmierczak 45dd1c4a9cSSzymon Dompke inline triggers::TriggerActionEnum 46dd1c4a9cSSzymon Dompke toRedfishTriggerAction(std::string_view dbusValue) 471b7e696bSLukasz Kazmierczak { 48dd1c4a9cSSzymon Dompke if (dbusValue == 49dd1c4a9cSSzymon Dompke "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.UpdateReport") 501b7e696bSLukasz Kazmierczak { 51dd1c4a9cSSzymon Dompke return triggers::TriggerActionEnum::RedfishMetricReport; 521b7e696bSLukasz Kazmierczak } 53dd1c4a9cSSzymon Dompke if (dbusValue == 54dd1c4a9cSSzymon Dompke "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.LogToRedfishEventLog") 551b7e696bSLukasz Kazmierczak { 56dd1c4a9cSSzymon Dompke return triggers::TriggerActionEnum::RedfishEvent; 571b7e696bSLukasz Kazmierczak } 58dd1c4a9cSSzymon Dompke if (dbusValue == 59dd1c4a9cSSzymon Dompke "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.LogToJournal") 601b7e696bSLukasz Kazmierczak { 61dd1c4a9cSSzymon Dompke return triggers::TriggerActionEnum::LogToLogService; 621b7e696bSLukasz Kazmierczak } 63dd1c4a9cSSzymon Dompke return triggers::TriggerActionEnum::Invalid; 641b7e696bSLukasz Kazmierczak } 651b7e696bSLukasz Kazmierczak 66dd1c4a9cSSzymon Dompke inline std::string toDbusTriggerAction(std::string_view redfishValue) 671b7e696bSLukasz Kazmierczak { 68dd1c4a9cSSzymon Dompke if (redfishValue == "RedfishMetricReport") 691b7e696bSLukasz Kazmierczak { 70dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.UpdateReport"; 71dd1c4a9cSSzymon Dompke } 72dd1c4a9cSSzymon Dompke if (redfishValue == "RedfishEvent") 73dd1c4a9cSSzymon Dompke { 74dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.LogToRedfishEventLog"; 75dd1c4a9cSSzymon Dompke } 76dd1c4a9cSSzymon Dompke if (redfishValue == "LogToLogService") 77dd1c4a9cSSzymon Dompke { 78dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.LogToJournal"; 79dd1c4a9cSSzymon Dompke } 80dd1c4a9cSSzymon Dompke return ""; 81dd1c4a9cSSzymon Dompke } 821b7e696bSLukasz Kazmierczak 83dd1c4a9cSSzymon Dompke inline std::string toDbusSeverity(std::string_view redfishValue) 84dd1c4a9cSSzymon Dompke { 85dd1c4a9cSSzymon Dompke if (redfishValue == "OK") 86dd1c4a9cSSzymon Dompke { 87dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.Severity.OK"; 88dd1c4a9cSSzymon Dompke } 89dd1c4a9cSSzymon Dompke if (redfishValue == "Warning") 90dd1c4a9cSSzymon Dompke { 91dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.Severity.Warning"; 92dd1c4a9cSSzymon Dompke } 93dd1c4a9cSSzymon Dompke if (redfishValue == "Critical") 94dd1c4a9cSSzymon Dompke { 95dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.Severity.Critical"; 96dd1c4a9cSSzymon Dompke } 97dd1c4a9cSSzymon Dompke return ""; 98dd1c4a9cSSzymon Dompke } 99dd1c4a9cSSzymon Dompke 100dd1c4a9cSSzymon Dompke inline resource::Health toRedfishSeverity(std::string_view dbusValue) 101dd1c4a9cSSzymon Dompke { 102dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Severity.OK") 103dd1c4a9cSSzymon Dompke { 104dd1c4a9cSSzymon Dompke return resource::Health::OK; 105dd1c4a9cSSzymon Dompke } 106dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Severity.Warning") 107dd1c4a9cSSzymon Dompke { 108dd1c4a9cSSzymon Dompke return resource::Health::Warning; 109dd1c4a9cSSzymon Dompke } 110dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Severity.Critical") 111dd1c4a9cSSzymon Dompke { 112dd1c4a9cSSzymon Dompke return resource::Health::Critical; 113dd1c4a9cSSzymon Dompke } 114dd1c4a9cSSzymon Dompke return resource::Health::Invalid; 115dd1c4a9cSSzymon Dompke } 116dd1c4a9cSSzymon Dompke 117dd1c4a9cSSzymon Dompke inline std::string toRedfishThresholdName(std::string_view dbusValue) 118dd1c4a9cSSzymon Dompke { 119dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Type.UpperCritical") 120dd1c4a9cSSzymon Dompke { 121dd1c4a9cSSzymon Dompke return "UpperCritical"; 122dd1c4a9cSSzymon Dompke } 123dd1c4a9cSSzymon Dompke 124dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Type.LowerCritical") 125dd1c4a9cSSzymon Dompke { 126dd1c4a9cSSzymon Dompke return "LowerCritical"; 127dd1c4a9cSSzymon Dompke } 128dd1c4a9cSSzymon Dompke 129dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Type.UpperWarning") 130dd1c4a9cSSzymon Dompke { 131dd1c4a9cSSzymon Dompke return "UpperWarning"; 132dd1c4a9cSSzymon Dompke } 133dd1c4a9cSSzymon Dompke 134dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Type.LowerWarning") 135dd1c4a9cSSzymon Dompke { 136dd1c4a9cSSzymon Dompke return "LowerWarning"; 137dd1c4a9cSSzymon Dompke } 138dd1c4a9cSSzymon Dompke 139dd1c4a9cSSzymon Dompke return ""; 140dd1c4a9cSSzymon Dompke } 141dd1c4a9cSSzymon Dompke 142dd1c4a9cSSzymon Dompke inline std::string toDbusActivation(std::string_view redfishValue) 143dd1c4a9cSSzymon Dompke { 144dd1c4a9cSSzymon Dompke if (redfishValue == "Either") 145dd1c4a9cSSzymon Dompke { 146dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.Direction.Either"; 147dd1c4a9cSSzymon Dompke } 148dd1c4a9cSSzymon Dompke 149dd1c4a9cSSzymon Dompke if (redfishValue == "Decreasing") 150dd1c4a9cSSzymon Dompke { 151dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.Direction.Decreasing"; 152dd1c4a9cSSzymon Dompke } 153dd1c4a9cSSzymon Dompke 154dd1c4a9cSSzymon Dompke if (redfishValue == "Increasing") 155dd1c4a9cSSzymon Dompke { 156dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.Direction.Increasing"; 157dd1c4a9cSSzymon Dompke } 158dd1c4a9cSSzymon Dompke 159dd1c4a9cSSzymon Dompke return ""; 160dd1c4a9cSSzymon Dompke } 161dd1c4a9cSSzymon Dompke 162dd1c4a9cSSzymon Dompke inline triggers::ThresholdActivation 163dd1c4a9cSSzymon Dompke toRedfishActivation(std::string_view dbusValue) 164dd1c4a9cSSzymon Dompke { 165dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Direction.Either") 166dd1c4a9cSSzymon Dompke { 167dd1c4a9cSSzymon Dompke return triggers::ThresholdActivation::Either; 168dd1c4a9cSSzymon Dompke } 169dd1c4a9cSSzymon Dompke 170dd1c4a9cSSzymon Dompke if (dbusValue == 171dd1c4a9cSSzymon Dompke "xyz.openbmc_project.Telemetry.Trigger.Direction.Decreasing") 172dd1c4a9cSSzymon Dompke { 173dd1c4a9cSSzymon Dompke return triggers::ThresholdActivation::Decreasing; 174dd1c4a9cSSzymon Dompke } 175dd1c4a9cSSzymon Dompke 176dd1c4a9cSSzymon Dompke if (dbusValue == 177dd1c4a9cSSzymon Dompke "xyz.openbmc_project.Telemetry.Trigger.Direction.Increasing") 178dd1c4a9cSSzymon Dompke { 179dd1c4a9cSSzymon Dompke return triggers::ThresholdActivation::Increasing; 180dd1c4a9cSSzymon Dompke } 181dd1c4a9cSSzymon Dompke 182dd1c4a9cSSzymon Dompke return triggers::ThresholdActivation::Invalid; 183dd1c4a9cSSzymon Dompke } 184dd1c4a9cSSzymon Dompke 185dd1c4a9cSSzymon Dompke enum class MetricType 186dd1c4a9cSSzymon Dompke { 187dd1c4a9cSSzymon Dompke Discrete, 188dd1c4a9cSSzymon Dompke Numeric 189dd1c4a9cSSzymon Dompke }; 190dd1c4a9cSSzymon Dompke 191dd1c4a9cSSzymon Dompke enum class DiscreteCondition 192dd1c4a9cSSzymon Dompke { 193dd1c4a9cSSzymon Dompke Specified, 194dd1c4a9cSSzymon Dompke Changed 195dd1c4a9cSSzymon Dompke }; 196dd1c4a9cSSzymon Dompke 197dd1c4a9cSSzymon Dompke struct Context 198dd1c4a9cSSzymon Dompke { 199dd1c4a9cSSzymon Dompke std::string id; 200dd1c4a9cSSzymon Dompke std::string name; 201dd1c4a9cSSzymon Dompke std::vector<std::string> actions; 202dd1c4a9cSSzymon Dompke std::vector<std::pair<sdbusplus::message::object_path, std::string>> 203dd1c4a9cSSzymon Dompke sensors; 204dd1c4a9cSSzymon Dompke std::vector<sdbusplus::message::object_path> reports; 20558c71488SEd Tanous std::vector<NumericThresholdParams> numericThresholds; 20658c71488SEd Tanous std::vector<DiscreteThresholdParams> discreteThresholds; 207dd1c4a9cSSzymon Dompke std::optional<DiscreteCondition> discreteCondition; 208dd1c4a9cSSzymon Dompke std::optional<MetricType> metricType; 209dd1c4a9cSSzymon Dompke std::optional<std::vector<std::string>> metricProperties; 210dd1c4a9cSSzymon Dompke }; 211dd1c4a9cSSzymon Dompke 212dd1c4a9cSSzymon Dompke inline std::optional<sdbusplus::message::object_path> 213dd1c4a9cSSzymon Dompke getReportPathFromReportDefinitionUri(const std::string& uri) 214dd1c4a9cSSzymon Dompke { 2156fd29553SEd Tanous boost::system::result<boost::urls::url_view> parsed = 216dd1c4a9cSSzymon Dompke boost::urls::parse_relative_ref(uri); 217dd1c4a9cSSzymon Dompke 218dd1c4a9cSSzymon Dompke if (!parsed) 2191b7e696bSLukasz Kazmierczak { 2201b7e696bSLukasz Kazmierczak return std::nullopt; 2211b7e696bSLukasz Kazmierczak } 2221b7e696bSLukasz Kazmierczak 223dd1c4a9cSSzymon Dompke std::string id; 224dd1c4a9cSSzymon Dompke if (!crow::utility::readUrlSegments( 225dd1c4a9cSSzymon Dompke *parsed, "redfish", "v1", "TelemetryService", 226dd1c4a9cSSzymon Dompke "MetricReportDefinitions", std::ref(id))) 227dd1c4a9cSSzymon Dompke { 228dd1c4a9cSSzymon Dompke return std::nullopt; 2291b7e696bSLukasz Kazmierczak } 2301b7e696bSLukasz Kazmierczak 231dd1c4a9cSSzymon Dompke return sdbusplus::message::object_path( 232dd1c4a9cSSzymon Dompke "/xyz/openbmc_project/Telemetry/Reports") / 233dd1c4a9cSSzymon Dompke "TelemetryService" / id; 234dd1c4a9cSSzymon Dompke } 235dd1c4a9cSSzymon Dompke 236dd1c4a9cSSzymon Dompke inline std::optional<MetricType> getMetricType(const std::string& metricType) 237dd1c4a9cSSzymon Dompke { 238dd1c4a9cSSzymon Dompke if (metricType == "Discrete") 239dd1c4a9cSSzymon Dompke { 240dd1c4a9cSSzymon Dompke return MetricType::Discrete; 241dd1c4a9cSSzymon Dompke } 242dd1c4a9cSSzymon Dompke if (metricType == "Numeric") 243dd1c4a9cSSzymon Dompke { 244dd1c4a9cSSzymon Dompke return MetricType::Numeric; 245dd1c4a9cSSzymon Dompke } 246dd1c4a9cSSzymon Dompke return std::nullopt; 247dd1c4a9cSSzymon Dompke } 248dd1c4a9cSSzymon Dompke 249dd1c4a9cSSzymon Dompke inline std::optional<DiscreteCondition> 250dd1c4a9cSSzymon Dompke getDiscreteCondition(const std::string& discreteTriggerCondition) 251dd1c4a9cSSzymon Dompke { 252dd1c4a9cSSzymon Dompke if (discreteTriggerCondition == "Specified") 253dd1c4a9cSSzymon Dompke { 254dd1c4a9cSSzymon Dompke return DiscreteCondition::Specified; 255dd1c4a9cSSzymon Dompke } 256dd1c4a9cSSzymon Dompke if (discreteTriggerCondition == "Changed") 257dd1c4a9cSSzymon Dompke { 258dd1c4a9cSSzymon Dompke return DiscreteCondition::Changed; 259dd1c4a9cSSzymon Dompke } 260dd1c4a9cSSzymon Dompke return std::nullopt; 261dd1c4a9cSSzymon Dompke } 262dd1c4a9cSSzymon Dompke 2632932dcb6SEd Tanous inline bool parseThreshold(crow::Response& res, 2642932dcb6SEd Tanous nlohmann::json::object_t& threshold, 2652932dcb6SEd Tanous std::string_view dbusThresholdName, 2662932dcb6SEd Tanous std::vector<NumericThresholdParams>& parsedParams) 267dd1c4a9cSSzymon Dompke { 268dd1c4a9cSSzymon Dompke double reading = 0.0; 269dd1c4a9cSSzymon Dompke std::string activation; 270dd1c4a9cSSzymon Dompke std::string dwellTimeStr; 271dd1c4a9cSSzymon Dompke 272afc474aeSMyung Bae if (!json_util::readJsonObject( // 273afc474aeSMyung Bae threshold, res, // 274afc474aeSMyung Bae "Activation", activation, // 275afc474aeSMyung Bae "DwellTime", dwellTimeStr, // 276afc474aeSMyung Bae "Reading", reading // 277afc474aeSMyung Bae )) 278dd1c4a9cSSzymon Dompke { 279dd1c4a9cSSzymon Dompke return false; 280dd1c4a9cSSzymon Dompke } 281dd1c4a9cSSzymon Dompke 282dd1c4a9cSSzymon Dompke std::string dbusActivation = toDbusActivation(activation); 283dd1c4a9cSSzymon Dompke 284dd1c4a9cSSzymon Dompke if (dbusActivation.empty()) 285dd1c4a9cSSzymon Dompke { 286dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "Activation", activation); 287dd1c4a9cSSzymon Dompke return false; 288dd1c4a9cSSzymon Dompke } 289dd1c4a9cSSzymon Dompke 290dd1c4a9cSSzymon Dompke std::optional<std::chrono::milliseconds> dwellTime = 291dd1c4a9cSSzymon Dompke time_utils::fromDurationString(dwellTimeStr); 292dd1c4a9cSSzymon Dompke if (!dwellTime) 293dd1c4a9cSSzymon Dompke { 294dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "DwellTime", dwellTimeStr); 295dd1c4a9cSSzymon Dompke return false; 296dd1c4a9cSSzymon Dompke } 297dd1c4a9cSSzymon Dompke 298dd1c4a9cSSzymon Dompke parsedParams.emplace_back(dbusThresholdName, 299dd1c4a9cSSzymon Dompke static_cast<uint64_t>(dwellTime->count()), 300dd1c4a9cSSzymon Dompke dbusActivation, reading); 3012932dcb6SEd Tanous return true; 3022932dcb6SEd Tanous } 3032932dcb6SEd Tanous 3042932dcb6SEd Tanous struct NumericThresholds 3052932dcb6SEd Tanous { 3062932dcb6SEd Tanous std::optional<nlohmann::json::object_t> upperCritical; 3072932dcb6SEd Tanous std::optional<nlohmann::json::object_t> upperWarning; 3082932dcb6SEd Tanous std::optional<nlohmann::json::object_t> lowerWarning; 3092932dcb6SEd Tanous std::optional<nlohmann::json::object_t> lowerCritical; 3102932dcb6SEd Tanous 3112932dcb6SEd Tanous bool any() const 3122932dcb6SEd Tanous { 3132932dcb6SEd Tanous return upperCritical || upperWarning || lowerWarning || lowerCritical; 3142932dcb6SEd Tanous } 3152932dcb6SEd Tanous }; 3162932dcb6SEd Tanous 317bd79bce8SPatrick Williams inline bool parseNumericThresholds( 318bd79bce8SPatrick Williams crow::Response& res, NumericThresholds& numericThresholds, Context& ctx) 3192932dcb6SEd Tanous { 3202932dcb6SEd Tanous std::vector<NumericThresholdParams> parsedParams; 3212932dcb6SEd Tanous if (numericThresholds.upperCritical) 3222932dcb6SEd Tanous { 3232932dcb6SEd Tanous if (!parseThreshold( 3242932dcb6SEd Tanous res, *numericThresholds.upperCritical, 3252932dcb6SEd Tanous "xyz.openbmc_project.Telemetry.Trigger.Type.UpperCritical", 3262932dcb6SEd Tanous parsedParams)) 3272932dcb6SEd Tanous { 3282932dcb6SEd Tanous return false; 3292932dcb6SEd Tanous } 3302932dcb6SEd Tanous } 3312932dcb6SEd Tanous if (numericThresholds.upperWarning) 3322932dcb6SEd Tanous { 3332932dcb6SEd Tanous if (!parseThreshold( 3342932dcb6SEd Tanous res, *numericThresholds.upperWarning, 3352932dcb6SEd Tanous "xyz.openbmc_project.Telemetry.Trigger.Type.UpperWarning", 3362932dcb6SEd Tanous parsedParams)) 3372932dcb6SEd Tanous { 3382932dcb6SEd Tanous return false; 3392932dcb6SEd Tanous } 3402932dcb6SEd Tanous } 3412932dcb6SEd Tanous if (numericThresholds.lowerWarning) 3422932dcb6SEd Tanous { 3432932dcb6SEd Tanous if (!parseThreshold( 3442932dcb6SEd Tanous res, *numericThresholds.lowerWarning, 3452932dcb6SEd Tanous "xyz.openbmc_project.Telemetry.Trigger.Type.LowerWarning", 3462932dcb6SEd Tanous parsedParams)) 3472932dcb6SEd Tanous { 3482932dcb6SEd Tanous return false; 3492932dcb6SEd Tanous } 3502932dcb6SEd Tanous } 3512932dcb6SEd Tanous if (numericThresholds.lowerCritical) 3522932dcb6SEd Tanous { 3532932dcb6SEd Tanous if (!parseThreshold( 3542932dcb6SEd Tanous res, *numericThresholds.lowerCritical, 3552932dcb6SEd Tanous "xyz.openbmc_project.Telemetry.Trigger.Type.LowerCritical", 3562932dcb6SEd Tanous parsedParams)) 3572932dcb6SEd Tanous { 3582932dcb6SEd Tanous return false; 3592932dcb6SEd Tanous } 360dd1c4a9cSSzymon Dompke } 361dd1c4a9cSSzymon Dompke 36258c71488SEd Tanous ctx.numericThresholds = std::move(parsedParams); 363dd1c4a9cSSzymon Dompke return true; 364dd1c4a9cSSzymon Dompke } 365dd1c4a9cSSzymon Dompke 366dd1c4a9cSSzymon Dompke inline bool parseDiscreteTriggers( 367dd1c4a9cSSzymon Dompke crow::Response& res, 3682932dcb6SEd Tanous std::optional<std::vector<nlohmann::json::object_t>>& discreteTriggers, 3692932dcb6SEd Tanous Context& ctx) 370dd1c4a9cSSzymon Dompke { 371dd1c4a9cSSzymon Dompke std::vector<DiscreteThresholdParams> parsedParams; 372dd1c4a9cSSzymon Dompke if (!discreteTriggers) 373dd1c4a9cSSzymon Dompke { 37458c71488SEd Tanous ctx.discreteThresholds = std::move(parsedParams); 375dd1c4a9cSSzymon Dompke return true; 376dd1c4a9cSSzymon Dompke } 377dd1c4a9cSSzymon Dompke 378dd1c4a9cSSzymon Dompke parsedParams.reserve(discreteTriggers->size()); 3792932dcb6SEd Tanous for (nlohmann::json::object_t& thresholdInfo : *discreteTriggers) 380dd1c4a9cSSzymon Dompke { 381dd1c4a9cSSzymon Dompke std::optional<std::string> name = ""; 382dd1c4a9cSSzymon Dompke std::string value; 383dd1c4a9cSSzymon Dompke std::string dwellTimeStr; 384dd1c4a9cSSzymon Dompke std::string severity; 385dd1c4a9cSSzymon Dompke 386afc474aeSMyung Bae if (!json_util::readJsonObject( // 387afc474aeSMyung Bae thresholdInfo, res, // 388afc474aeSMyung Bae "DwellTime", dwellTimeStr, // 389afc474aeSMyung Bae "Name", name, // 390afc474aeSMyung Bae "Severity", severity, // 391afc474aeSMyung Bae "Value", value // 392afc474aeSMyung Bae )) 393dd1c4a9cSSzymon Dompke { 394dd1c4a9cSSzymon Dompke return false; 395dd1c4a9cSSzymon Dompke } 396dd1c4a9cSSzymon Dompke 397dd1c4a9cSSzymon Dompke std::optional<std::chrono::milliseconds> dwellTime = 398dd1c4a9cSSzymon Dompke time_utils::fromDurationString(dwellTimeStr); 399dd1c4a9cSSzymon Dompke if (!dwellTime) 400dd1c4a9cSSzymon Dompke { 401dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "DwellTime", dwellTimeStr); 402dd1c4a9cSSzymon Dompke return false; 403dd1c4a9cSSzymon Dompke } 404dd1c4a9cSSzymon Dompke 405dd1c4a9cSSzymon Dompke std::string dbusSeverity = toDbusSeverity(severity); 406dd1c4a9cSSzymon Dompke if (dbusSeverity.empty()) 407dd1c4a9cSSzymon Dompke { 408dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "Severity", severity); 409dd1c4a9cSSzymon Dompke return false; 410dd1c4a9cSSzymon Dompke } 411dd1c4a9cSSzymon Dompke 412dd1c4a9cSSzymon Dompke parsedParams.emplace_back(*name, dbusSeverity, 413dd1c4a9cSSzymon Dompke static_cast<uint64_t>(dwellTime->count()), 414dd1c4a9cSSzymon Dompke value); 415dd1c4a9cSSzymon Dompke } 416dd1c4a9cSSzymon Dompke 41758c71488SEd Tanous ctx.discreteThresholds = std::move(parsedParams); 418dd1c4a9cSSzymon Dompke return true; 419dd1c4a9cSSzymon Dompke } 420dd1c4a9cSSzymon Dompke 421dd1c4a9cSSzymon Dompke inline bool parseTriggerThresholds( 422dd1c4a9cSSzymon Dompke crow::Response& res, 4232932dcb6SEd Tanous std::optional<std::vector<nlohmann::json::object_t>>& discreteTriggers, 4242932dcb6SEd Tanous NumericThresholds& numericThresholds, Context& ctx) 425dd1c4a9cSSzymon Dompke { 4262932dcb6SEd Tanous if (discreteTriggers && numericThresholds.any()) 427dd1c4a9cSSzymon Dompke { 428dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "DiscreteTriggers", 429dd1c4a9cSSzymon Dompke "NumericThresholds"); 430dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "NumericThresholds", 431dd1c4a9cSSzymon Dompke "DiscreteTriggers"); 432dd1c4a9cSSzymon Dompke return false; 433dd1c4a9cSSzymon Dompke } 434dd1c4a9cSSzymon Dompke 435dd1c4a9cSSzymon Dompke if (ctx.discreteCondition) 436dd1c4a9cSSzymon Dompke { 4372932dcb6SEd Tanous if (numericThresholds.any()) 438dd1c4a9cSSzymon Dompke { 439dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "DiscreteTriggerCondition", 440dd1c4a9cSSzymon Dompke "NumericThresholds"); 441dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "NumericThresholds", 442dd1c4a9cSSzymon Dompke "DiscreteTriggerCondition"); 443dd1c4a9cSSzymon Dompke return false; 444dd1c4a9cSSzymon Dompke } 445dd1c4a9cSSzymon Dompke } 446dd1c4a9cSSzymon Dompke 447dd1c4a9cSSzymon Dompke if (ctx.metricType) 448dd1c4a9cSSzymon Dompke { 4492932dcb6SEd Tanous if (*ctx.metricType == MetricType::Discrete && numericThresholds.any()) 450dd1c4a9cSSzymon Dompke { 451dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "NumericThresholds", 452dd1c4a9cSSzymon Dompke "MetricType"); 453dd1c4a9cSSzymon Dompke return false; 454dd1c4a9cSSzymon Dompke } 455dd1c4a9cSSzymon Dompke if (*ctx.metricType == MetricType::Numeric && discreteTriggers) 456dd1c4a9cSSzymon Dompke { 457dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "DiscreteTriggers", 458dd1c4a9cSSzymon Dompke "MetricType"); 459dd1c4a9cSSzymon Dompke return false; 460dd1c4a9cSSzymon Dompke } 461dd1c4a9cSSzymon Dompke if (*ctx.metricType == MetricType::Numeric && ctx.discreteCondition) 462dd1c4a9cSSzymon Dompke { 463dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "DiscreteTriggers", 464dd1c4a9cSSzymon Dompke "DiscreteTriggerCondition"); 465dd1c4a9cSSzymon Dompke return false; 466dd1c4a9cSSzymon Dompke } 467dd1c4a9cSSzymon Dompke } 468dd1c4a9cSSzymon Dompke 469dd1c4a9cSSzymon Dompke if (discreteTriggers || ctx.discreteCondition || 470dd1c4a9cSSzymon Dompke (ctx.metricType && *ctx.metricType == MetricType::Discrete)) 471dd1c4a9cSSzymon Dompke { 472dd1c4a9cSSzymon Dompke if (ctx.discreteCondition) 473dd1c4a9cSSzymon Dompke { 474dd1c4a9cSSzymon Dompke if (*ctx.discreteCondition == DiscreteCondition::Specified && 475dd1c4a9cSSzymon Dompke !discreteTriggers) 476dd1c4a9cSSzymon Dompke { 477dd1c4a9cSSzymon Dompke messages::createFailedMissingReqProperties(res, 478dd1c4a9cSSzymon Dompke "DiscreteTriggers"); 479dd1c4a9cSSzymon Dompke return false; 480dd1c4a9cSSzymon Dompke } 481dd1c4a9cSSzymon Dompke if (discreteTriggers && 482dd1c4a9cSSzymon Dompke ((*ctx.discreteCondition == DiscreteCondition::Specified && 483dd1c4a9cSSzymon Dompke discreteTriggers->empty()) || 484dd1c4a9cSSzymon Dompke (*ctx.discreteCondition == DiscreteCondition::Changed && 485dd1c4a9cSSzymon Dompke !discreteTriggers->empty()))) 486dd1c4a9cSSzymon Dompke { 487dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "DiscreteTriggers", 488dd1c4a9cSSzymon Dompke "DiscreteTriggerCondition"); 489dd1c4a9cSSzymon Dompke return false; 490dd1c4a9cSSzymon Dompke } 491dd1c4a9cSSzymon Dompke } 492dd1c4a9cSSzymon Dompke if (!parseDiscreteTriggers(res, discreteTriggers, ctx)) 493dd1c4a9cSSzymon Dompke { 494dd1c4a9cSSzymon Dompke return false; 495dd1c4a9cSSzymon Dompke } 496dd1c4a9cSSzymon Dompke } 4972932dcb6SEd Tanous else if (numericThresholds.any()) 498dd1c4a9cSSzymon Dompke { 4992932dcb6SEd Tanous if (!parseNumericThresholds(res, numericThresholds, ctx)) 500dd1c4a9cSSzymon Dompke { 501dd1c4a9cSSzymon Dompke return false; 502dd1c4a9cSSzymon Dompke } 503dd1c4a9cSSzymon Dompke } 504dd1c4a9cSSzymon Dompke else 505dd1c4a9cSSzymon Dompke { 506dd1c4a9cSSzymon Dompke messages::createFailedMissingReqProperties( 507dd1c4a9cSSzymon Dompke res, "'DiscreteTriggers', 'NumericThresholds', " 508dd1c4a9cSSzymon Dompke "'DiscreteTriggerCondition' or 'MetricType'"); 509dd1c4a9cSSzymon Dompke return false; 510dd1c4a9cSSzymon Dompke } 511dd1c4a9cSSzymon Dompke return true; 512dd1c4a9cSSzymon Dompke } 513dd1c4a9cSSzymon Dompke 5142932dcb6SEd Tanous inline bool parseLinks(crow::Response& res, 5152932dcb6SEd Tanous const std::vector<std::string>& metricReportDefinitions, 5162932dcb6SEd Tanous Context& ctx) 517dd1c4a9cSSzymon Dompke { 5182932dcb6SEd Tanous ctx.reports.reserve(metricReportDefinitions.size()); 5192932dcb6SEd Tanous for (const std::string& reportDefinionUri : metricReportDefinitions) 520dd1c4a9cSSzymon Dompke { 521dd1c4a9cSSzymon Dompke std::optional<sdbusplus::message::object_path> reportPath = 522dd1c4a9cSSzymon Dompke getReportPathFromReportDefinitionUri(reportDefinionUri); 523dd1c4a9cSSzymon Dompke if (!reportPath) 524dd1c4a9cSSzymon Dompke { 525dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "MetricReportDefinitions", 526dd1c4a9cSSzymon Dompke reportDefinionUri); 527dd1c4a9cSSzymon Dompke return false; 528dd1c4a9cSSzymon Dompke } 529dd1c4a9cSSzymon Dompke ctx.reports.emplace_back(*reportPath); 530dd1c4a9cSSzymon Dompke } 531dd1c4a9cSSzymon Dompke return true; 532dd1c4a9cSSzymon Dompke } 533dd1c4a9cSSzymon Dompke 534dd1c4a9cSSzymon Dompke inline bool parseMetricProperties(crow::Response& res, Context& ctx) 535dd1c4a9cSSzymon Dompke { 536dd1c4a9cSSzymon Dompke if (!ctx.metricProperties) 537dd1c4a9cSSzymon Dompke { 538dd1c4a9cSSzymon Dompke return true; 539dd1c4a9cSSzymon Dompke } 540dd1c4a9cSSzymon Dompke 541dd1c4a9cSSzymon Dompke ctx.sensors.reserve(ctx.metricProperties->size()); 542dd1c4a9cSSzymon Dompke 543dd1c4a9cSSzymon Dompke size_t uriIdx = 0; 544dd1c4a9cSSzymon Dompke for (const std::string& uriStr : *ctx.metricProperties) 545dd1c4a9cSSzymon Dompke { 5464a7fbefdSEd Tanous boost::system::result<boost::urls::url> uri = 547dd1c4a9cSSzymon Dompke boost::urls::parse_relative_ref(uriStr); 548dd1c4a9cSSzymon Dompke if (!uri) 549dd1c4a9cSSzymon Dompke { 550dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect( 551dd1c4a9cSSzymon Dompke res, "MetricProperties/" + std::to_string(uriIdx), uriStr); 552dd1c4a9cSSzymon Dompke return false; 553dd1c4a9cSSzymon Dompke } 554dd1c4a9cSSzymon Dompke std::string chassisName; 555dd1c4a9cSSzymon Dompke std::string sensorName; 556dd1c4a9cSSzymon Dompke if (!crow::utility::readUrlSegments(*uri, "redfish", "v1", "Chassis", 557dd1c4a9cSSzymon Dompke std::ref(chassisName), "Sensors", 558dd1c4a9cSSzymon Dompke std::ref(sensorName))) 559dd1c4a9cSSzymon Dompke { 560dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect( 561dd1c4a9cSSzymon Dompke res, "MetricProperties/" + std::to_string(uriIdx), uriStr); 562dd1c4a9cSSzymon Dompke return false; 563dd1c4a9cSSzymon Dompke } 564dd1c4a9cSSzymon Dompke 565dd1c4a9cSSzymon Dompke std::pair<std::string, std::string> split = 5661516c21bSJanet Adkins redfish::sensor_utils::splitSensorNameAndType(sensorName); 567dd1c4a9cSSzymon Dompke if (split.first.empty() || split.second.empty()) 568dd1c4a9cSSzymon Dompke { 569dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect( 570dd1c4a9cSSzymon Dompke res, "MetricProperties/" + std::to_string(uriIdx), uriStr); 571dd1c4a9cSSzymon Dompke return false; 572dd1c4a9cSSzymon Dompke } 573dd1c4a9cSSzymon Dompke 574bd79bce8SPatrick Williams std::string sensorPath = 575bd79bce8SPatrick Williams "/xyz/openbmc_project/sensors/" + split.first + '/' + split.second; 576dd1c4a9cSSzymon Dompke 577dd1c4a9cSSzymon Dompke ctx.sensors.emplace_back(sensorPath, uriStr); 578dd1c4a9cSSzymon Dompke uriIdx++; 579dd1c4a9cSSzymon Dompke } 580dd1c4a9cSSzymon Dompke return true; 581dd1c4a9cSSzymon Dompke } 582dd1c4a9cSSzymon Dompke 583dd1c4a9cSSzymon Dompke inline bool parsePostTriggerParams(crow::Response& res, 584dd1c4a9cSSzymon Dompke const crow::Request& req, Context& ctx) 585dd1c4a9cSSzymon Dompke { 586dd1c4a9cSSzymon Dompke std::optional<std::string> id = ""; 587dd1c4a9cSSzymon Dompke std::optional<std::string> name = ""; 588dd1c4a9cSSzymon Dompke std::optional<std::string> metricType; 589dd1c4a9cSSzymon Dompke std::optional<std::vector<std::string>> triggerActions; 590dd1c4a9cSSzymon Dompke std::optional<std::string> discreteTriggerCondition; 5912932dcb6SEd Tanous std::optional<std::vector<nlohmann::json::object_t>> discreteTriggers; 5922932dcb6SEd Tanous std::optional<std::vector<std::string>> metricReportDefinitions; 5932932dcb6SEd Tanous NumericThresholds thresholds; 594afc474aeSMyung Bae 595afc474aeSMyung Bae if (!json_util::readJsonPatch( // 596afc474aeSMyung Bae req, res, // 597afc474aeSMyung Bae "Id", id, // 598afc474aeSMyung Bae "DiscreteTriggerCondition", discreteTriggerCondition, // 599afc474aeSMyung Bae "DiscreteTriggers", discreteTriggers, // 600afc474aeSMyung Bae "Links/MetricReportDefinitions", metricReportDefinitions, // 601afc474aeSMyung Bae "MetricProperties", ctx.metricProperties, // 602afc474aeSMyung Bae "MetricType", metricType, // 603afc474aeSMyung Bae "Name", name, // 604afc474aeSMyung Bae "NumericThresholds/LowerCritical", thresholds.lowerCritical, // 605afc474aeSMyung Bae "NumericThresholds/LowerWarning", thresholds.lowerWarning, // 606afc474aeSMyung Bae "NumericThresholds/UpperCritical", thresholds.upperCritical, // 607afc474aeSMyung Bae "NumericThresholds/UpperWarning", thresholds.upperWarning, // 608afc474aeSMyung Bae "TriggerActions", triggerActions // 609afc474aeSMyung Bae )) 610dd1c4a9cSSzymon Dompke { 611dd1c4a9cSSzymon Dompke return false; 612dd1c4a9cSSzymon Dompke } 613dd1c4a9cSSzymon Dompke 614dd1c4a9cSSzymon Dompke ctx.id = *id; 615dd1c4a9cSSzymon Dompke ctx.name = *name; 616dd1c4a9cSSzymon Dompke 617dd1c4a9cSSzymon Dompke if (metricType) 618dd1c4a9cSSzymon Dompke { 619d5736ef2SEd Tanous ctx.metricType = getMetricType(*metricType); 620d5736ef2SEd Tanous if (!ctx.metricType) 621dd1c4a9cSSzymon Dompke { 622dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "MetricType", *metricType); 623dd1c4a9cSSzymon Dompke return false; 624dd1c4a9cSSzymon Dompke } 625dd1c4a9cSSzymon Dompke } 626dd1c4a9cSSzymon Dompke 627dd1c4a9cSSzymon Dompke if (discreteTriggerCondition) 628dd1c4a9cSSzymon Dompke { 629d5736ef2SEd Tanous ctx.discreteCondition = getDiscreteCondition(*discreteTriggerCondition); 630d5736ef2SEd Tanous if (!ctx.discreteCondition) 631dd1c4a9cSSzymon Dompke { 632dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "DiscreteTriggerCondition", 633dd1c4a9cSSzymon Dompke *discreteTriggerCondition); 634dd1c4a9cSSzymon Dompke return false; 635dd1c4a9cSSzymon Dompke } 636dd1c4a9cSSzymon Dompke } 637dd1c4a9cSSzymon Dompke 638dd1c4a9cSSzymon Dompke if (triggerActions) 639dd1c4a9cSSzymon Dompke { 640dd1c4a9cSSzymon Dompke ctx.actions.reserve(triggerActions->size()); 641dd1c4a9cSSzymon Dompke for (const std::string& action : *triggerActions) 642dd1c4a9cSSzymon Dompke { 643dd1c4a9cSSzymon Dompke std::string dbusAction = toDbusTriggerAction(action); 644dd1c4a9cSSzymon Dompke 645dd1c4a9cSSzymon Dompke if (dbusAction.empty()) 646dd1c4a9cSSzymon Dompke { 647dd1c4a9cSSzymon Dompke messages::propertyValueNotInList(res, action, "TriggerActions"); 648dd1c4a9cSSzymon Dompke return false; 649dd1c4a9cSSzymon Dompke } 650dd1c4a9cSSzymon Dompke 651dd1c4a9cSSzymon Dompke ctx.actions.emplace_back(dbusAction); 652dd1c4a9cSSzymon Dompke } 653dd1c4a9cSSzymon Dompke } 654dd1c4a9cSSzymon Dompke if (!parseMetricProperties(res, ctx)) 655dd1c4a9cSSzymon Dompke { 656dd1c4a9cSSzymon Dompke return false; 657dd1c4a9cSSzymon Dompke } 658dd1c4a9cSSzymon Dompke 6592932dcb6SEd Tanous if (!parseTriggerThresholds(res, discreteTriggers, thresholds, ctx)) 660dd1c4a9cSSzymon Dompke { 661dd1c4a9cSSzymon Dompke return false; 662dd1c4a9cSSzymon Dompke } 663dd1c4a9cSSzymon Dompke 6642932dcb6SEd Tanous if (metricReportDefinitions) 665dd1c4a9cSSzymon Dompke { 6662932dcb6SEd Tanous if (!parseLinks(res, *metricReportDefinitions, ctx)) 667dd1c4a9cSSzymon Dompke { 668dd1c4a9cSSzymon Dompke return false; 669dd1c4a9cSSzymon Dompke } 670dd1c4a9cSSzymon Dompke } 671dd1c4a9cSSzymon Dompke return true; 672dd1c4a9cSSzymon Dompke } 673dd1c4a9cSSzymon Dompke 674dd1c4a9cSSzymon Dompke inline void afterCreateTrigger( 675dd1c4a9cSSzymon Dompke const boost::system::error_code& ec, const std::string& dbusPath, 676dd1c4a9cSSzymon Dompke const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 677dd1c4a9cSSzymon Dompke { 678dd1c4a9cSSzymon Dompke if (ec == boost::system::errc::file_exists) 679dd1c4a9cSSzymon Dompke { 680dd1c4a9cSSzymon Dompke messages::resourceAlreadyExists(asyncResp->res, "Trigger", "Id", id); 681dd1c4a9cSSzymon Dompke return; 682dd1c4a9cSSzymon Dompke } 683dd1c4a9cSSzymon Dompke if (ec == boost::system::errc::too_many_files_open) 684dd1c4a9cSSzymon Dompke { 685dd1c4a9cSSzymon Dompke messages::createLimitReachedForResource(asyncResp->res); 686dd1c4a9cSSzymon Dompke return; 687dd1c4a9cSSzymon Dompke } 688dd1c4a9cSSzymon Dompke if (ec) 689dd1c4a9cSSzymon Dompke { 690dd1c4a9cSSzymon Dompke messages::internalError(asyncResp->res); 69162598e31SEd Tanous BMCWEB_LOG_ERROR("respHandler DBus error {}", ec); 692dd1c4a9cSSzymon Dompke return; 693dd1c4a9cSSzymon Dompke } 694dd1c4a9cSSzymon Dompke 695dd1c4a9cSSzymon Dompke const std::optional<std::string>& triggerId = 696dd1c4a9cSSzymon Dompke getTriggerIdFromDbusPath(dbusPath); 697dd1c4a9cSSzymon Dompke if (!triggerId) 698dd1c4a9cSSzymon Dompke { 699dd1c4a9cSSzymon Dompke messages::internalError(asyncResp->res); 70062598e31SEd Tanous BMCWEB_LOG_ERROR("Unknown data returned by " 70162598e31SEd Tanous "AddTrigger DBus method"); 702dd1c4a9cSSzymon Dompke return; 703dd1c4a9cSSzymon Dompke } 704dd1c4a9cSSzymon Dompke 705dd1c4a9cSSzymon Dompke messages::created(asyncResp->res); 706dd1c4a9cSSzymon Dompke boost::urls::url locationUrl = boost::urls::format( 707dd1c4a9cSSzymon Dompke "/redfish/v1/TelemetryService/Triggers/{}", *triggerId); 708dd1c4a9cSSzymon Dompke asyncResp->res.addHeader("Location", locationUrl.buffer()); 709dd1c4a9cSSzymon Dompke } 710dd1c4a9cSSzymon Dompke 711dd1c4a9cSSzymon Dompke inline std::optional<nlohmann::json::array_t> 712dd1c4a9cSSzymon Dompke getTriggerActions(const std::vector<std::string>& dbusActions) 713dd1c4a9cSSzymon Dompke { 714dd1c4a9cSSzymon Dompke nlohmann::json::array_t triggerActions; 715dd1c4a9cSSzymon Dompke for (const std::string& dbusAction : dbusActions) 716dd1c4a9cSSzymon Dompke { 717dd1c4a9cSSzymon Dompke triggers::TriggerActionEnum redfishAction = 718dd1c4a9cSSzymon Dompke toRedfishTriggerAction(dbusAction); 719dd1c4a9cSSzymon Dompke 720dd1c4a9cSSzymon Dompke if (redfishAction == triggers::TriggerActionEnum::Invalid) 721dd1c4a9cSSzymon Dompke { 722dd1c4a9cSSzymon Dompke return std::nullopt; 723dd1c4a9cSSzymon Dompke } 724dd1c4a9cSSzymon Dompke 725dd1c4a9cSSzymon Dompke triggerActions.emplace_back(redfishAction); 726dd1c4a9cSSzymon Dompke } 727dd1c4a9cSSzymon Dompke 728dd1c4a9cSSzymon Dompke return triggerActions; 7291b7e696bSLukasz Kazmierczak } 7301b7e696bSLukasz Kazmierczak 73158c71488SEd Tanous inline std::optional<nlohmann::json::array_t> getDiscreteTriggers( 73258c71488SEd Tanous const std::vector<DiscreteThresholdParams>& discreteParams) 7331b7e696bSLukasz Kazmierczak { 734dd1c4a9cSSzymon Dompke nlohmann::json::array_t triggers; 73558c71488SEd Tanous for (const auto& [name, severity, dwellTime, value] : discreteParams) 7361b7e696bSLukasz Kazmierczak { 7371b7e696bSLukasz Kazmierczak std::optional<std::string> duration = 7381b7e696bSLukasz Kazmierczak time_utils::toDurationStringFromUint(dwellTime); 7391b7e696bSLukasz Kazmierczak 7401b7e696bSLukasz Kazmierczak if (!duration) 7411b7e696bSLukasz Kazmierczak { 7421b7e696bSLukasz Kazmierczak return std::nullopt; 7431b7e696bSLukasz Kazmierczak } 744613dabeaSEd Tanous nlohmann::json::object_t trigger; 745613dabeaSEd Tanous trigger["Name"] = name; 746dd1c4a9cSSzymon Dompke trigger["Severity"] = toRedfishSeverity(severity); 747613dabeaSEd Tanous trigger["DwellTime"] = *duration; 748613dabeaSEd Tanous trigger["Value"] = value; 749ad539545SPatrick Williams triggers.emplace_back(std::move(trigger)); 7501b7e696bSLukasz Kazmierczak } 7511b7e696bSLukasz Kazmierczak 752dd1c4a9cSSzymon Dompke return triggers; 7531b7e696bSLukasz Kazmierczak } 7541b7e696bSLukasz Kazmierczak 75558c71488SEd Tanous inline std::optional<nlohmann::json::object_t> getNumericThresholds( 75658c71488SEd Tanous const std::vector<NumericThresholdParams>& numericParams) 7571b7e696bSLukasz Kazmierczak { 758dd1c4a9cSSzymon Dompke nlohmann::json::object_t thresholds; 7591b7e696bSLukasz Kazmierczak 76058c71488SEd Tanous for (const auto& [type, dwellTime, activation, reading] : numericParams) 7611b7e696bSLukasz Kazmierczak { 7621b7e696bSLukasz Kazmierczak std::optional<std::string> duration = 7631b7e696bSLukasz Kazmierczak time_utils::toDurationStringFromUint(dwellTime); 7641b7e696bSLukasz Kazmierczak 7651b7e696bSLukasz Kazmierczak if (!duration) 7661b7e696bSLukasz Kazmierczak { 7671b7e696bSLukasz Kazmierczak return std::nullopt; 7681b7e696bSLukasz Kazmierczak } 769dd1c4a9cSSzymon Dompke nlohmann::json& threshold = thresholds[toRedfishThresholdName(type)]; 7701476687dSEd Tanous threshold["Reading"] = reading; 771dd1c4a9cSSzymon Dompke threshold["Activation"] = toRedfishActivation(activation); 7721476687dSEd Tanous threshold["DwellTime"] = *duration; 7731b7e696bSLukasz Kazmierczak } 7741b7e696bSLukasz Kazmierczak 775dd1c4a9cSSzymon Dompke return thresholds; 7761b7e696bSLukasz Kazmierczak } 7771b7e696bSLukasz Kazmierczak 7783f215c92SSzymon Dompke inline std::optional<nlohmann::json> getMetricReportDefinitions( 7793f215c92SSzymon Dompke const std::vector<sdbusplus::message::object_path>& reportPaths) 7801b7e696bSLukasz Kazmierczak { 7811b7e696bSLukasz Kazmierczak nlohmann::json reports = nlohmann::json::array(); 7823f215c92SSzymon Dompke 7833f215c92SSzymon Dompke for (const sdbusplus::message::object_path& path : reportPaths) 7841b7e696bSLukasz Kazmierczak { 7853f215c92SSzymon Dompke std::string reportId = path.filename(); 7863f215c92SSzymon Dompke if (reportId.empty()) 7873f215c92SSzymon Dompke { 7883f215c92SSzymon Dompke { 78962598e31SEd Tanous BMCWEB_LOG_ERROR("Property Reports contains invalid value: {}", 79062598e31SEd Tanous path.str); 7913f215c92SSzymon Dompke return std::nullopt; 7923f215c92SSzymon Dompke } 7933f215c92SSzymon Dompke } 7943f215c92SSzymon Dompke 7951476687dSEd Tanous nlohmann::json::object_t report; 796ef4c65b7SEd Tanous report["@odata.id"] = boost::urls::format( 797ef4c65b7SEd Tanous "/redfish/v1/TelemetryService/MetricReportDefinitions/{}", 798ef4c65b7SEd Tanous reportId); 799b2ba3072SPatrick Williams reports.emplace_back(std::move(report)); 8001b7e696bSLukasz Kazmierczak } 8011b7e696bSLukasz Kazmierczak 8023f215c92SSzymon Dompke return {std::move(reports)}; 8031b7e696bSLukasz Kazmierczak } 8041b7e696bSLukasz Kazmierczak 8051b7e696bSLukasz Kazmierczak inline std::vector<std::string> 8061b7e696bSLukasz Kazmierczak getMetricProperties(const TriggerSensorsParams& sensors) 8071b7e696bSLukasz Kazmierczak { 8081b7e696bSLukasz Kazmierczak std::vector<std::string> metricProperties; 8091b7e696bSLukasz Kazmierczak metricProperties.reserve(sensors.size()); 8101b7e696bSLukasz Kazmierczak for (const auto& [_, metadata] : sensors) 8111b7e696bSLukasz Kazmierczak { 8121b7e696bSLukasz Kazmierczak metricProperties.emplace_back(metadata); 8131b7e696bSLukasz Kazmierczak } 8141b7e696bSLukasz Kazmierczak 8151b7e696bSLukasz Kazmierczak return metricProperties; 8161b7e696bSLukasz Kazmierczak } 8171b7e696bSLukasz Kazmierczak 818e3648032SEd Tanous inline bool fillTrigger(nlohmann::json& json, const std::string& id, 819e3648032SEd Tanous const dbus::utility::DBusPropertiesMap& properties) 8201b7e696bSLukasz Kazmierczak { 8211b7e696bSLukasz Kazmierczak const std::string* name = nullptr; 8221b7e696bSLukasz Kazmierczak const bool* discrete = nullptr; 8231b7e696bSLukasz Kazmierczak const TriggerSensorsParams* sensors = nullptr; 8243f215c92SSzymon Dompke const std::vector<sdbusplus::message::object_path>* reports = nullptr; 82589474494SKrzysztof Grobelny const std::vector<std::string>* triggerActions = nullptr; 82658c71488SEd Tanous 82758c71488SEd Tanous const std::vector<DiscreteThresholdParams>* discreteThresholds = nullptr; 82858c71488SEd Tanous const std::vector<NumericThresholdParams>* numericThresholds = nullptr; 8291b7e696bSLukasz Kazmierczak 83089474494SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 83189474494SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), properties, "Name", name, "Discrete", 83289474494SKrzysztof Grobelny discrete, "Sensors", sensors, "Reports", reports, "TriggerActions", 83358c71488SEd Tanous triggerActions, "DiscreteThresholds", discreteThresholds, 83458c71488SEd Tanous "NumericThresholds", numericThresholds); 83589474494SKrzysztof Grobelny 83689474494SKrzysztof Grobelny if (!success) 8371b7e696bSLukasz Kazmierczak { 83889474494SKrzysztof Grobelny return false; 8391b7e696bSLukasz Kazmierczak } 8401b7e696bSLukasz Kazmierczak 84189474494SKrzysztof Grobelny if (triggerActions != nullptr) 84289474494SKrzysztof Grobelny { 843dd1c4a9cSSzymon Dompke std::optional<nlohmann::json::array_t> redfishTriggerActions = 84489474494SKrzysztof Grobelny getTriggerActions(*triggerActions); 84589474494SKrzysztof Grobelny if (!redfishTriggerActions) 8461b7e696bSLukasz Kazmierczak { 84762598e31SEd Tanous BMCWEB_LOG_ERROR( 84862598e31SEd Tanous "Property TriggerActions is invalid in Trigger: {}", id); 8491b7e696bSLukasz Kazmierczak return false; 8501b7e696bSLukasz Kazmierczak } 851dd1c4a9cSSzymon Dompke json["TriggerActions"] = *redfishTriggerActions; 85289474494SKrzysztof Grobelny } 8531b7e696bSLukasz Kazmierczak 85489474494SKrzysztof Grobelny if (reports != nullptr) 8553f215c92SSzymon Dompke { 8563f215c92SSzymon Dompke std::optional<nlohmann::json> linkedReports = 8573f215c92SSzymon Dompke getMetricReportDefinitions(*reports); 8583f215c92SSzymon Dompke if (!linkedReports) 8593f215c92SSzymon Dompke { 86062598e31SEd Tanous BMCWEB_LOG_ERROR("Property Reports is invalid in Trigger: {}", id); 8613f215c92SSzymon Dompke return false; 8623f215c92SSzymon Dompke } 86389474494SKrzysztof Grobelny json["Links"]["MetricReportDefinitions"] = *linkedReports; 86489474494SKrzysztof Grobelny } 8651b7e696bSLukasz Kazmierczak 86658c71488SEd Tanous if (discreteThresholds != nullptr) 8671b7e696bSLukasz Kazmierczak { 8683f215c92SSzymon Dompke std::optional<nlohmann::json::array_t> discreteTriggers = 86958c71488SEd Tanous getDiscreteTriggers(*discreteThresholds); 8701b7e696bSLukasz Kazmierczak 8711b7e696bSLukasz Kazmierczak if (!discreteTriggers) 8721b7e696bSLukasz Kazmierczak { 87362598e31SEd Tanous BMCWEB_LOG_ERROR("Property Thresholds is invalid for discrete " 87462598e31SEd Tanous "triggers in Trigger: {}", 87562598e31SEd Tanous id); 8761b7e696bSLukasz Kazmierczak return false; 8771b7e696bSLukasz Kazmierczak } 8781b7e696bSLukasz Kazmierczak 8791b7e696bSLukasz Kazmierczak json["DiscreteTriggers"] = *discreteTriggers; 8801b7e696bSLukasz Kazmierczak json["DiscreteTriggerCondition"] = 8811b7e696bSLukasz Kazmierczak discreteTriggers->empty() ? "Changed" : "Specified"; 882539d8c6bSEd Tanous json["MetricType"] = metric_definition::MetricType::Discrete; 8831b7e696bSLukasz Kazmierczak } 88458c71488SEd Tanous if (numericThresholds != nullptr) 8851b7e696bSLukasz Kazmierczak { 88658c71488SEd Tanous std::optional<nlohmann::json::object_t> jnumericThresholds = 88758c71488SEd Tanous getNumericThresholds(*numericThresholds); 8881b7e696bSLukasz Kazmierczak 88958c71488SEd Tanous if (!jnumericThresholds) 8901b7e696bSLukasz Kazmierczak { 89162598e31SEd Tanous BMCWEB_LOG_ERROR("Property Thresholds is invalid for numeric " 89262598e31SEd Tanous "thresholds in Trigger: {}", 89362598e31SEd Tanous id); 8941b7e696bSLukasz Kazmierczak return false; 8951b7e696bSLukasz Kazmierczak } 8961b7e696bSLukasz Kazmierczak 89758c71488SEd Tanous json["NumericThresholds"] = *jnumericThresholds; 898539d8c6bSEd Tanous json["MetricType"] = metric_definition::MetricType::Numeric; 8991b7e696bSLukasz Kazmierczak } 90089474494SKrzysztof Grobelny 90189474494SKrzysztof Grobelny if (name != nullptr) 90289474494SKrzysztof Grobelny { 90389474494SKrzysztof Grobelny json["Name"] = *name; 90489474494SKrzysztof Grobelny } 90589474494SKrzysztof Grobelny 90689474494SKrzysztof Grobelny if (sensors != nullptr) 90789474494SKrzysztof Grobelny { 90889474494SKrzysztof Grobelny json["MetricProperties"] = getMetricProperties(*sensors); 90989474494SKrzysztof Grobelny } 9101b7e696bSLukasz Kazmierczak 9113f215c92SSzymon Dompke json["@odata.type"] = "#Triggers.v1_2_0.Triggers"; 912ef4c65b7SEd Tanous json["@odata.id"] = 913ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/TelemetryService/Triggers/{}", id); 9143f215c92SSzymon Dompke json["Id"] = id; 9151b7e696bSLukasz Kazmierczak 9161b7e696bSLukasz Kazmierczak return true; 9171b7e696bSLukasz Kazmierczak } 9181b7e696bSLukasz Kazmierczak 919dd1c4a9cSSzymon Dompke inline void handleTriggerCollectionPost( 920dd1c4a9cSSzymon Dompke App& app, const crow::Request& req, 921dd1c4a9cSSzymon Dompke const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 922dd1c4a9cSSzymon Dompke { 923dd1c4a9cSSzymon Dompke if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 924dd1c4a9cSSzymon Dompke { 925dd1c4a9cSSzymon Dompke return; 926dd1c4a9cSSzymon Dompke } 927dd1c4a9cSSzymon Dompke 928dd1c4a9cSSzymon Dompke telemetry::Context ctx; 929dd1c4a9cSSzymon Dompke if (!telemetry::parsePostTriggerParams(asyncResp->res, req, ctx)) 930dd1c4a9cSSzymon Dompke { 931dd1c4a9cSSzymon Dompke return; 932dd1c4a9cSSzymon Dompke } 933dd1c4a9cSSzymon Dompke 934dd1c4a9cSSzymon Dompke crow::connections::systemBus->async_method_call( 935dd1c4a9cSSzymon Dompke [asyncResp, id = ctx.id](const boost::system::error_code& ec, 936dd1c4a9cSSzymon Dompke const std::string& dbusPath) { 937dd1c4a9cSSzymon Dompke afterCreateTrigger(ec, dbusPath, asyncResp, id); 938dd1c4a9cSSzymon Dompke }, 939dd1c4a9cSSzymon Dompke service, "/xyz/openbmc_project/Telemetry/Triggers", 940dd1c4a9cSSzymon Dompke "xyz.openbmc_project.Telemetry.TriggerManager", "AddTrigger", 941dd1c4a9cSSzymon Dompke "TelemetryService/" + ctx.id, ctx.name, ctx.actions, ctx.sensors, 94258c71488SEd Tanous ctx.reports, ctx.numericThresholds, ctx.discreteThresholds); 943dd1c4a9cSSzymon Dompke } 944dd1c4a9cSSzymon Dompke 94507148cf2SLukasz Kazmierczak } // namespace telemetry 94607148cf2SLukasz Kazmierczak 94707148cf2SLukasz Kazmierczak inline void requestRoutesTriggerCollection(App& app) 94807148cf2SLukasz Kazmierczak { 94907148cf2SLukasz Kazmierczak BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/Triggers/") 95007148cf2SLukasz Kazmierczak .privileges(redfish::privileges::getTriggersCollection) 95107148cf2SLukasz Kazmierczak .methods(boost::beast::http::verb::get)( 95245ca1b86SEd Tanous [&app](const crow::Request& req, 95307148cf2SLukasz Kazmierczak const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 9543ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 95545ca1b86SEd Tanous { 95645ca1b86SEd Tanous return; 95745ca1b86SEd Tanous } 95807148cf2SLukasz Kazmierczak asyncResp->res.jsonValue["@odata.type"] = 95907148cf2SLukasz Kazmierczak "#TriggersCollection.TriggersCollection"; 960ae9031f0SWilly Tu asyncResp->res.jsonValue["@odata.id"] = 961ae9031f0SWilly Tu "/redfish/v1/TelemetryService/Triggers"; 96207148cf2SLukasz Kazmierczak asyncResp->res.jsonValue["Name"] = "Triggers Collection"; 9637a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces{ 9647a1dbc48SGeorge Liu telemetry::triggerInterface}; 96507148cf2SLukasz Kazmierczak collection_util::getCollectionMembers( 966ae9031f0SWilly Tu asyncResp, 967ae9031f0SWilly Tu boost::urls::url("/redfish/v1/TelemetryService/Triggers"), 968ae9031f0SWilly Tu interfaces, 96907148cf2SLukasz Kazmierczak "/xyz/openbmc_project/Telemetry/Triggers/TelemetryService"); 97007148cf2SLukasz Kazmierczak }); 971dd1c4a9cSSzymon Dompke 972dd1c4a9cSSzymon Dompke BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/Triggers/") 973dd1c4a9cSSzymon Dompke .privileges(redfish::privileges::postTriggersCollection) 974dd1c4a9cSSzymon Dompke .methods(boost::beast::http::verb::post)(std::bind_front( 975dd1c4a9cSSzymon Dompke telemetry::handleTriggerCollectionPost, std::ref(app))); 97607148cf2SLukasz Kazmierczak } 97707148cf2SLukasz Kazmierczak 9781b7e696bSLukasz Kazmierczak inline void requestRoutesTrigger(App& app) 9791b7e696bSLukasz Kazmierczak { 9801b7e696bSLukasz Kazmierczak BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/Triggers/<str>/") 9811b7e696bSLukasz Kazmierczak .privileges(redfish::privileges::getTriggers) 9821b7e696bSLukasz Kazmierczak .methods(boost::beast::http::verb::get)( 98345ca1b86SEd Tanous [&app](const crow::Request& req, 9841b7e696bSLukasz Kazmierczak const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9851b7e696bSLukasz Kazmierczak const std::string& id) { 9863ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 98745ca1b86SEd Tanous { 98845ca1b86SEd Tanous return; 98945ca1b86SEd Tanous } 99089474494SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 99189474494SKrzysztof Grobelny *crow::connections::systemBus, telemetry::service, 992bd79bce8SPatrick Williams telemetry::getDbusTriggerPath(id), 993bd79bce8SPatrick Williams telemetry::triggerInterface, 9941b7e696bSLukasz Kazmierczak [asyncResp, 9955e7e2dc5SEd Tanous id](const boost::system::error_code& ec, 996e3648032SEd Tanous const dbus::utility::DBusPropertiesMap& ret) { 9971b7e696bSLukasz Kazmierczak if (ec.value() == EBADR || 9981b7e696bSLukasz Kazmierczak ec == boost::system::errc::host_unreachable) 9991b7e696bSLukasz Kazmierczak { 1000bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, 1001bd79bce8SPatrick Williams "Triggers", id); 10021b7e696bSLukasz Kazmierczak return; 10031b7e696bSLukasz Kazmierczak } 10041b7e696bSLukasz Kazmierczak if (ec) 10051b7e696bSLukasz Kazmierczak { 100662598e31SEd Tanous BMCWEB_LOG_ERROR("respHandler DBus error {}", ec); 10071b7e696bSLukasz Kazmierczak messages::internalError(asyncResp->res); 10081b7e696bSLukasz Kazmierczak return; 10091b7e696bSLukasz Kazmierczak } 10101b7e696bSLukasz Kazmierczak 1011bd79bce8SPatrick Williams if (!telemetry::fillTrigger(asyncResp->res.jsonValue, 1012bd79bce8SPatrick Williams id, ret)) 10131b7e696bSLukasz Kazmierczak { 10141b7e696bSLukasz Kazmierczak messages::internalError(asyncResp->res); 10151b7e696bSLukasz Kazmierczak } 101689474494SKrzysztof Grobelny }); 10171b7e696bSLukasz Kazmierczak }); 1018163994a8SSzymon Dompke 1019163994a8SSzymon Dompke BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/Triggers/<str>/") 1020163994a8SSzymon Dompke .privileges(redfish::privileges::deleteTriggers) 1021163994a8SSzymon Dompke .methods(boost::beast::http::verb::delete_)( 102245ca1b86SEd Tanous [&app](const crow::Request& req, 1023163994a8SSzymon Dompke const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1024163994a8SSzymon Dompke const std::string& id) { 10253ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 102645ca1b86SEd Tanous { 102745ca1b86SEd Tanous return; 102845ca1b86SEd Tanous } 1029bd79bce8SPatrick Williams const std::string triggerPath = 1030bd79bce8SPatrick Williams telemetry::getDbusTriggerPath(id); 1031163994a8SSzymon Dompke 1032163994a8SSzymon Dompke crow::connections::systemBus->async_method_call( 10335e7e2dc5SEd Tanous [asyncResp, id](const boost::system::error_code& ec) { 1034163994a8SSzymon Dompke if (ec.value() == EBADR) 1035163994a8SSzymon Dompke { 1036bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, 1037bd79bce8SPatrick Williams "Triggers", id); 1038163994a8SSzymon Dompke return; 1039163994a8SSzymon Dompke } 1040163994a8SSzymon Dompke 1041163994a8SSzymon Dompke if (ec) 1042163994a8SSzymon Dompke { 104362598e31SEd Tanous BMCWEB_LOG_ERROR("respHandler DBus error {}", ec); 1044163994a8SSzymon Dompke messages::internalError(asyncResp->res); 1045163994a8SSzymon Dompke return; 1046163994a8SSzymon Dompke } 1047163994a8SSzymon Dompke 1048bd79bce8SPatrick Williams asyncResp->res.result( 1049bd79bce8SPatrick Williams boost::beast::http::status::no_content); 1050163994a8SSzymon Dompke }, 1051163994a8SSzymon Dompke telemetry::service, triggerPath, 1052163994a8SSzymon Dompke "xyz.openbmc_project.Object.Delete", "Delete"); 1053163994a8SSzymon Dompke }); 10541b7e696bSLukasz Kazmierczak } 10551b7e696bSLukasz Kazmierczak 105607148cf2SLukasz Kazmierczak } // namespace redfish 1057