140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 307148cf2SLukasz Kazmierczak #pragma once 407148cf2SLukasz Kazmierczak 53ccb3adbSEd Tanous #include "app.hpp" 6d7857201SEd Tanous #include "async_resp.hpp" 7d7857201SEd Tanous #include "dbus_singleton.hpp" 8d7857201SEd Tanous #include "dbus_utility.hpp" 9d7857201SEd Tanous #include "error_messages.hpp" 10539d8c6bSEd Tanous #include "generated/enums/metric_definition.hpp" 11dd1c4a9cSSzymon Dompke #include "generated/enums/resource.hpp" 12dd1c4a9cSSzymon Dompke #include "generated/enums/triggers.hpp" 13d7857201SEd Tanous #include "http_request.hpp" 14d7857201SEd Tanous #include "http_response.hpp" 15d7857201SEd Tanous #include "logging.hpp" 163ccb3adbSEd Tanous #include "query.hpp" 173ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 18dd1c4a9cSSzymon Dompke #include "utility.hpp" 1907148cf2SLukasz Kazmierczak #include "utils/collection.hpp" 203ccb3adbSEd Tanous #include "utils/dbus_utils.hpp" 215b90429aSEd Tanous #include "utils/json_utils.hpp" 221516c21bSJanet Adkins #include "utils/sensor_utils.hpp" 2307148cf2SLukasz Kazmierczak #include "utils/telemetry_utils.hpp" 243ccb3adbSEd Tanous #include "utils/time_utils.hpp" 2507148cf2SLukasz Kazmierczak 26d7857201SEd Tanous #include <asm-generic/errno.h> 27d7857201SEd Tanous 28d7857201SEd Tanous #include <boost/beast/http/status.hpp> 29d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 30d7857201SEd Tanous #include <boost/system/result.hpp> 31ef4c65b7SEd Tanous #include <boost/url/format.hpp> 32d7857201SEd Tanous #include <boost/url/parse.hpp> 33d7857201SEd Tanous #include <boost/url/url.hpp> 34d7857201SEd Tanous #include <boost/url/url_view.hpp> 35d7857201SEd Tanous #include <nlohmann/json.hpp> 3689474494SKrzysztof Grobelny #include <sdbusplus/asio/property.hpp> 37d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 3889474494SKrzysztof Grobelny #include <sdbusplus/unpack_properties.hpp> 3907148cf2SLukasz Kazmierczak 407a1dbc48SGeorge Liu #include <array> 41d7857201SEd Tanous #include <chrono> 42d7857201SEd Tanous #include <cstddef> 43d7857201SEd Tanous #include <cstdint> 44d7857201SEd Tanous #include <functional> 45d7857201SEd Tanous #include <memory> 46d7857201SEd Tanous #include <optional> 47d7857201SEd Tanous #include <string> 487a1dbc48SGeorge Liu #include <string_view> 491b7e696bSLukasz Kazmierczak #include <tuple> 50d7857201SEd Tanous #include <utility> 511b7e696bSLukasz Kazmierczak #include <vector> 521b7e696bSLukasz Kazmierczak 5307148cf2SLukasz Kazmierczak namespace redfish 5407148cf2SLukasz Kazmierczak { 5507148cf2SLukasz Kazmierczak namespace telemetry 5607148cf2SLukasz Kazmierczak { 5707148cf2SLukasz Kazmierczak constexpr const char* triggerInterface = 5807148cf2SLukasz Kazmierczak "xyz.openbmc_project.Telemetry.Trigger"; 5907148cf2SLukasz Kazmierczak 601b7e696bSLukasz Kazmierczak using NumericThresholdParams = 611b7e696bSLukasz Kazmierczak std::tuple<std::string, uint64_t, std::string, double>; 621b7e696bSLukasz Kazmierczak 631b7e696bSLukasz Kazmierczak using DiscreteThresholdParams = 641b7e696bSLukasz Kazmierczak std::tuple<std::string, std::string, uint64_t, std::string>; 651b7e696bSLukasz Kazmierczak 661b7e696bSLukasz Kazmierczak using TriggerSensorsParams = 671b7e696bSLukasz Kazmierczak std::vector<std::pair<sdbusplus::message::object_path, std::string>>; 681b7e696bSLukasz Kazmierczak 69*504af5a0SPatrick Williams inline triggers::TriggerActionEnum toRedfishTriggerAction( 70*504af5a0SPatrick Williams std::string_view dbusValue) 711b7e696bSLukasz Kazmierczak { 72dd1c4a9cSSzymon Dompke if (dbusValue == 73dd1c4a9cSSzymon Dompke "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.UpdateReport") 741b7e696bSLukasz Kazmierczak { 75dd1c4a9cSSzymon Dompke return triggers::TriggerActionEnum::RedfishMetricReport; 761b7e696bSLukasz Kazmierczak } 77dd1c4a9cSSzymon Dompke if (dbusValue == 78dd1c4a9cSSzymon Dompke "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.LogToRedfishEventLog") 791b7e696bSLukasz Kazmierczak { 80dd1c4a9cSSzymon Dompke return triggers::TriggerActionEnum::RedfishEvent; 811b7e696bSLukasz Kazmierczak } 82dd1c4a9cSSzymon Dompke if (dbusValue == 83dd1c4a9cSSzymon Dompke "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.LogToJournal") 841b7e696bSLukasz Kazmierczak { 85dd1c4a9cSSzymon Dompke return triggers::TriggerActionEnum::LogToLogService; 861b7e696bSLukasz Kazmierczak } 87dd1c4a9cSSzymon Dompke return triggers::TriggerActionEnum::Invalid; 881b7e696bSLukasz Kazmierczak } 891b7e696bSLukasz Kazmierczak 90dd1c4a9cSSzymon Dompke inline std::string toDbusTriggerAction(std::string_view redfishValue) 911b7e696bSLukasz Kazmierczak { 92dd1c4a9cSSzymon Dompke if (redfishValue == "RedfishMetricReport") 931b7e696bSLukasz Kazmierczak { 94dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.UpdateReport"; 95dd1c4a9cSSzymon Dompke } 96dd1c4a9cSSzymon Dompke if (redfishValue == "RedfishEvent") 97dd1c4a9cSSzymon Dompke { 98dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.LogToRedfishEventLog"; 99dd1c4a9cSSzymon Dompke } 100dd1c4a9cSSzymon Dompke if (redfishValue == "LogToLogService") 101dd1c4a9cSSzymon Dompke { 102dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.TriggerAction.LogToJournal"; 103dd1c4a9cSSzymon Dompke } 104dd1c4a9cSSzymon Dompke return ""; 105dd1c4a9cSSzymon Dompke } 1061b7e696bSLukasz Kazmierczak 107dd1c4a9cSSzymon Dompke inline std::string toDbusSeverity(std::string_view redfishValue) 108dd1c4a9cSSzymon Dompke { 109dd1c4a9cSSzymon Dompke if (redfishValue == "OK") 110dd1c4a9cSSzymon Dompke { 111dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.Severity.OK"; 112dd1c4a9cSSzymon Dompke } 113dd1c4a9cSSzymon Dompke if (redfishValue == "Warning") 114dd1c4a9cSSzymon Dompke { 115dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.Severity.Warning"; 116dd1c4a9cSSzymon Dompke } 117dd1c4a9cSSzymon Dompke if (redfishValue == "Critical") 118dd1c4a9cSSzymon Dompke { 119dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.Severity.Critical"; 120dd1c4a9cSSzymon Dompke } 121dd1c4a9cSSzymon Dompke return ""; 122dd1c4a9cSSzymon Dompke } 123dd1c4a9cSSzymon Dompke 124dd1c4a9cSSzymon Dompke inline resource::Health toRedfishSeverity(std::string_view dbusValue) 125dd1c4a9cSSzymon Dompke { 126dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Severity.OK") 127dd1c4a9cSSzymon Dompke { 128dd1c4a9cSSzymon Dompke return resource::Health::OK; 129dd1c4a9cSSzymon Dompke } 130dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Severity.Warning") 131dd1c4a9cSSzymon Dompke { 132dd1c4a9cSSzymon Dompke return resource::Health::Warning; 133dd1c4a9cSSzymon Dompke } 134dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Severity.Critical") 135dd1c4a9cSSzymon Dompke { 136dd1c4a9cSSzymon Dompke return resource::Health::Critical; 137dd1c4a9cSSzymon Dompke } 138dd1c4a9cSSzymon Dompke return resource::Health::Invalid; 139dd1c4a9cSSzymon Dompke } 140dd1c4a9cSSzymon Dompke 141dd1c4a9cSSzymon Dompke inline std::string toRedfishThresholdName(std::string_view dbusValue) 142dd1c4a9cSSzymon Dompke { 143dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Type.UpperCritical") 144dd1c4a9cSSzymon Dompke { 145dd1c4a9cSSzymon Dompke return "UpperCritical"; 146dd1c4a9cSSzymon Dompke } 147dd1c4a9cSSzymon Dompke 148dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Type.LowerCritical") 149dd1c4a9cSSzymon Dompke { 150dd1c4a9cSSzymon Dompke return "LowerCritical"; 151dd1c4a9cSSzymon Dompke } 152dd1c4a9cSSzymon Dompke 153dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Type.UpperWarning") 154dd1c4a9cSSzymon Dompke { 155dd1c4a9cSSzymon Dompke return "UpperWarning"; 156dd1c4a9cSSzymon Dompke } 157dd1c4a9cSSzymon Dompke 158dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Type.LowerWarning") 159dd1c4a9cSSzymon Dompke { 160dd1c4a9cSSzymon Dompke return "LowerWarning"; 161dd1c4a9cSSzymon Dompke } 162dd1c4a9cSSzymon Dompke 163dd1c4a9cSSzymon Dompke return ""; 164dd1c4a9cSSzymon Dompke } 165dd1c4a9cSSzymon Dompke 166dd1c4a9cSSzymon Dompke inline std::string toDbusActivation(std::string_view redfishValue) 167dd1c4a9cSSzymon Dompke { 168dd1c4a9cSSzymon Dompke if (redfishValue == "Either") 169dd1c4a9cSSzymon Dompke { 170dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.Direction.Either"; 171dd1c4a9cSSzymon Dompke } 172dd1c4a9cSSzymon Dompke 173dd1c4a9cSSzymon Dompke if (redfishValue == "Decreasing") 174dd1c4a9cSSzymon Dompke { 175dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.Direction.Decreasing"; 176dd1c4a9cSSzymon Dompke } 177dd1c4a9cSSzymon Dompke 178dd1c4a9cSSzymon Dompke if (redfishValue == "Increasing") 179dd1c4a9cSSzymon Dompke { 180dd1c4a9cSSzymon Dompke return "xyz.openbmc_project.Telemetry.Trigger.Direction.Increasing"; 181dd1c4a9cSSzymon Dompke } 182dd1c4a9cSSzymon Dompke 183dd1c4a9cSSzymon Dompke return ""; 184dd1c4a9cSSzymon Dompke } 185dd1c4a9cSSzymon Dompke 186*504af5a0SPatrick Williams inline triggers::ThresholdActivation toRedfishActivation( 187*504af5a0SPatrick Williams std::string_view dbusValue) 188dd1c4a9cSSzymon Dompke { 189dd1c4a9cSSzymon Dompke if (dbusValue == "xyz.openbmc_project.Telemetry.Trigger.Direction.Either") 190dd1c4a9cSSzymon Dompke { 191dd1c4a9cSSzymon Dompke return triggers::ThresholdActivation::Either; 192dd1c4a9cSSzymon Dompke } 193dd1c4a9cSSzymon Dompke 194dd1c4a9cSSzymon Dompke if (dbusValue == 195dd1c4a9cSSzymon Dompke "xyz.openbmc_project.Telemetry.Trigger.Direction.Decreasing") 196dd1c4a9cSSzymon Dompke { 197dd1c4a9cSSzymon Dompke return triggers::ThresholdActivation::Decreasing; 198dd1c4a9cSSzymon Dompke } 199dd1c4a9cSSzymon Dompke 200dd1c4a9cSSzymon Dompke if (dbusValue == 201dd1c4a9cSSzymon Dompke "xyz.openbmc_project.Telemetry.Trigger.Direction.Increasing") 202dd1c4a9cSSzymon Dompke { 203dd1c4a9cSSzymon Dompke return triggers::ThresholdActivation::Increasing; 204dd1c4a9cSSzymon Dompke } 205dd1c4a9cSSzymon Dompke 206dd1c4a9cSSzymon Dompke return triggers::ThresholdActivation::Invalid; 207dd1c4a9cSSzymon Dompke } 208dd1c4a9cSSzymon Dompke 209dd1c4a9cSSzymon Dompke enum class MetricType 210dd1c4a9cSSzymon Dompke { 211dd1c4a9cSSzymon Dompke Discrete, 212dd1c4a9cSSzymon Dompke Numeric 213dd1c4a9cSSzymon Dompke }; 214dd1c4a9cSSzymon Dompke 215dd1c4a9cSSzymon Dompke enum class DiscreteCondition 216dd1c4a9cSSzymon Dompke { 217dd1c4a9cSSzymon Dompke Specified, 218dd1c4a9cSSzymon Dompke Changed 219dd1c4a9cSSzymon Dompke }; 220dd1c4a9cSSzymon Dompke 221dd1c4a9cSSzymon Dompke struct Context 222dd1c4a9cSSzymon Dompke { 223dd1c4a9cSSzymon Dompke std::string id; 224dd1c4a9cSSzymon Dompke std::string name; 225dd1c4a9cSSzymon Dompke std::vector<std::string> actions; 226dd1c4a9cSSzymon Dompke std::vector<std::pair<sdbusplus::message::object_path, std::string>> 227dd1c4a9cSSzymon Dompke sensors; 228dd1c4a9cSSzymon Dompke std::vector<sdbusplus::message::object_path> reports; 22958c71488SEd Tanous std::vector<NumericThresholdParams> numericThresholds; 23058c71488SEd Tanous std::vector<DiscreteThresholdParams> discreteThresholds; 231dd1c4a9cSSzymon Dompke std::optional<DiscreteCondition> discreteCondition; 232dd1c4a9cSSzymon Dompke std::optional<MetricType> metricType; 233dd1c4a9cSSzymon Dompke std::optional<std::vector<std::string>> metricProperties; 234dd1c4a9cSSzymon Dompke }; 235dd1c4a9cSSzymon Dompke 236dd1c4a9cSSzymon Dompke inline std::optional<sdbusplus::message::object_path> 237dd1c4a9cSSzymon Dompke getReportPathFromReportDefinitionUri(const std::string& uri) 238dd1c4a9cSSzymon Dompke { 2396fd29553SEd Tanous boost::system::result<boost::urls::url_view> parsed = 240dd1c4a9cSSzymon Dompke boost::urls::parse_relative_ref(uri); 241dd1c4a9cSSzymon Dompke 242dd1c4a9cSSzymon Dompke if (!parsed) 2431b7e696bSLukasz Kazmierczak { 2441b7e696bSLukasz Kazmierczak return std::nullopt; 2451b7e696bSLukasz Kazmierczak } 2461b7e696bSLukasz Kazmierczak 247dd1c4a9cSSzymon Dompke std::string id; 248dd1c4a9cSSzymon Dompke if (!crow::utility::readUrlSegments( 249dd1c4a9cSSzymon Dompke *parsed, "redfish", "v1", "TelemetryService", 250dd1c4a9cSSzymon Dompke "MetricReportDefinitions", std::ref(id))) 251dd1c4a9cSSzymon Dompke { 252dd1c4a9cSSzymon Dompke return std::nullopt; 2531b7e696bSLukasz Kazmierczak } 2541b7e696bSLukasz Kazmierczak 255dd1c4a9cSSzymon Dompke return sdbusplus::message::object_path( 256dd1c4a9cSSzymon Dompke "/xyz/openbmc_project/Telemetry/Reports") / 257dd1c4a9cSSzymon Dompke "TelemetryService" / id; 258dd1c4a9cSSzymon Dompke } 259dd1c4a9cSSzymon Dompke 260dd1c4a9cSSzymon Dompke inline std::optional<MetricType> getMetricType(const std::string& metricType) 261dd1c4a9cSSzymon Dompke { 262dd1c4a9cSSzymon Dompke if (metricType == "Discrete") 263dd1c4a9cSSzymon Dompke { 264dd1c4a9cSSzymon Dompke return MetricType::Discrete; 265dd1c4a9cSSzymon Dompke } 266dd1c4a9cSSzymon Dompke if (metricType == "Numeric") 267dd1c4a9cSSzymon Dompke { 268dd1c4a9cSSzymon Dompke return MetricType::Numeric; 269dd1c4a9cSSzymon Dompke } 270dd1c4a9cSSzymon Dompke return std::nullopt; 271dd1c4a9cSSzymon Dompke } 272dd1c4a9cSSzymon Dompke 273*504af5a0SPatrick Williams inline std::optional<DiscreteCondition> getDiscreteCondition( 274*504af5a0SPatrick Williams const std::string& discreteTriggerCondition) 275dd1c4a9cSSzymon Dompke { 276dd1c4a9cSSzymon Dompke if (discreteTriggerCondition == "Specified") 277dd1c4a9cSSzymon Dompke { 278dd1c4a9cSSzymon Dompke return DiscreteCondition::Specified; 279dd1c4a9cSSzymon Dompke } 280dd1c4a9cSSzymon Dompke if (discreteTriggerCondition == "Changed") 281dd1c4a9cSSzymon Dompke { 282dd1c4a9cSSzymon Dompke return DiscreteCondition::Changed; 283dd1c4a9cSSzymon Dompke } 284dd1c4a9cSSzymon Dompke return std::nullopt; 285dd1c4a9cSSzymon Dompke } 286dd1c4a9cSSzymon Dompke 2872932dcb6SEd Tanous inline bool parseThreshold(crow::Response& res, 2882932dcb6SEd Tanous nlohmann::json::object_t& threshold, 2892932dcb6SEd Tanous std::string_view dbusThresholdName, 2902932dcb6SEd Tanous std::vector<NumericThresholdParams>& parsedParams) 291dd1c4a9cSSzymon Dompke { 292dd1c4a9cSSzymon Dompke double reading = 0.0; 293dd1c4a9cSSzymon Dompke std::string activation; 294dd1c4a9cSSzymon Dompke std::string dwellTimeStr; 295dd1c4a9cSSzymon Dompke 296afc474aeSMyung Bae if (!json_util::readJsonObject( // 297afc474aeSMyung Bae threshold, res, // 298afc474aeSMyung Bae "Activation", activation, // 299afc474aeSMyung Bae "DwellTime", dwellTimeStr, // 300afc474aeSMyung Bae "Reading", reading // 301afc474aeSMyung Bae )) 302dd1c4a9cSSzymon Dompke { 303dd1c4a9cSSzymon Dompke return false; 304dd1c4a9cSSzymon Dompke } 305dd1c4a9cSSzymon Dompke 306dd1c4a9cSSzymon Dompke std::string dbusActivation = toDbusActivation(activation); 307dd1c4a9cSSzymon Dompke 308dd1c4a9cSSzymon Dompke if (dbusActivation.empty()) 309dd1c4a9cSSzymon Dompke { 310dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "Activation", activation); 311dd1c4a9cSSzymon Dompke return false; 312dd1c4a9cSSzymon Dompke } 313dd1c4a9cSSzymon Dompke 314dd1c4a9cSSzymon Dompke std::optional<std::chrono::milliseconds> dwellTime = 315dd1c4a9cSSzymon Dompke time_utils::fromDurationString(dwellTimeStr); 316dd1c4a9cSSzymon Dompke if (!dwellTime) 317dd1c4a9cSSzymon Dompke { 318dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "DwellTime", dwellTimeStr); 319dd1c4a9cSSzymon Dompke return false; 320dd1c4a9cSSzymon Dompke } 321dd1c4a9cSSzymon Dompke 322dd1c4a9cSSzymon Dompke parsedParams.emplace_back(dbusThresholdName, 323dd1c4a9cSSzymon Dompke static_cast<uint64_t>(dwellTime->count()), 324dd1c4a9cSSzymon Dompke dbusActivation, reading); 3252932dcb6SEd Tanous return true; 3262932dcb6SEd Tanous } 3272932dcb6SEd Tanous 3282932dcb6SEd Tanous struct NumericThresholds 3292932dcb6SEd Tanous { 3302932dcb6SEd Tanous std::optional<nlohmann::json::object_t> upperCritical; 3312932dcb6SEd Tanous std::optional<nlohmann::json::object_t> upperWarning; 3322932dcb6SEd Tanous std::optional<nlohmann::json::object_t> lowerWarning; 3332932dcb6SEd Tanous std::optional<nlohmann::json::object_t> lowerCritical; 3342932dcb6SEd Tanous 3352932dcb6SEd Tanous bool any() const 3362932dcb6SEd Tanous { 3372932dcb6SEd Tanous return upperCritical || upperWarning || lowerWarning || lowerCritical; 3382932dcb6SEd Tanous } 3392932dcb6SEd Tanous }; 3402932dcb6SEd Tanous 341bd79bce8SPatrick Williams inline bool parseNumericThresholds( 342bd79bce8SPatrick Williams crow::Response& res, NumericThresholds& numericThresholds, Context& ctx) 3432932dcb6SEd Tanous { 3442932dcb6SEd Tanous std::vector<NumericThresholdParams> parsedParams; 3452932dcb6SEd Tanous if (numericThresholds.upperCritical) 3462932dcb6SEd Tanous { 3472932dcb6SEd Tanous if (!parseThreshold( 3482932dcb6SEd Tanous res, *numericThresholds.upperCritical, 3492932dcb6SEd Tanous "xyz.openbmc_project.Telemetry.Trigger.Type.UpperCritical", 3502932dcb6SEd Tanous parsedParams)) 3512932dcb6SEd Tanous { 3522932dcb6SEd Tanous return false; 3532932dcb6SEd Tanous } 3542932dcb6SEd Tanous } 3552932dcb6SEd Tanous if (numericThresholds.upperWarning) 3562932dcb6SEd Tanous { 3572932dcb6SEd Tanous if (!parseThreshold( 3582932dcb6SEd Tanous res, *numericThresholds.upperWarning, 3592932dcb6SEd Tanous "xyz.openbmc_project.Telemetry.Trigger.Type.UpperWarning", 3602932dcb6SEd Tanous parsedParams)) 3612932dcb6SEd Tanous { 3622932dcb6SEd Tanous return false; 3632932dcb6SEd Tanous } 3642932dcb6SEd Tanous } 3652932dcb6SEd Tanous if (numericThresholds.lowerWarning) 3662932dcb6SEd Tanous { 3672932dcb6SEd Tanous if (!parseThreshold( 3682932dcb6SEd Tanous res, *numericThresholds.lowerWarning, 3692932dcb6SEd Tanous "xyz.openbmc_project.Telemetry.Trigger.Type.LowerWarning", 3702932dcb6SEd Tanous parsedParams)) 3712932dcb6SEd Tanous { 3722932dcb6SEd Tanous return false; 3732932dcb6SEd Tanous } 3742932dcb6SEd Tanous } 3752932dcb6SEd Tanous if (numericThresholds.lowerCritical) 3762932dcb6SEd Tanous { 3772932dcb6SEd Tanous if (!parseThreshold( 3782932dcb6SEd Tanous res, *numericThresholds.lowerCritical, 3792932dcb6SEd Tanous "xyz.openbmc_project.Telemetry.Trigger.Type.LowerCritical", 3802932dcb6SEd Tanous parsedParams)) 3812932dcb6SEd Tanous { 3822932dcb6SEd Tanous return false; 3832932dcb6SEd Tanous } 384dd1c4a9cSSzymon Dompke } 385dd1c4a9cSSzymon Dompke 38658c71488SEd Tanous ctx.numericThresholds = std::move(parsedParams); 387dd1c4a9cSSzymon Dompke return true; 388dd1c4a9cSSzymon Dompke } 389dd1c4a9cSSzymon Dompke 390dd1c4a9cSSzymon Dompke inline bool parseDiscreteTriggers( 391dd1c4a9cSSzymon Dompke crow::Response& res, 3922932dcb6SEd Tanous std::optional<std::vector<nlohmann::json::object_t>>& discreteTriggers, 3932932dcb6SEd Tanous Context& ctx) 394dd1c4a9cSSzymon Dompke { 395dd1c4a9cSSzymon Dompke std::vector<DiscreteThresholdParams> parsedParams; 396dd1c4a9cSSzymon Dompke if (!discreteTriggers) 397dd1c4a9cSSzymon Dompke { 39858c71488SEd Tanous ctx.discreteThresholds = std::move(parsedParams); 399dd1c4a9cSSzymon Dompke return true; 400dd1c4a9cSSzymon Dompke } 401dd1c4a9cSSzymon Dompke 402dd1c4a9cSSzymon Dompke parsedParams.reserve(discreteTriggers->size()); 4032932dcb6SEd Tanous for (nlohmann::json::object_t& thresholdInfo : *discreteTriggers) 404dd1c4a9cSSzymon Dompke { 405dd1c4a9cSSzymon Dompke std::optional<std::string> name = ""; 406dd1c4a9cSSzymon Dompke std::string value; 407dd1c4a9cSSzymon Dompke std::string dwellTimeStr; 408dd1c4a9cSSzymon Dompke std::string severity; 409dd1c4a9cSSzymon Dompke 410afc474aeSMyung Bae if (!json_util::readJsonObject( // 411afc474aeSMyung Bae thresholdInfo, res, // 412afc474aeSMyung Bae "DwellTime", dwellTimeStr, // 413afc474aeSMyung Bae "Name", name, // 414afc474aeSMyung Bae "Severity", severity, // 415afc474aeSMyung Bae "Value", value // 416afc474aeSMyung Bae )) 417dd1c4a9cSSzymon Dompke { 418dd1c4a9cSSzymon Dompke return false; 419dd1c4a9cSSzymon Dompke } 420dd1c4a9cSSzymon Dompke 421dd1c4a9cSSzymon Dompke std::optional<std::chrono::milliseconds> dwellTime = 422dd1c4a9cSSzymon Dompke time_utils::fromDurationString(dwellTimeStr); 423dd1c4a9cSSzymon Dompke if (!dwellTime) 424dd1c4a9cSSzymon Dompke { 425dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "DwellTime", dwellTimeStr); 426dd1c4a9cSSzymon Dompke return false; 427dd1c4a9cSSzymon Dompke } 428dd1c4a9cSSzymon Dompke 429dd1c4a9cSSzymon Dompke std::string dbusSeverity = toDbusSeverity(severity); 430dd1c4a9cSSzymon Dompke if (dbusSeverity.empty()) 431dd1c4a9cSSzymon Dompke { 432dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "Severity", severity); 433dd1c4a9cSSzymon Dompke return false; 434dd1c4a9cSSzymon Dompke } 435dd1c4a9cSSzymon Dompke 436dd1c4a9cSSzymon Dompke parsedParams.emplace_back(*name, dbusSeverity, 437dd1c4a9cSSzymon Dompke static_cast<uint64_t>(dwellTime->count()), 438dd1c4a9cSSzymon Dompke value); 439dd1c4a9cSSzymon Dompke } 440dd1c4a9cSSzymon Dompke 44158c71488SEd Tanous ctx.discreteThresholds = std::move(parsedParams); 442dd1c4a9cSSzymon Dompke return true; 443dd1c4a9cSSzymon Dompke } 444dd1c4a9cSSzymon Dompke 445dd1c4a9cSSzymon Dompke inline bool parseTriggerThresholds( 446dd1c4a9cSSzymon Dompke crow::Response& res, 4472932dcb6SEd Tanous std::optional<std::vector<nlohmann::json::object_t>>& discreteTriggers, 4482932dcb6SEd Tanous NumericThresholds& numericThresholds, Context& ctx) 449dd1c4a9cSSzymon Dompke { 4502932dcb6SEd Tanous if (discreteTriggers && numericThresholds.any()) 451dd1c4a9cSSzymon Dompke { 452dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "DiscreteTriggers", 453dd1c4a9cSSzymon Dompke "NumericThresholds"); 454dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "NumericThresholds", 455dd1c4a9cSSzymon Dompke "DiscreteTriggers"); 456dd1c4a9cSSzymon Dompke return false; 457dd1c4a9cSSzymon Dompke } 458dd1c4a9cSSzymon Dompke 459dd1c4a9cSSzymon Dompke if (ctx.discreteCondition) 460dd1c4a9cSSzymon Dompke { 4612932dcb6SEd Tanous if (numericThresholds.any()) 462dd1c4a9cSSzymon Dompke { 463dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "DiscreteTriggerCondition", 464dd1c4a9cSSzymon Dompke "NumericThresholds"); 465dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "NumericThresholds", 466dd1c4a9cSSzymon Dompke "DiscreteTriggerCondition"); 467dd1c4a9cSSzymon Dompke return false; 468dd1c4a9cSSzymon Dompke } 469dd1c4a9cSSzymon Dompke } 470dd1c4a9cSSzymon Dompke 471dd1c4a9cSSzymon Dompke if (ctx.metricType) 472dd1c4a9cSSzymon Dompke { 4732932dcb6SEd Tanous if (*ctx.metricType == MetricType::Discrete && numericThresholds.any()) 474dd1c4a9cSSzymon Dompke { 475dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "NumericThresholds", 476dd1c4a9cSSzymon Dompke "MetricType"); 477dd1c4a9cSSzymon Dompke return false; 478dd1c4a9cSSzymon Dompke } 479dd1c4a9cSSzymon Dompke if (*ctx.metricType == MetricType::Numeric && discreteTriggers) 480dd1c4a9cSSzymon Dompke { 481dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "DiscreteTriggers", 482dd1c4a9cSSzymon Dompke "MetricType"); 483dd1c4a9cSSzymon Dompke return false; 484dd1c4a9cSSzymon Dompke } 485dd1c4a9cSSzymon Dompke if (*ctx.metricType == MetricType::Numeric && ctx.discreteCondition) 486dd1c4a9cSSzymon Dompke { 487dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "DiscreteTriggers", 488dd1c4a9cSSzymon Dompke "DiscreteTriggerCondition"); 489dd1c4a9cSSzymon Dompke return false; 490dd1c4a9cSSzymon Dompke } 491dd1c4a9cSSzymon Dompke } 492dd1c4a9cSSzymon Dompke 493dd1c4a9cSSzymon Dompke if (discreteTriggers || ctx.discreteCondition || 494dd1c4a9cSSzymon Dompke (ctx.metricType && *ctx.metricType == MetricType::Discrete)) 495dd1c4a9cSSzymon Dompke { 496dd1c4a9cSSzymon Dompke if (ctx.discreteCondition) 497dd1c4a9cSSzymon Dompke { 498dd1c4a9cSSzymon Dompke if (*ctx.discreteCondition == DiscreteCondition::Specified && 499dd1c4a9cSSzymon Dompke !discreteTriggers) 500dd1c4a9cSSzymon Dompke { 501dd1c4a9cSSzymon Dompke messages::createFailedMissingReqProperties(res, 502dd1c4a9cSSzymon Dompke "DiscreteTriggers"); 503dd1c4a9cSSzymon Dompke return false; 504dd1c4a9cSSzymon Dompke } 505dd1c4a9cSSzymon Dompke if (discreteTriggers && 506dd1c4a9cSSzymon Dompke ((*ctx.discreteCondition == DiscreteCondition::Specified && 507dd1c4a9cSSzymon Dompke discreteTriggers->empty()) || 508dd1c4a9cSSzymon Dompke (*ctx.discreteCondition == DiscreteCondition::Changed && 509dd1c4a9cSSzymon Dompke !discreteTriggers->empty()))) 510dd1c4a9cSSzymon Dompke { 511dd1c4a9cSSzymon Dompke messages::propertyValueConflict(res, "DiscreteTriggers", 512dd1c4a9cSSzymon Dompke "DiscreteTriggerCondition"); 513dd1c4a9cSSzymon Dompke return false; 514dd1c4a9cSSzymon Dompke } 515dd1c4a9cSSzymon Dompke } 516dd1c4a9cSSzymon Dompke if (!parseDiscreteTriggers(res, discreteTriggers, ctx)) 517dd1c4a9cSSzymon Dompke { 518dd1c4a9cSSzymon Dompke return false; 519dd1c4a9cSSzymon Dompke } 520dd1c4a9cSSzymon Dompke } 5212932dcb6SEd Tanous else if (numericThresholds.any()) 522dd1c4a9cSSzymon Dompke { 5232932dcb6SEd Tanous if (!parseNumericThresholds(res, numericThresholds, ctx)) 524dd1c4a9cSSzymon Dompke { 525dd1c4a9cSSzymon Dompke return false; 526dd1c4a9cSSzymon Dompke } 527dd1c4a9cSSzymon Dompke } 528dd1c4a9cSSzymon Dompke else 529dd1c4a9cSSzymon Dompke { 530dd1c4a9cSSzymon Dompke messages::createFailedMissingReqProperties( 531dd1c4a9cSSzymon Dompke res, "'DiscreteTriggers', 'NumericThresholds', " 532dd1c4a9cSSzymon Dompke "'DiscreteTriggerCondition' or 'MetricType'"); 533dd1c4a9cSSzymon Dompke return false; 534dd1c4a9cSSzymon Dompke } 535dd1c4a9cSSzymon Dompke return true; 536dd1c4a9cSSzymon Dompke } 537dd1c4a9cSSzymon Dompke 5382932dcb6SEd Tanous inline bool parseLinks(crow::Response& res, 5392932dcb6SEd Tanous const std::vector<std::string>& metricReportDefinitions, 5402932dcb6SEd Tanous Context& ctx) 541dd1c4a9cSSzymon Dompke { 5422932dcb6SEd Tanous ctx.reports.reserve(metricReportDefinitions.size()); 5432932dcb6SEd Tanous for (const std::string& reportDefinionUri : metricReportDefinitions) 544dd1c4a9cSSzymon Dompke { 545dd1c4a9cSSzymon Dompke std::optional<sdbusplus::message::object_path> reportPath = 546dd1c4a9cSSzymon Dompke getReportPathFromReportDefinitionUri(reportDefinionUri); 547dd1c4a9cSSzymon Dompke if (!reportPath) 548dd1c4a9cSSzymon Dompke { 549dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "MetricReportDefinitions", 550dd1c4a9cSSzymon Dompke reportDefinionUri); 551dd1c4a9cSSzymon Dompke return false; 552dd1c4a9cSSzymon Dompke } 553dd1c4a9cSSzymon Dompke ctx.reports.emplace_back(*reportPath); 554dd1c4a9cSSzymon Dompke } 555dd1c4a9cSSzymon Dompke return true; 556dd1c4a9cSSzymon Dompke } 557dd1c4a9cSSzymon Dompke 558dd1c4a9cSSzymon Dompke inline bool parseMetricProperties(crow::Response& res, Context& ctx) 559dd1c4a9cSSzymon Dompke { 560dd1c4a9cSSzymon Dompke if (!ctx.metricProperties) 561dd1c4a9cSSzymon Dompke { 562dd1c4a9cSSzymon Dompke return true; 563dd1c4a9cSSzymon Dompke } 564dd1c4a9cSSzymon Dompke 565dd1c4a9cSSzymon Dompke ctx.sensors.reserve(ctx.metricProperties->size()); 566dd1c4a9cSSzymon Dompke 567dd1c4a9cSSzymon Dompke size_t uriIdx = 0; 568dd1c4a9cSSzymon Dompke for (const std::string& uriStr : *ctx.metricProperties) 569dd1c4a9cSSzymon Dompke { 5704a7fbefdSEd Tanous boost::system::result<boost::urls::url> uri = 571dd1c4a9cSSzymon Dompke boost::urls::parse_relative_ref(uriStr); 572dd1c4a9cSSzymon Dompke if (!uri) 573dd1c4a9cSSzymon Dompke { 574dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect( 575dd1c4a9cSSzymon Dompke res, "MetricProperties/" + std::to_string(uriIdx), uriStr); 576dd1c4a9cSSzymon Dompke return false; 577dd1c4a9cSSzymon Dompke } 578dd1c4a9cSSzymon Dompke std::string chassisName; 579dd1c4a9cSSzymon Dompke std::string sensorName; 580dd1c4a9cSSzymon Dompke if (!crow::utility::readUrlSegments(*uri, "redfish", "v1", "Chassis", 581dd1c4a9cSSzymon Dompke std::ref(chassisName), "Sensors", 582dd1c4a9cSSzymon Dompke std::ref(sensorName))) 583dd1c4a9cSSzymon Dompke { 584dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect( 585dd1c4a9cSSzymon Dompke res, "MetricProperties/" + std::to_string(uriIdx), uriStr); 586dd1c4a9cSSzymon Dompke return false; 587dd1c4a9cSSzymon Dompke } 588dd1c4a9cSSzymon Dompke 589dd1c4a9cSSzymon Dompke std::pair<std::string, std::string> split = 5901516c21bSJanet Adkins redfish::sensor_utils::splitSensorNameAndType(sensorName); 591dd1c4a9cSSzymon Dompke if (split.first.empty() || split.second.empty()) 592dd1c4a9cSSzymon Dompke { 593dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect( 594dd1c4a9cSSzymon Dompke res, "MetricProperties/" + std::to_string(uriIdx), uriStr); 595dd1c4a9cSSzymon Dompke return false; 596dd1c4a9cSSzymon Dompke } 597dd1c4a9cSSzymon Dompke 598bd79bce8SPatrick Williams std::string sensorPath = 599bd79bce8SPatrick Williams "/xyz/openbmc_project/sensors/" + split.first + '/' + split.second; 600dd1c4a9cSSzymon Dompke 601dd1c4a9cSSzymon Dompke ctx.sensors.emplace_back(sensorPath, uriStr); 602dd1c4a9cSSzymon Dompke uriIdx++; 603dd1c4a9cSSzymon Dompke } 604dd1c4a9cSSzymon Dompke return true; 605dd1c4a9cSSzymon Dompke } 606dd1c4a9cSSzymon Dompke 607dd1c4a9cSSzymon Dompke inline bool parsePostTriggerParams(crow::Response& res, 608dd1c4a9cSSzymon Dompke const crow::Request& req, Context& ctx) 609dd1c4a9cSSzymon Dompke { 610dd1c4a9cSSzymon Dompke std::optional<std::string> id = ""; 611dd1c4a9cSSzymon Dompke std::optional<std::string> name = ""; 612dd1c4a9cSSzymon Dompke std::optional<std::string> metricType; 613dd1c4a9cSSzymon Dompke std::optional<std::vector<std::string>> triggerActions; 614dd1c4a9cSSzymon Dompke std::optional<std::string> discreteTriggerCondition; 6152932dcb6SEd Tanous std::optional<std::vector<nlohmann::json::object_t>> discreteTriggers; 6162932dcb6SEd Tanous std::optional<std::vector<std::string>> metricReportDefinitions; 6172932dcb6SEd Tanous NumericThresholds thresholds; 618afc474aeSMyung Bae 619afc474aeSMyung Bae if (!json_util::readJsonPatch( // 620afc474aeSMyung Bae req, res, // 621afc474aeSMyung Bae "Id", id, // 622afc474aeSMyung Bae "DiscreteTriggerCondition", discreteTriggerCondition, // 623afc474aeSMyung Bae "DiscreteTriggers", discreteTriggers, // 624afc474aeSMyung Bae "Links/MetricReportDefinitions", metricReportDefinitions, // 625afc474aeSMyung Bae "MetricProperties", ctx.metricProperties, // 626afc474aeSMyung Bae "MetricType", metricType, // 627afc474aeSMyung Bae "Name", name, // 628afc474aeSMyung Bae "NumericThresholds/LowerCritical", thresholds.lowerCritical, // 629afc474aeSMyung Bae "NumericThresholds/LowerWarning", thresholds.lowerWarning, // 630afc474aeSMyung Bae "NumericThresholds/UpperCritical", thresholds.upperCritical, // 631afc474aeSMyung Bae "NumericThresholds/UpperWarning", thresholds.upperWarning, // 632afc474aeSMyung Bae "TriggerActions", triggerActions // 633afc474aeSMyung Bae )) 634dd1c4a9cSSzymon Dompke { 635dd1c4a9cSSzymon Dompke return false; 636dd1c4a9cSSzymon Dompke } 637dd1c4a9cSSzymon Dompke 638dd1c4a9cSSzymon Dompke ctx.id = *id; 639dd1c4a9cSSzymon Dompke ctx.name = *name; 640dd1c4a9cSSzymon Dompke 641dd1c4a9cSSzymon Dompke if (metricType) 642dd1c4a9cSSzymon Dompke { 643d5736ef2SEd Tanous ctx.metricType = getMetricType(*metricType); 644d5736ef2SEd Tanous if (!ctx.metricType) 645dd1c4a9cSSzymon Dompke { 646dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "MetricType", *metricType); 647dd1c4a9cSSzymon Dompke return false; 648dd1c4a9cSSzymon Dompke } 649dd1c4a9cSSzymon Dompke } 650dd1c4a9cSSzymon Dompke 651dd1c4a9cSSzymon Dompke if (discreteTriggerCondition) 652dd1c4a9cSSzymon Dompke { 653d5736ef2SEd Tanous ctx.discreteCondition = getDiscreteCondition(*discreteTriggerCondition); 654d5736ef2SEd Tanous if (!ctx.discreteCondition) 655dd1c4a9cSSzymon Dompke { 656dd1c4a9cSSzymon Dompke messages::propertyValueIncorrect(res, "DiscreteTriggerCondition", 657dd1c4a9cSSzymon Dompke *discreteTriggerCondition); 658dd1c4a9cSSzymon Dompke return false; 659dd1c4a9cSSzymon Dompke } 660dd1c4a9cSSzymon Dompke } 661dd1c4a9cSSzymon Dompke 662dd1c4a9cSSzymon Dompke if (triggerActions) 663dd1c4a9cSSzymon Dompke { 664dd1c4a9cSSzymon Dompke ctx.actions.reserve(triggerActions->size()); 665dd1c4a9cSSzymon Dompke for (const std::string& action : *triggerActions) 666dd1c4a9cSSzymon Dompke { 667dd1c4a9cSSzymon Dompke std::string dbusAction = toDbusTriggerAction(action); 668dd1c4a9cSSzymon Dompke 669dd1c4a9cSSzymon Dompke if (dbusAction.empty()) 670dd1c4a9cSSzymon Dompke { 671dd1c4a9cSSzymon Dompke messages::propertyValueNotInList(res, action, "TriggerActions"); 672dd1c4a9cSSzymon Dompke return false; 673dd1c4a9cSSzymon Dompke } 674dd1c4a9cSSzymon Dompke 675dd1c4a9cSSzymon Dompke ctx.actions.emplace_back(dbusAction); 676dd1c4a9cSSzymon Dompke } 677dd1c4a9cSSzymon Dompke } 678dd1c4a9cSSzymon Dompke if (!parseMetricProperties(res, ctx)) 679dd1c4a9cSSzymon Dompke { 680dd1c4a9cSSzymon Dompke return false; 681dd1c4a9cSSzymon Dompke } 682dd1c4a9cSSzymon Dompke 6832932dcb6SEd Tanous if (!parseTriggerThresholds(res, discreteTriggers, thresholds, ctx)) 684dd1c4a9cSSzymon Dompke { 685dd1c4a9cSSzymon Dompke return false; 686dd1c4a9cSSzymon Dompke } 687dd1c4a9cSSzymon Dompke 6882932dcb6SEd Tanous if (metricReportDefinitions) 689dd1c4a9cSSzymon Dompke { 6902932dcb6SEd Tanous if (!parseLinks(res, *metricReportDefinitions, ctx)) 691dd1c4a9cSSzymon Dompke { 692dd1c4a9cSSzymon Dompke return false; 693dd1c4a9cSSzymon Dompke } 694dd1c4a9cSSzymon Dompke } 695dd1c4a9cSSzymon Dompke return true; 696dd1c4a9cSSzymon Dompke } 697dd1c4a9cSSzymon Dompke 698dd1c4a9cSSzymon Dompke inline void afterCreateTrigger( 699dd1c4a9cSSzymon Dompke const boost::system::error_code& ec, const std::string& dbusPath, 700dd1c4a9cSSzymon Dompke const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 701dd1c4a9cSSzymon Dompke { 702dd1c4a9cSSzymon Dompke if (ec == boost::system::errc::file_exists) 703dd1c4a9cSSzymon Dompke { 704dd1c4a9cSSzymon Dompke messages::resourceAlreadyExists(asyncResp->res, "Trigger", "Id", id); 705dd1c4a9cSSzymon Dompke return; 706dd1c4a9cSSzymon Dompke } 707dd1c4a9cSSzymon Dompke if (ec == boost::system::errc::too_many_files_open) 708dd1c4a9cSSzymon Dompke { 709dd1c4a9cSSzymon Dompke messages::createLimitReachedForResource(asyncResp->res); 710dd1c4a9cSSzymon Dompke return; 711dd1c4a9cSSzymon Dompke } 712dd1c4a9cSSzymon Dompke if (ec) 713dd1c4a9cSSzymon Dompke { 714dd1c4a9cSSzymon Dompke messages::internalError(asyncResp->res); 71562598e31SEd Tanous BMCWEB_LOG_ERROR("respHandler DBus error {}", ec); 716dd1c4a9cSSzymon Dompke return; 717dd1c4a9cSSzymon Dompke } 718dd1c4a9cSSzymon Dompke 719dd1c4a9cSSzymon Dompke const std::optional<std::string>& triggerId = 720dd1c4a9cSSzymon Dompke getTriggerIdFromDbusPath(dbusPath); 721dd1c4a9cSSzymon Dompke if (!triggerId) 722dd1c4a9cSSzymon Dompke { 723dd1c4a9cSSzymon Dompke messages::internalError(asyncResp->res); 72462598e31SEd Tanous BMCWEB_LOG_ERROR("Unknown data returned by " 72562598e31SEd Tanous "AddTrigger DBus method"); 726dd1c4a9cSSzymon Dompke return; 727dd1c4a9cSSzymon Dompke } 728dd1c4a9cSSzymon Dompke 729dd1c4a9cSSzymon Dompke messages::created(asyncResp->res); 730dd1c4a9cSSzymon Dompke boost::urls::url locationUrl = boost::urls::format( 731dd1c4a9cSSzymon Dompke "/redfish/v1/TelemetryService/Triggers/{}", *triggerId); 732dd1c4a9cSSzymon Dompke asyncResp->res.addHeader("Location", locationUrl.buffer()); 733dd1c4a9cSSzymon Dompke } 734dd1c4a9cSSzymon Dompke 735*504af5a0SPatrick Williams inline std::optional<nlohmann::json::array_t> getTriggerActions( 736*504af5a0SPatrick Williams const std::vector<std::string>& dbusActions) 737dd1c4a9cSSzymon Dompke { 738dd1c4a9cSSzymon Dompke nlohmann::json::array_t triggerActions; 739dd1c4a9cSSzymon Dompke for (const std::string& dbusAction : dbusActions) 740dd1c4a9cSSzymon Dompke { 741dd1c4a9cSSzymon Dompke triggers::TriggerActionEnum redfishAction = 742dd1c4a9cSSzymon Dompke toRedfishTriggerAction(dbusAction); 743dd1c4a9cSSzymon Dompke 744dd1c4a9cSSzymon Dompke if (redfishAction == triggers::TriggerActionEnum::Invalid) 745dd1c4a9cSSzymon Dompke { 746dd1c4a9cSSzymon Dompke return std::nullopt; 747dd1c4a9cSSzymon Dompke } 748dd1c4a9cSSzymon Dompke 749dd1c4a9cSSzymon Dompke triggerActions.emplace_back(redfishAction); 750dd1c4a9cSSzymon Dompke } 751dd1c4a9cSSzymon Dompke 752dd1c4a9cSSzymon Dompke return triggerActions; 7531b7e696bSLukasz Kazmierczak } 7541b7e696bSLukasz Kazmierczak 75558c71488SEd Tanous inline std::optional<nlohmann::json::array_t> getDiscreteTriggers( 75658c71488SEd Tanous const std::vector<DiscreteThresholdParams>& discreteParams) 7571b7e696bSLukasz Kazmierczak { 758dd1c4a9cSSzymon Dompke nlohmann::json::array_t triggers; 75958c71488SEd Tanous for (const auto& [name, severity, dwellTime, value] : discreteParams) 7601b7e696bSLukasz Kazmierczak { 7611b7e696bSLukasz Kazmierczak std::optional<std::string> duration = 7621b7e696bSLukasz Kazmierczak time_utils::toDurationStringFromUint(dwellTime); 7631b7e696bSLukasz Kazmierczak 7641b7e696bSLukasz Kazmierczak if (!duration) 7651b7e696bSLukasz Kazmierczak { 7661b7e696bSLukasz Kazmierczak return std::nullopt; 7671b7e696bSLukasz Kazmierczak } 768613dabeaSEd Tanous nlohmann::json::object_t trigger; 769613dabeaSEd Tanous trigger["Name"] = name; 770dd1c4a9cSSzymon Dompke trigger["Severity"] = toRedfishSeverity(severity); 771613dabeaSEd Tanous trigger["DwellTime"] = *duration; 772613dabeaSEd Tanous trigger["Value"] = value; 773ad539545SPatrick Williams triggers.emplace_back(std::move(trigger)); 7741b7e696bSLukasz Kazmierczak } 7751b7e696bSLukasz Kazmierczak 776dd1c4a9cSSzymon Dompke return triggers; 7771b7e696bSLukasz Kazmierczak } 7781b7e696bSLukasz Kazmierczak 77958c71488SEd Tanous inline std::optional<nlohmann::json::object_t> getNumericThresholds( 78058c71488SEd Tanous const std::vector<NumericThresholdParams>& numericParams) 7811b7e696bSLukasz Kazmierczak { 782dd1c4a9cSSzymon Dompke nlohmann::json::object_t thresholds; 7831b7e696bSLukasz Kazmierczak 78458c71488SEd Tanous for (const auto& [type, dwellTime, activation, reading] : numericParams) 7851b7e696bSLukasz Kazmierczak { 7861b7e696bSLukasz Kazmierczak std::optional<std::string> duration = 7871b7e696bSLukasz Kazmierczak time_utils::toDurationStringFromUint(dwellTime); 7881b7e696bSLukasz Kazmierczak 7891b7e696bSLukasz Kazmierczak if (!duration) 7901b7e696bSLukasz Kazmierczak { 7911b7e696bSLukasz Kazmierczak return std::nullopt; 7921b7e696bSLukasz Kazmierczak } 793dd1c4a9cSSzymon Dompke nlohmann::json& threshold = thresholds[toRedfishThresholdName(type)]; 7941476687dSEd Tanous threshold["Reading"] = reading; 795dd1c4a9cSSzymon Dompke threshold["Activation"] = toRedfishActivation(activation); 7961476687dSEd Tanous threshold["DwellTime"] = *duration; 7971b7e696bSLukasz Kazmierczak } 7981b7e696bSLukasz Kazmierczak 799dd1c4a9cSSzymon Dompke return thresholds; 8001b7e696bSLukasz Kazmierczak } 8011b7e696bSLukasz Kazmierczak 8023f215c92SSzymon Dompke inline std::optional<nlohmann::json> getMetricReportDefinitions( 8033f215c92SSzymon Dompke const std::vector<sdbusplus::message::object_path>& reportPaths) 8041b7e696bSLukasz Kazmierczak { 8051b7e696bSLukasz Kazmierczak nlohmann::json reports = nlohmann::json::array(); 8063f215c92SSzymon Dompke 8073f215c92SSzymon Dompke for (const sdbusplus::message::object_path& path : reportPaths) 8081b7e696bSLukasz Kazmierczak { 8093f215c92SSzymon Dompke std::string reportId = path.filename(); 8103f215c92SSzymon Dompke if (reportId.empty()) 8113f215c92SSzymon Dompke { 8123f215c92SSzymon Dompke { 81362598e31SEd Tanous BMCWEB_LOG_ERROR("Property Reports contains invalid value: {}", 81462598e31SEd Tanous path.str); 8153f215c92SSzymon Dompke return std::nullopt; 8163f215c92SSzymon Dompke } 8173f215c92SSzymon Dompke } 8183f215c92SSzymon Dompke 8191476687dSEd Tanous nlohmann::json::object_t report; 820ef4c65b7SEd Tanous report["@odata.id"] = boost::urls::format( 821ef4c65b7SEd Tanous "/redfish/v1/TelemetryService/MetricReportDefinitions/{}", 822ef4c65b7SEd Tanous reportId); 823b2ba3072SPatrick Williams reports.emplace_back(std::move(report)); 8241b7e696bSLukasz Kazmierczak } 8251b7e696bSLukasz Kazmierczak 8263f215c92SSzymon Dompke return {std::move(reports)}; 8271b7e696bSLukasz Kazmierczak } 8281b7e696bSLukasz Kazmierczak 829*504af5a0SPatrick Williams inline std::vector<std::string> getMetricProperties( 830*504af5a0SPatrick Williams const TriggerSensorsParams& sensors) 8311b7e696bSLukasz Kazmierczak { 8321b7e696bSLukasz Kazmierczak std::vector<std::string> metricProperties; 8331b7e696bSLukasz Kazmierczak metricProperties.reserve(sensors.size()); 8341b7e696bSLukasz Kazmierczak for (const auto& [_, metadata] : sensors) 8351b7e696bSLukasz Kazmierczak { 8361b7e696bSLukasz Kazmierczak metricProperties.emplace_back(metadata); 8371b7e696bSLukasz Kazmierczak } 8381b7e696bSLukasz Kazmierczak 8391b7e696bSLukasz Kazmierczak return metricProperties; 8401b7e696bSLukasz Kazmierczak } 8411b7e696bSLukasz Kazmierczak 842e3648032SEd Tanous inline bool fillTrigger(nlohmann::json& json, const std::string& id, 843e3648032SEd Tanous const dbus::utility::DBusPropertiesMap& properties) 8441b7e696bSLukasz Kazmierczak { 8451b7e696bSLukasz Kazmierczak const std::string* name = nullptr; 8461b7e696bSLukasz Kazmierczak const bool* discrete = nullptr; 8471b7e696bSLukasz Kazmierczak const TriggerSensorsParams* sensors = nullptr; 8483f215c92SSzymon Dompke const std::vector<sdbusplus::message::object_path>* reports = nullptr; 84989474494SKrzysztof Grobelny const std::vector<std::string>* triggerActions = nullptr; 85058c71488SEd Tanous 85158c71488SEd Tanous const std::vector<DiscreteThresholdParams>* discreteThresholds = nullptr; 85258c71488SEd Tanous const std::vector<NumericThresholdParams>* numericThresholds = nullptr; 8531b7e696bSLukasz Kazmierczak 85489474494SKrzysztof Grobelny const bool success = sdbusplus::unpackPropertiesNoThrow( 85589474494SKrzysztof Grobelny dbus_utils::UnpackErrorPrinter(), properties, "Name", name, "Discrete", 85689474494SKrzysztof Grobelny discrete, "Sensors", sensors, "Reports", reports, "TriggerActions", 85758c71488SEd Tanous triggerActions, "DiscreteThresholds", discreteThresholds, 85858c71488SEd Tanous "NumericThresholds", numericThresholds); 85989474494SKrzysztof Grobelny 86089474494SKrzysztof Grobelny if (!success) 8611b7e696bSLukasz Kazmierczak { 86289474494SKrzysztof Grobelny return false; 8631b7e696bSLukasz Kazmierczak } 8641b7e696bSLukasz Kazmierczak 86589474494SKrzysztof Grobelny if (triggerActions != nullptr) 86689474494SKrzysztof Grobelny { 867dd1c4a9cSSzymon Dompke std::optional<nlohmann::json::array_t> redfishTriggerActions = 86889474494SKrzysztof Grobelny getTriggerActions(*triggerActions); 86989474494SKrzysztof Grobelny if (!redfishTriggerActions) 8701b7e696bSLukasz Kazmierczak { 87162598e31SEd Tanous BMCWEB_LOG_ERROR( 87262598e31SEd Tanous "Property TriggerActions is invalid in Trigger: {}", id); 8731b7e696bSLukasz Kazmierczak return false; 8741b7e696bSLukasz Kazmierczak } 875dd1c4a9cSSzymon Dompke json["TriggerActions"] = *redfishTriggerActions; 87689474494SKrzysztof Grobelny } 8771b7e696bSLukasz Kazmierczak 87889474494SKrzysztof Grobelny if (reports != nullptr) 8793f215c92SSzymon Dompke { 8803f215c92SSzymon Dompke std::optional<nlohmann::json> linkedReports = 8813f215c92SSzymon Dompke getMetricReportDefinitions(*reports); 8823f215c92SSzymon Dompke if (!linkedReports) 8833f215c92SSzymon Dompke { 88462598e31SEd Tanous BMCWEB_LOG_ERROR("Property Reports is invalid in Trigger: {}", id); 8853f215c92SSzymon Dompke return false; 8863f215c92SSzymon Dompke } 88789474494SKrzysztof Grobelny json["Links"]["MetricReportDefinitions"] = *linkedReports; 88889474494SKrzysztof Grobelny } 8891b7e696bSLukasz Kazmierczak 89058c71488SEd Tanous if (discreteThresholds != nullptr) 8911b7e696bSLukasz Kazmierczak { 8923f215c92SSzymon Dompke std::optional<nlohmann::json::array_t> discreteTriggers = 89358c71488SEd Tanous getDiscreteTriggers(*discreteThresholds); 8941b7e696bSLukasz Kazmierczak 8951b7e696bSLukasz Kazmierczak if (!discreteTriggers) 8961b7e696bSLukasz Kazmierczak { 89762598e31SEd Tanous BMCWEB_LOG_ERROR("Property Thresholds is invalid for discrete " 89862598e31SEd Tanous "triggers in Trigger: {}", 89962598e31SEd Tanous id); 9001b7e696bSLukasz Kazmierczak return false; 9011b7e696bSLukasz Kazmierczak } 9021b7e696bSLukasz Kazmierczak 9031b7e696bSLukasz Kazmierczak json["DiscreteTriggers"] = *discreteTriggers; 9041b7e696bSLukasz Kazmierczak json["DiscreteTriggerCondition"] = 9051b7e696bSLukasz Kazmierczak discreteTriggers->empty() ? "Changed" : "Specified"; 906539d8c6bSEd Tanous json["MetricType"] = metric_definition::MetricType::Discrete; 9071b7e696bSLukasz Kazmierczak } 90858c71488SEd Tanous if (numericThresholds != nullptr) 9091b7e696bSLukasz Kazmierczak { 91058c71488SEd Tanous std::optional<nlohmann::json::object_t> jnumericThresholds = 91158c71488SEd Tanous getNumericThresholds(*numericThresholds); 9121b7e696bSLukasz Kazmierczak 91358c71488SEd Tanous if (!jnumericThresholds) 9141b7e696bSLukasz Kazmierczak { 91562598e31SEd Tanous BMCWEB_LOG_ERROR("Property Thresholds is invalid for numeric " 91662598e31SEd Tanous "thresholds in Trigger: {}", 91762598e31SEd Tanous id); 9181b7e696bSLukasz Kazmierczak return false; 9191b7e696bSLukasz Kazmierczak } 9201b7e696bSLukasz Kazmierczak 92158c71488SEd Tanous json["NumericThresholds"] = *jnumericThresholds; 922539d8c6bSEd Tanous json["MetricType"] = metric_definition::MetricType::Numeric; 9231b7e696bSLukasz Kazmierczak } 92489474494SKrzysztof Grobelny 92589474494SKrzysztof Grobelny if (name != nullptr) 92689474494SKrzysztof Grobelny { 92789474494SKrzysztof Grobelny json["Name"] = *name; 92889474494SKrzysztof Grobelny } 92989474494SKrzysztof Grobelny 93089474494SKrzysztof Grobelny if (sensors != nullptr) 93189474494SKrzysztof Grobelny { 93289474494SKrzysztof Grobelny json["MetricProperties"] = getMetricProperties(*sensors); 93389474494SKrzysztof Grobelny } 9341b7e696bSLukasz Kazmierczak 9353f215c92SSzymon Dompke json["@odata.type"] = "#Triggers.v1_2_0.Triggers"; 936ef4c65b7SEd Tanous json["@odata.id"] = 937ef4c65b7SEd Tanous boost::urls::format("/redfish/v1/TelemetryService/Triggers/{}", id); 9383f215c92SSzymon Dompke json["Id"] = id; 9391b7e696bSLukasz Kazmierczak 9401b7e696bSLukasz Kazmierczak return true; 9411b7e696bSLukasz Kazmierczak } 9421b7e696bSLukasz Kazmierczak 943dd1c4a9cSSzymon Dompke inline void handleTriggerCollectionPost( 944dd1c4a9cSSzymon Dompke App& app, const crow::Request& req, 945dd1c4a9cSSzymon Dompke const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 946dd1c4a9cSSzymon Dompke { 947dd1c4a9cSSzymon Dompke if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 948dd1c4a9cSSzymon Dompke { 949dd1c4a9cSSzymon Dompke return; 950dd1c4a9cSSzymon Dompke } 951dd1c4a9cSSzymon Dompke 952dd1c4a9cSSzymon Dompke telemetry::Context ctx; 953dd1c4a9cSSzymon Dompke if (!telemetry::parsePostTriggerParams(asyncResp->res, req, ctx)) 954dd1c4a9cSSzymon Dompke { 955dd1c4a9cSSzymon Dompke return; 956dd1c4a9cSSzymon Dompke } 957dd1c4a9cSSzymon Dompke 958dd1c4a9cSSzymon Dompke crow::connections::systemBus->async_method_call( 959dd1c4a9cSSzymon Dompke [asyncResp, id = ctx.id](const boost::system::error_code& ec, 960dd1c4a9cSSzymon Dompke const std::string& dbusPath) { 961dd1c4a9cSSzymon Dompke afterCreateTrigger(ec, dbusPath, asyncResp, id); 962dd1c4a9cSSzymon Dompke }, 963dd1c4a9cSSzymon Dompke service, "/xyz/openbmc_project/Telemetry/Triggers", 964dd1c4a9cSSzymon Dompke "xyz.openbmc_project.Telemetry.TriggerManager", "AddTrigger", 965dd1c4a9cSSzymon Dompke "TelemetryService/" + ctx.id, ctx.name, ctx.actions, ctx.sensors, 96658c71488SEd Tanous ctx.reports, ctx.numericThresholds, ctx.discreteThresholds); 967dd1c4a9cSSzymon Dompke } 968dd1c4a9cSSzymon Dompke 96907148cf2SLukasz Kazmierczak } // namespace telemetry 97007148cf2SLukasz Kazmierczak 97107148cf2SLukasz Kazmierczak inline void requestRoutesTriggerCollection(App& app) 97207148cf2SLukasz Kazmierczak { 97307148cf2SLukasz Kazmierczak BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/Triggers/") 97407148cf2SLukasz Kazmierczak .privileges(redfish::privileges::getTriggersCollection) 97507148cf2SLukasz Kazmierczak .methods(boost::beast::http::verb::get)( 97645ca1b86SEd Tanous [&app](const crow::Request& req, 97707148cf2SLukasz Kazmierczak const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 9783ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 97945ca1b86SEd Tanous { 98045ca1b86SEd Tanous return; 98145ca1b86SEd Tanous } 98207148cf2SLukasz Kazmierczak asyncResp->res.jsonValue["@odata.type"] = 98307148cf2SLukasz Kazmierczak "#TriggersCollection.TriggersCollection"; 984ae9031f0SWilly Tu asyncResp->res.jsonValue["@odata.id"] = 985ae9031f0SWilly Tu "/redfish/v1/TelemetryService/Triggers"; 98607148cf2SLukasz Kazmierczak asyncResp->res.jsonValue["Name"] = "Triggers Collection"; 9877a1dbc48SGeorge Liu constexpr std::array<std::string_view, 1> interfaces{ 9887a1dbc48SGeorge Liu telemetry::triggerInterface}; 98907148cf2SLukasz Kazmierczak collection_util::getCollectionMembers( 990ae9031f0SWilly Tu asyncResp, 991ae9031f0SWilly Tu boost::urls::url("/redfish/v1/TelemetryService/Triggers"), 992ae9031f0SWilly Tu interfaces, 99307148cf2SLukasz Kazmierczak "/xyz/openbmc_project/Telemetry/Triggers/TelemetryService"); 99407148cf2SLukasz Kazmierczak }); 995dd1c4a9cSSzymon Dompke 996dd1c4a9cSSzymon Dompke BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/Triggers/") 997dd1c4a9cSSzymon Dompke .privileges(redfish::privileges::postTriggersCollection) 998dd1c4a9cSSzymon Dompke .methods(boost::beast::http::verb::post)(std::bind_front( 999dd1c4a9cSSzymon Dompke telemetry::handleTriggerCollectionPost, std::ref(app))); 100007148cf2SLukasz Kazmierczak } 100107148cf2SLukasz Kazmierczak 10021b7e696bSLukasz Kazmierczak inline void requestRoutesTrigger(App& app) 10031b7e696bSLukasz Kazmierczak { 10041b7e696bSLukasz Kazmierczak BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/Triggers/<str>/") 10051b7e696bSLukasz Kazmierczak .privileges(redfish::privileges::getTriggers) 10061b7e696bSLukasz Kazmierczak .methods(boost::beast::http::verb::get)( 100745ca1b86SEd Tanous [&app](const crow::Request& req, 10081b7e696bSLukasz Kazmierczak const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 10091b7e696bSLukasz Kazmierczak const std::string& id) { 10103ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 101145ca1b86SEd Tanous { 101245ca1b86SEd Tanous return; 101345ca1b86SEd Tanous } 101489474494SKrzysztof Grobelny sdbusplus::asio::getAllProperties( 101589474494SKrzysztof Grobelny *crow::connections::systemBus, telemetry::service, 1016bd79bce8SPatrick Williams telemetry::getDbusTriggerPath(id), 1017bd79bce8SPatrick Williams telemetry::triggerInterface, 10181b7e696bSLukasz Kazmierczak [asyncResp, 10195e7e2dc5SEd Tanous id](const boost::system::error_code& ec, 1020e3648032SEd Tanous const dbus::utility::DBusPropertiesMap& ret) { 10211b7e696bSLukasz Kazmierczak if (ec.value() == EBADR || 10221b7e696bSLukasz Kazmierczak ec == boost::system::errc::host_unreachable) 10231b7e696bSLukasz Kazmierczak { 1024bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, 1025bd79bce8SPatrick Williams "Triggers", id); 10261b7e696bSLukasz Kazmierczak return; 10271b7e696bSLukasz Kazmierczak } 10281b7e696bSLukasz Kazmierczak if (ec) 10291b7e696bSLukasz Kazmierczak { 103062598e31SEd Tanous BMCWEB_LOG_ERROR("respHandler DBus error {}", ec); 10311b7e696bSLukasz Kazmierczak messages::internalError(asyncResp->res); 10321b7e696bSLukasz Kazmierczak return; 10331b7e696bSLukasz Kazmierczak } 10341b7e696bSLukasz Kazmierczak 1035bd79bce8SPatrick Williams if (!telemetry::fillTrigger(asyncResp->res.jsonValue, 1036bd79bce8SPatrick Williams id, ret)) 10371b7e696bSLukasz Kazmierczak { 10381b7e696bSLukasz Kazmierczak messages::internalError(asyncResp->res); 10391b7e696bSLukasz Kazmierczak } 104089474494SKrzysztof Grobelny }); 10411b7e696bSLukasz Kazmierczak }); 1042163994a8SSzymon Dompke 1043163994a8SSzymon Dompke BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/Triggers/<str>/") 1044163994a8SSzymon Dompke .privileges(redfish::privileges::deleteTriggers) 1045163994a8SSzymon Dompke .methods(boost::beast::http::verb::delete_)( 104645ca1b86SEd Tanous [&app](const crow::Request& req, 1047163994a8SSzymon Dompke const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1048163994a8SSzymon Dompke const std::string& id) { 10493ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 105045ca1b86SEd Tanous { 105145ca1b86SEd Tanous return; 105245ca1b86SEd Tanous } 1053bd79bce8SPatrick Williams const std::string triggerPath = 1054bd79bce8SPatrick Williams telemetry::getDbusTriggerPath(id); 1055163994a8SSzymon Dompke 1056163994a8SSzymon Dompke crow::connections::systemBus->async_method_call( 10575e7e2dc5SEd Tanous [asyncResp, id](const boost::system::error_code& ec) { 1058163994a8SSzymon Dompke if (ec.value() == EBADR) 1059163994a8SSzymon Dompke { 1060bd79bce8SPatrick Williams messages::resourceNotFound(asyncResp->res, 1061bd79bce8SPatrick Williams "Triggers", id); 1062163994a8SSzymon Dompke return; 1063163994a8SSzymon Dompke } 1064163994a8SSzymon Dompke 1065163994a8SSzymon Dompke if (ec) 1066163994a8SSzymon Dompke { 106762598e31SEd Tanous BMCWEB_LOG_ERROR("respHandler DBus error {}", ec); 1068163994a8SSzymon Dompke messages::internalError(asyncResp->res); 1069163994a8SSzymon Dompke return; 1070163994a8SSzymon Dompke } 1071163994a8SSzymon Dompke 1072bd79bce8SPatrick Williams asyncResp->res.result( 1073bd79bce8SPatrick Williams boost::beast::http::status::no_content); 1074163994a8SSzymon Dompke }, 1075163994a8SSzymon Dompke telemetry::service, triggerPath, 1076163994a8SSzymon Dompke "xyz.openbmc_project.Object.Delete", "Delete"); 1077163994a8SSzymon Dompke }); 10781b7e696bSLukasz Kazmierczak } 10791b7e696bSLukasz Kazmierczak 108007148cf2SLukasz Kazmierczak } // namespace redfish 1081