From 18f97faa411078b95d042d207f5fff32bc8ece1d Mon Sep 17 00:00:00 2001 From: P Dheeraj Srujan Kumar Date: Thu, 31 Mar 2022 02:50:48 +0530 Subject: Update to internal 1-0.91 Signed-off-by: P Dheeraj Srujan Kumar --- ...1-Add-support-for-MetricDefinition-scheme.patch | 619 -------------- ...dd-support-for-POST-on-TriggersCollection.patch | 889 +++++++++++++++++++++ ...1-Sync-Telmetry-service-with-EventService.patch | 284 +++++++ ...t-Remove-LogService-from-TelemetryService.patch | 26 + ...2-Sync-Telmetry-service-with-EventService.patch | 295 ------- ...d-bmcweb-to-use-new-telemetry-service-API.patch | 513 ++++++++---- ...MetricDefinition-property-in-MetricReport.patch | 268 ------- ...0005-Add-GET-method-for-TriggerCollection.patch | 313 -------- ...t-Remove-LogService-from-TelemetryService.patch | 26 - ...rvice-fix-added-Context-field-to-response.patch | 29 - ...ort-for-deleting-terminated-subscriptions.patch | 46 -- .../interfaces/bmcweb/telemetry/README | 28 +- 12 files changed, 1550 insertions(+), 1786 deletions(-) delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-POST-on-TriggersCollection.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Sync-Telmetry-service-with-EventService.patch create mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Revert-Remove-LogService-from-TelemetryService.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-MetricDefinition-property-in-MetricReport.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-GET-method-for-TriggerCollection.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Revert-Remove-LogService-from-TelemetryService.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0007-event-service-fix-added-Context-field-to-response.patch delete mode 100644 meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0009-Add-support-for-deleting-terminated-subscriptions.patch (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry') diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch deleted file mode 100644 index f5226fe6e..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch +++ /dev/null @@ -1,619 +0,0 @@ -From 32e557279450226ed9c06312649d90b802f3d4c5 Mon Sep 17 00:00:00 2001 -From: Krzysztof Grobelny -Date: Tue, 13 Apr 2021 13:00:18 +0000 -Subject: [PATCH] Add support for MetricDefinition scheme - -Added MetricDefinition node to Redfish code. Now user is able to list -all available metrics in OpenBMC that are supported by Telemetry -service. Metrics are grouped by reading type. - -MetricDefinitions contains all physical sensors supported by redfish, -algorithm iterates through all chassis and collects results for each -node available in that chassis (Power, Thermal, Sensors). - -When BMCWEB_NEW_POWERSUBSYSTEM_THERMALSUBSYSTEM will be enabled by -default (meson option redfish-new-powersubsystem-thermalsubsystem) it -will be possible to optimize this algorithm to only get sensors from -Sensors node. Currently Sensors node doesn't contain all available -sensors. - -Tested: - - MetricDefinitions response is filled with existing sensors, it works - with and without Telemetry service - - Validated a presence of MetricDefinition members and its attributes - - Successfully passed RedfishServiceValidator.py using witherspoon - image on QEMU - - Tested using following GET,POST requests - -GET /redfish/v1/TelemetryService/MetricDefinitions -{ - "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions", - "@odata.type": "#MetricDefinitionCollection.MetricDefinitionCollection", - "Members": [ - { - "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Fan_Pwm" - }, - { - "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Fan_Tach" - }, - { - "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/HostCpuUtilization" - }, - { - "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/HostMemoryBandwidthUtilization" - }, - { - "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/HostPciBandwidthUtilization" - }, - { - "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Inlet_BRD_Temp" - }, - { - "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Left_Rear_Board_Temp" - } - ], - "Members@odata.count": 7, - "Name": "Metric Definition Collection" -} - -GET /redfish/v1/TelemetryService/MetricDefinitions/Fan_Tach -{ - "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Fan_Tach", - "@odata.type": "#MetricDefinition.v1_0_3.MetricDefinition", - "Id": "Fan_Tach", - "IsLinear": true, - "MaxReadingRange": 25000.0, - "MetricDataType": "Decimal", - "MetricProperties": [ - "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/0/Reading", - "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/1/Reading", - "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/2/Reading", - "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/3/Reading", - "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/4/Reading", - "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/5/Reading", - "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/6/Reading", - "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/7/Reading", - "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/8/Reading", - "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/9/Reading" - ], - "MetricType": "Gauge", - "MinReadingRange": 0.0, - "Name": "Fan_Tach", - "Units": "RPM" -} - -POST redfish/v1/TelemetryService/MetricReportDefinitions, body: -{ - "Id": "TestReport", - "Metrics": [ - { - "MetricId": "TestMetric", - "MetricProperties": [ - "/redfish/v1/Chassis/Chassis0/Thermal#/Fans/3/Reading", - ] - } - ], - "MetricReportDefinitionType": "OnRequest", - "ReportActions": [ - "RedfishEvent", - "LogToMetricReportsCollection" - ] -} -{ - "@Message.ExtendedInfo": [ - { - "@odata.type": "#Message.v1_1_1.Message", - "Message": "The resource has been created successfully", - "MessageArgs": [], - "MessageId": "Base.1.8.1.Created", - "MessageSeverity": "OK", - "Resolution": "None" - } - ] -} - -Signed-off-by: Wludzik, Jozef -Signed-off-by: Krzysztof Grobelny -Change-Id: I3086e1302e1ba2e5442d1367939fd5507a0cbc00 ---- - redfish-core/include/redfish.hpp | 3 + - .../include/utils/get_chassis_names.hpp | 58 +++ - .../include/utils/telemetry_utils.hpp | 2 + - redfish-core/lib/metric_definition.hpp | 368 ++++++++++++++++++ - redfish-core/lib/telemetry_service.hpp | 3 +- - 5 files changed, 433 insertions(+), 1 deletion(-) - create mode 100644 redfish-core/include/utils/get_chassis_names.hpp - create mode 100644 redfish-core/lib/metric_definition.hpp - -diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp -index 0a97150..67c5af2 100644 ---- a/redfish-core/include/redfish.hpp -+++ b/redfish-core/include/redfish.hpp -@@ -26,6 +26,7 @@ - #include "../lib/managers.hpp" - #include "../lib/memory.hpp" - #include "../lib/message_registries.hpp" -+#include "../lib/metric_definition.hpp" - #include "../lib/metric_report.hpp" - #include "../lib/metric_report_definition.hpp" - #include "../lib/network_protocol.hpp" -@@ -200,6 +201,8 @@ class RedfishService - requestRoutesMetricReportDefinition(app); - requestRoutesMetricReportCollection(app); - requestRoutesMetricReport(app); -+ requestRoutesMetricDefinitionCollection(app); -+ requestRoutesMetricDefinition(app); - } - }; - -diff --git a/redfish-core/include/utils/get_chassis_names.hpp b/redfish-core/include/utils/get_chassis_names.hpp -new file mode 100644 -index 0000000..0276b6f ---- /dev/null -+++ b/redfish-core/include/utils/get_chassis_names.hpp -@@ -0,0 +1,58 @@ -+#pragma once -+ -+#include -+ -+#include -+#include -+#include -+ -+namespace redfish -+{ -+ -+namespace utils -+{ -+ -+template -+inline void getChassisNames(F&& cb) -+{ -+ const std::array interfaces = { -+ "xyz.openbmc_project.Inventory.Item.Board", -+ "xyz.openbmc_project.Inventory.Item.Chassis"}; -+ -+ crow::connections::systemBus->async_method_call( -+ [callback = std::move(cb)](const boost::system::error_code ec, -+ const std::vector& chassis) { -+ std::vector chassisNames; -+ -+ if (ec) -+ { -+ callback(ec, chassisNames); -+ return; -+ } -+ -+ chassisNames.reserve(chassis.size()); -+ for (const std::string& path : chassis) -+ { -+ sdbusplus::message::object_path dbusPath = path; -+ std::string name = dbusPath.filename(); -+ if (name.empty()) -+ { -+ callback(boost::system::errc::make_error_code( -+ boost::system::errc::invalid_argument), -+ chassisNames); -+ return; -+ } -+ chassisNames.emplace_back(std::move(name)); -+ } -+ -+ callback(ec, chassisNames); -+ }, -+ "xyz.openbmc_project.ObjectMapper", -+ "/xyz/openbmc_project/object_mapper", -+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", -+ "/xyz/openbmc_project/inventory", 0, interfaces); -+} -+ -+} // namespace utils -+ -+} // namespace redfish -diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp -index 5872350..1b4f75d 100644 ---- a/redfish-core/include/utils/telemetry_utils.hpp -+++ b/redfish-core/include/utils/telemetry_utils.hpp -@@ -10,6 +10,8 @@ namespace telemetry - - constexpr const char* service = "xyz.openbmc_project.Telemetry"; - constexpr const char* reportInterface = "xyz.openbmc_project.Telemetry.Report"; -+constexpr const char* metricDefinitionUri = -+ "/redfish/v1/TelemetryService/MetricDefinitions/"; - constexpr const char* metricReportDefinitionUri = - "/redfish/v1/TelemetryService/MetricReportDefinitions/"; - constexpr const char* metricReportUri = -diff --git a/redfish-core/lib/metric_definition.hpp b/redfish-core/lib/metric_definition.hpp -new file mode 100644 -index 0000000..347c297 ---- /dev/null -+++ b/redfish-core/lib/metric_definition.hpp -@@ -0,0 +1,368 @@ -+#pragma once -+ -+#include "async_resp.hpp" -+#include "sensors.hpp" -+#include "utils/get_chassis_names.hpp" -+#include "utils/telemetry_utils.hpp" -+ -+#include -+ -+namespace redfish -+{ -+ -+namespace telemetry -+{ -+ -+struct ValueVisitor -+{ -+ ValueVisitor(boost::system::error_code& ec) : ec(ec) -+ {} -+ -+ template -+ double operator()(T value) const -+ { -+ return static_cast(value); -+ } -+ -+ double operator()(std::monostate) const -+ { -+ ec = boost::system::errc::make_error_code( -+ boost::system::errc::invalid_argument); -+ return double{}; -+ } -+ -+ boost::system::error_code& ec; -+}; -+ -+inline void getReadingRange( -+ const std::string& service, const std::string& path, -+ const std::string& property, -+ std::function callback) -+{ -+ crow::connections::systemBus->async_method_call( -+ [callback = std::move(callback)]( -+ boost::system::error_code ec, -+ const std::variant& -+ valueVariant) { -+ if (ec) -+ { -+ callback(ec, double{}); -+ return; -+ } -+ -+ const double value = std::visit(ValueVisitor(ec), valueVariant); -+ -+ callback(ec, value); -+ }, -+ service, path, "org.freedesktop.DBus.Properties", "Get", -+ "xyz.openbmc_project.Sensor.Value", property); -+} -+ -+inline void -+ fillMinMaxReadingRange(const std::shared_ptr& asyncResp, -+ const std::string& serviceName, -+ const std::string& sensorPath) -+{ -+ asyncResp->res.jsonValue["MetricType"] = "Numeric"; -+ -+ telemetry::getReadingRange( -+ serviceName, sensorPath, "MinValue", -+ [asyncResp](boost::system::error_code ec, double readingRange) { -+ if (ec) -+ { -+ messages::internalError(asyncResp->res); -+ return; -+ } -+ -+ if (std::isfinite(readingRange)) -+ { -+ asyncResp->res.jsonValue["MetricType"] = "Gauge"; -+ -+ asyncResp->res.jsonValue["MinReadingRange"] = readingRange; -+ } -+ }); -+ -+ telemetry::getReadingRange( -+ serviceName, sensorPath, "MaxValue", -+ [asyncResp](boost::system::error_code ec, double readingRange) { -+ if (ec) -+ { -+ messages::internalError(asyncResp->res); -+ return; -+ } -+ -+ if (std::isfinite(readingRange)) -+ { -+ asyncResp->res.jsonValue["MetricType"] = "Gauge"; -+ -+ asyncResp->res.jsonValue["MaxReadingRange"] = readingRange; -+ } -+ }); -+} -+ -+inline void getSensorService( -+ const std::string& sensorPath, -+ std::function callback) -+{ -+ using ResultType = std::pair< -+ std::string, -+ std::vector>>>; -+ -+ crow::connections::systemBus->async_method_call( -+ [sensorPath, callback = std::move(callback)]( -+ boost::system::error_code ec, -+ const std::vector& result) { -+ if (ec) -+ { -+ callback(ec, std::string{}); -+ return; -+ } -+ -+ for (const auto& [path, serviceToInterfaces] : result) -+ { -+ if (path == sensorPath) -+ { -+ for (const auto& [service, interfaces] : -+ serviceToInterfaces) -+ { -+ callback(boost::system::errc::make_error_code( -+ boost::system::errc::success), -+ service); -+ return; -+ } -+ } -+ } -+ -+ callback(boost::system::errc::make_error_code( -+ boost::system::errc::no_such_file_or_directory), -+ std::string{}); -+ }, -+ "xyz.openbmc_project.ObjectMapper", -+ "/xyz/openbmc_project/object_mapper", -+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", -+ "/xyz/openbmc_project/sensors", 2, -+ std::array{"xyz.openbmc_project.Sensor.Value"}); -+} -+ -+constexpr auto metricDefinitionMapping = std::array{ -+ std::pair{"fan_pwm", "Fan_Pwm"}, std::pair{"fan_tach", "Fan_Tach"}}; -+ -+std::string mapSensorToMetricDefinition(const std::string& sensorPath) -+{ -+ sdbusplus::message::object_path sensorObjectPath{sensorPath}; -+ -+ const auto it = std::find_if( -+ metricDefinitionMapping.begin(), metricDefinitionMapping.end(), -+ [&sensorObjectPath](const auto& item) { -+ return item.first == sensorObjectPath.parent_path().filename(); -+ }); -+ -+ const char* metricDefinitionPath = -+ "/redfish/v1/TelemetryService/MetricDefinitions/"; -+ -+ if (it != metricDefinitionMapping.end()) -+ { -+ return std::string{metricDefinitionPath} + it->second; -+ } -+ -+ return metricDefinitionPath + sensorObjectPath.filename(); -+} -+ -+template -+inline void mapRedfishUriToDbusPath(Callback&& callback) -+{ -+ utils::getChassisNames([callback = std::move(callback)]( -+ boost::system::error_code ec, -+ const std::vector& chassisNames) { -+ if (ec) -+ { -+ BMCWEB_LOG_ERROR << "getChassisNames error: " << ec.value(); -+ callback(ec, {}); -+ return; -+ } -+ -+ auto counter = std::make_shared, size_t>>(); -+ -+ auto handleRetrieveUriToDbusMap = -+ [counter, callback = std::move(callback)]( -+ const boost::beast::http::status status, -+ const boost::container::flat_map& -+ uriToDbus) { -+ if (status != boost::beast::http::status::ok) -+ { -+ BMCWEB_LOG_ERROR << "Failed to retrieve URI to dbus " -+ "sensors map with err " -+ << static_cast(status); -+ counter->second = 0u; -+ callback(boost::system::errc::make_error_code( -+ boost::system::errc::io_error), -+ {}); -+ return; -+ } -+ -+ for (const auto& [key, value] : uriToDbus) -+ { -+ counter->first[key] = value; -+ } -+ -+ if (--counter->second == 0u) -+ { -+ callback(boost::system::errc::make_error_code( -+ boost::system::errc::success), -+ counter->first); -+ } -+ }; -+ -+ for (const std::string& chassisName : chassisNames) -+ { -+ for (const auto& [sensorNode, dbusPaths] : sensors::dbus::paths) -+ { -+ ++counter->second; -+ retrieveUriToDbusMap(chassisName, sensorNode.data(), -+ handleRetrieveUriToDbusMap); -+ } -+ } -+ }); -+} -+ -+} // namespace telemetry -+ -+inline void requestRoutesMetricDefinitionCollection(App& app) -+{ -+ BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricDefinitions/") -+ .privileges(privileges::getTelemetryService) -+ .methods(boost::beast::http::verb::get)( -+ [](const crow::Request&, -+ const std::shared_ptr& asyncResp) { -+ telemetry::mapRedfishUriToDbusPath( -+ [asyncResp](boost::system::error_code ec, -+ const boost::container::flat_map< -+ std::string, std::string>& uriToDbus) { -+ if (ec) -+ { -+ messages::internalError(asyncResp->res); -+ BMCWEB_LOG_ERROR -+ << "mapRedfishUriToDbusPath error: " -+ << ec.value(); -+ return; -+ } -+ -+ std::set members; -+ -+ for (const auto& [uri, dbusPath] : uriToDbus) -+ { -+ members.insert( -+ telemetry::mapSensorToMetricDefinition( -+ dbusPath)); -+ } -+ -+ for (const std::string& odataId : members) -+ { -+ asyncResp->res.jsonValue["Members"].push_back( -+ {{"@odata.id", odataId}}); -+ } -+ -+ asyncResp->res.jsonValue["Members@odata.count"] = -+ asyncResp->res.jsonValue["Members"].size(); -+ }); -+ -+ asyncResp->res.jsonValue["@odata.type"] = -+ "#MetricDefinitionCollection." -+ "MetricDefinitionCollection"; -+ asyncResp->res.jsonValue["@odata.id"] = -+ "/redfish/v1/TelemetryService/MetricDefinitions"; -+ asyncResp->res.jsonValue["Name"] = -+ "Metric Definition Collection"; -+ asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); -+ asyncResp->res.jsonValue["Members@odata.count"] = 0; -+ }); -+} -+ -+inline void requestRoutesMetricDefinition(App& app) -+{ -+ BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricDefinitions//") -+ .privileges(privileges::getTelemetryService) -+ .methods( -+ boost::beast::http::verb::get)([](const crow::Request&, -+ const std::shared_ptr< -+ bmcweb::AsyncResp>& asyncResp, -+ const std::string& name) { -+ telemetry::mapRedfishUriToDbusPath( -+ [asyncResp, name]( -+ boost::system::error_code ec, -+ const boost::container::flat_map& -+ uriToDbus) { -+ if (ec) -+ { -+ messages::internalError(asyncResp->res); -+ BMCWEB_LOG_ERROR << "mapRedfishUriToDbusPath error: " -+ << ec.value(); -+ return; -+ } -+ -+ std::string odataId = telemetry::metricDefinitionUri + name; -+ boost::container::flat_map -+ matchingUris; -+ -+ for (const auto& [uri, dbusPath] : uriToDbus) -+ { -+ if (telemetry::mapSensorToMetricDefinition(dbusPath) == -+ odataId) -+ { -+ matchingUris.emplace(uri, dbusPath); -+ } -+ } -+ -+ if (matchingUris.empty()) -+ { -+ messages::resourceNotFound(asyncResp->res, -+ "MetricDefinition", name); -+ return; -+ } -+ -+ std::string sensorPath = matchingUris.begin()->second; -+ -+ telemetry::getSensorService( -+ sensorPath, -+ [asyncResp, name, odataId = std::move(odataId), -+ sensorPath, matchingUris = std::move(matchingUris)]( -+ boost::system::error_code ec, -+ const std::string& serviceName) { -+ if (ec) -+ { -+ messages::internalError(asyncResp->res); -+ BMCWEB_LOG_ERROR << "getServiceSensorFailed: " -+ << ec.value(); -+ return; -+ } -+ -+ asyncResp->res.jsonValue["Id"] = name; -+ asyncResp->res.jsonValue["Name"] = name; -+ asyncResp->res.jsonValue["@odata.id"] = odataId; -+ asyncResp->res.jsonValue["@odata.type"] = -+ "#MetricDefinition.v1_0_3.MetricDefinition"; -+ asyncResp->res.jsonValue["MetricDataType"] = -+ "Decimal"; -+ asyncResp->res.jsonValue["IsLinear"] = true; -+ asyncResp->res.jsonValue["Units"] = -+ sensors::toReadingUnits( -+ sdbusplus::message::object_path{sensorPath} -+ .parent_path() -+ .filename()); -+ -+ for (const auto& [uri, dbusPath] : matchingUris) -+ { -+ asyncResp->res.jsonValue["MetricProperties"] -+ .push_back(uri); -+ } -+ -+ telemetry::fillMinMaxReadingRange( -+ asyncResp, serviceName, sensorPath); -+ }); -+ }); -+ }); -+} -+ -+} // namespace redfish -diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp -index 8ecc591..027b51b 100644 ---- a/redfish-core/lib/telemetry_service.hpp -+++ b/redfish-core/lib/telemetry_service.hpp -@@ -18,11 +18,12 @@ inline void handleTelemetryServiceGet( - asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/TelemetryService"; - asyncResp->res.jsonValue["Id"] = "TelemetryService"; - asyncResp->res.jsonValue["Name"] = "Telemetry Service"; -- - asyncResp->res.jsonValue["MetricReportDefinitions"]["@odata.id"] = - "/redfish/v1/TelemetryService/MetricReportDefinitions"; - asyncResp->res.jsonValue["MetricReports"]["@odata.id"] = - "/redfish/v1/TelemetryService/MetricReports"; -+ asyncResp->res.jsonValue["MetricDefinitions"]["@odata.id"] = -+ "/redfish/v1/TelemetryService/MetricDefinitions"; - - crow::connections::systemBus->async_method_call( - [asyncResp](const boost::system::error_code ec, --- -2.25.1 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-POST-on-TriggersCollection.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-POST-on-TriggersCollection.patch new file mode 100644 index 000000000..b0cf44cb2 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-POST-on-TriggersCollection.patch @@ -0,0 +1,889 @@ +From 008cc1b35ccb1508d3c71ff5c6cfc6c772f1744c Mon Sep 17 00:00:00 2001 +From: Szymon Dompke +Date: Wed, 17 Nov 2021 18:18:16 +0100 +Subject: [PATCH] Add support for POST on TriggersCollection +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Added POST method on /redfish/v1/TelemetryService/Triggers uri, which +creates new trigger in telemetry service, by using dbus call AddTrigger. + +By DMTF, most of the properties are not required, and as such are +treated as optional. Some values can be deduced from others (like +'MetricType', depending on 'DiscreteTriggers' or 'NumericThresholds'). +All properties provided in POST body by user will be verified against +each other, and errors will be raised. Few examples of such situations: +- 'MetricType' is set to 'Discrete' but 'NumericThresholds' was passed. +- 'MetricType' is set to 'Numeric' but "DiscreteTriggers' or + 'DiscreteTriggerCondition' were passed +- 'DiscreteTriggerCondition' is set to 'Specified' but + 'DiscreteTriggers' is an empty array or was not passed. +- 'DiscreteTriggerCondition' is set to 'Changed' but 'DiscreteTriggers' + is passed and is not an empty array. + +Example 1 – Trigger with discrete values: +{ + "Id": "TestTrigger", + "MetricType": "Discrete", + "TriggerActions": [ + "RedfishEvent" + ], + "DiscreteTriggerCondition": "Specified", + "DiscreteTriggers": [ + { + "Value": "55.88", + "DwellTime": "PT0.001S", + "Severity": "Warning" + }, + { + "Name": "My discrete trigger", + "Value": "55.88", + "DwellTime": "PT0.001S", + "Severity": "OK" + }, + { + "Value": "55.88", + "DwellTime": "PT0.001S", + "Severity": "Critical" + } + ], + "MetricProperties": [ + "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/0/Reading" + ], + "Links": { + "MetricReportDefinitions": [] + } +} + +Example 2 – trigger with numeric threshold: +{ + "Id": "TestTrigger2", + "Name": "My Numeric Trigger", + "MetricType": "Numeric", + "TriggerActions": [ + "RedfishEvent", + "RedfishMetricReport" + ], + "NumericThresholds": { + "UpperCritical": { + "Reading": 50, + "Activation": "Increasing", + "DwellTime": "PT0.001S" + }, + "UpperWarning": { + "Reading": 48.1, + "Activation": "Increasing", + "DwellTime": "PT0.004S" + } + }, + "MetricProperties": [ + "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/0/Reading", + "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/17/Reading" + ], + "Links": { + "MetricReportDefinitions": [ + "/redfish/v1/TelemetryService/MetricReportDefinitions/PowerMetrics", + "/redfish/v1/TelemetryService/MetricReportDefinitions/PowerMetricStats", + "/redfish/v1/TelemetryService/MetricReportDefinitions/PlatformPowerUsage" + ] + } +} + +Tested: +- Triggers were successfully created with above example message bodies. + This can be checked by calling: + 'busctl tree xyz.openbmc_project.Telemetry'. +- Expected errors were returned for messages with incorrect or mutually + exclusive properties and incorrect values. +- Redfish service validator is passing. + +Signed-off-by: Szymon Dompke +Change-Id: Ief8c76de8aa660ae0d2dbe4610c26a28186a290a +--- + redfish-core/include/utils/finalizer.hpp | 35 ++ + .../include/utils/telemetry_utils.hpp | 82 +++ + redfish-core/lib/metric_report_definition.hpp | 31 +- + redfish-core/lib/trigger.hpp | 526 +++++++++++++++++- + 4 files changed, 642 insertions(+), 32 deletions(-) + create mode 100644 redfish-core/include/utils/finalizer.hpp + +diff --git a/redfish-core/include/utils/finalizer.hpp b/redfish-core/include/utils/finalizer.hpp +new file mode 100644 +index 0000000..cb98507 +--- /dev/null ++++ b/redfish-core/include/utils/finalizer.hpp +@@ -0,0 +1,35 @@ ++#pragma once ++ ++#include ++ ++namespace redfish ++{ ++ ++namespace utils ++{ ++ ++class Finalizer ++{ ++ public: ++ Finalizer() = delete; ++ Finalizer(std::function finalizer) : finalizer(std::move(finalizer)) ++ {} ++ ++ Finalizer(const Finalizer&) = delete; ++ Finalizer(Finalizer&&) = delete; ++ ++ ~Finalizer() ++ { ++ if (finalizer) ++ { ++ finalizer(); ++ } ++ } ++ ++ private: ++ std::function finalizer; ++}; ++ ++} // namespace utils ++ ++} // namespace redfish +\ No newline at end of file +diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp +index 8aeff0d..c68e40c 100644 +--- a/redfish-core/include/utils/telemetry_utils.hpp ++++ b/redfish-core/include/utils/telemetry_utils.hpp +@@ -13,6 +13,9 @@ constexpr const char* metricReportDefinitionUri = + "/redfish/v1/TelemetryService/MetricReportDefinitions"; + constexpr const char* metricReportUri = + "/redfish/v1/TelemetryService/MetricReports"; ++constexpr const char* triggerInterface = ++ "xyz.openbmc_project.Telemetry.Trigger"; ++constexpr const char* triggerUri = "/redfish/v1/TelemetryService/Triggers"; + + inline std::string getDbusReportPath(const std::string& id) + { +@@ -28,5 +31,84 @@ inline std::string getDbusTriggerPath(const std::string& id) + return {triggersPath / id}; + } + ++inline std::optional ++ getReportNameFromReportDefinitionUri(const std::string& uri) ++{ ++ constexpr const char* uriPattern = ++ "/redfish/v1/TelemetryService/MetricReportDefinitions/"; ++ constexpr size_t idx = std::string_view(uriPattern).length(); ++ if (boost::starts_with(uri, uriPattern)) ++ { ++ return uri.substr(idx); ++ } ++ return std::nullopt; ++} ++ ++inline std::optional ++ getTriggerIdFromDbusPath(const std::string& dbusPath) ++{ ++ constexpr const char* triggerTree = ++ "/xyz/openbmc_project/Telemetry/Triggers/TelemetryService/"; ++ constexpr size_t idx = std::string_view(triggerTree).length(); ++ if (boost::starts_with(dbusPath, triggerTree)) ++ { ++ return dbusPath.substr(idx); ++ } ++ return std::nullopt; ++} ++ ++inline bool getChassisSensorNode( ++ const std::shared_ptr& asyncResp, ++ const std::vector& uris, ++ boost::container::flat_set>& matched) ++{ ++ size_t uriIdx = 0; ++ for (const std::string& uri : uris) ++ { ++ std::string chassis; ++ std::string node; ++ ++ if (!boost::starts_with(uri, "/redfish/v1/Chassis/") || ++ !dbus::utility::getNthStringFromPath(uri, 3, chassis) || ++ !dbus::utility::getNthStringFromPath(uri, 4, node)) ++ { ++ BMCWEB_LOG_ERROR << "Failed to get chassis and sensor Node " ++ "from " ++ << uri; ++ messages::propertyValueIncorrect(asyncResp->res, uri, ++ "MetricProperties/" + ++ std::to_string(uriIdx)); ++ return false; ++ } ++ ++ if (boost::ends_with(node, "#")) ++ { ++ node.pop_back(); ++ } ++ ++ matched.emplace(std::move(chassis), std::move(node)); ++ uriIdx++; ++ } ++ return true; ++} ++ ++inline std::optional ++ redfishActionToDbusAction(const std::string& redfishAction) ++{ ++ if (redfishAction == "RedfishMetricReport") ++ { ++ return "UpdateReport"; ++ } ++ if (redfishAction == "RedfishEvent") ++ { ++ return "RedfishEvent"; ++ } ++ if (redfishAction == "LogToLogService") ++ { ++ return "LogToLogService"; ++ } ++ return std::nullopt; ++} ++ + } // namespace telemetry + } // namespace redfish +diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp +index cb38633..4007544 100644 +--- a/redfish-core/lib/metric_report_definition.hpp ++++ b/redfish-core/lib/metric_report_definition.hpp +@@ -217,7 +217,7 @@ inline bool getUserParameters(crow::Response& res, const crow::Request& req, + return true; + } + +-inline bool getChassisSensorNode( ++inline bool getChassisSensorNodeFromMetrics( + const std::shared_ptr& asyncResp, + const std::vector>>& + metrics, +@@ -225,30 +225,9 @@ inline bool getChassisSensorNode( + { + for (const auto& [id, uris] : metrics) + { +- for (size_t i = 0; i < uris.size(); i++) ++ if (!getChassisSensorNode(asyncResp, uris, matched)) + { +- const std::string& uri = uris[i]; +- std::string chassis; +- std::string node; +- +- if (!boost::starts_with(uri, "/redfish/v1/Chassis/") || +- !dbus::utility::getNthStringFromPath(uri, 3, chassis) || +- !dbus::utility::getNthStringFromPath(uri, 4, node)) +- { +- BMCWEB_LOG_ERROR +- << "Failed to get chassis and sensor Node from " << uri; +- messages::propertyValueIncorrect(asyncResp->res, uri, +- "MetricProperties/" + +- std::to_string(i)); +- return false; +- } +- +- if (boost::ends_with(node, "#")) +- { +- node.pop_back(); +- } +- +- matched.emplace(std::move(chassis), std::move(node)); ++ return false; + } + } + return true; +@@ -382,8 +361,8 @@ inline void requestRoutesMetricReportDefinitionCollection(App& app) + + boost::container::flat_set> + chassisSensors; +- if (!telemetry::getChassisSensorNode(asyncResp, args.metrics, +- chassisSensors)) ++ if (!telemetry::getChassisSensorNodeFromMetrics( ++ asyncResp, args.metrics, chassisSensors)) + { + return; + } +diff --git a/redfish-core/lib/trigger.hpp b/redfish-core/lib/trigger.hpp +index 210468c..01c150e 100644 +--- a/redfish-core/lib/trigger.hpp ++++ b/redfish-core/lib/trigger.hpp +@@ -1,7 +1,9 @@ + #pragma once + +-#include "utils/collection.hpp" ++#include "sensors.hpp" ++#include "utils/finalizer.hpp" + #include "utils/telemetry_utils.hpp" ++#include "utils/time_utils.hpp" + + #include + #include +@@ -14,9 +16,10 @@ namespace redfish + { + namespace telemetry + { +-constexpr const char* triggerInterface = +- "xyz.openbmc_project.Telemetry.Trigger"; +-constexpr const char* triggerUri = "/redfish/v1/TelemetryService/Triggers"; ++ ++static constexpr std::array ++ supportedNumericThresholdNames = {"UpperCritical", "LowerCritical", ++ "UpperWarning", "LowerWarning"}; + + using NumericThresholdParams = + std::tuple; +@@ -24,6 +27,10 @@ using NumericThresholdParams = + using DiscreteThresholdParams = + std::tuple; + ++using TriggerThresholdParams = ++ std::variant, ++ std::vector>; ++ + using TriggerThresholdParamsExt = + std::variant, + std::vector>; +@@ -35,6 +42,455 @@ using TriggerGetParamsVariant = + std::variant>; + ++namespace add_trigger ++{ ++ ++enum class MetricType ++{ ++ Discrete, ++ Numeric ++}; ++ ++enum class DiscreteCondition ++{ ++ Specified, ++ Changed ++}; ++ ++struct Context ++{ ++ struct ++ { ++ std::string id; ++ std::string name; ++ std::vector actions; ++ std::vector> ++ sensors; ++ std::vector reportNames; ++ TriggerThresholdParams thresholds; ++ } dbusArgs; ++ ++ struct ++ { ++ std::optional discreteCondition; ++ std::optional metricType; ++ std::optional> metricProperties; ++ } parsedInfo; ++ ++ boost::container::flat_map uriToDbusMerged{}; ++}; ++ ++inline std::optional getMetricType(const std::string& metricType) ++{ ++ if (metricType == "Discrete") ++ { ++ return MetricType::Discrete; ++ } ++ if (metricType == "Numeric") ++ { ++ return MetricType::Numeric; ++ } ++ return std::nullopt; ++} ++ ++inline std::optional ++ getDiscreteCondition(const std::string& discreteTriggerCondition) ++{ ++ if (discreteTriggerCondition == "Specified") ++ { ++ return DiscreteCondition::Specified; ++ } ++ if (discreteTriggerCondition == "Changed") ++ { ++ return DiscreteCondition::Changed; ++ } ++ return std::nullopt; ++} ++ ++inline bool parseNumericThresholds(crow::Response& res, ++ nlohmann::json& numericThresholds, ++ Context& ctx) ++{ ++ if (!numericThresholds.is_object()) ++ { ++ messages::propertyValueTypeError(res, numericThresholds.dump(), ++ "NumericThresholds"); ++ return false; ++ } ++ ++ std::vector parsedParams; ++ parsedParams.reserve(numericThresholds.size()); ++ ++ for (auto& [thresholdName, thresholdData] : numericThresholds.items()) ++ { ++ if (std::find(supportedNumericThresholdNames.begin(), ++ supportedNumericThresholdNames.end(), ++ thresholdName) == supportedNumericThresholdNames.end()) ++ { ++ messages::propertyUnknown(res, thresholdName); ++ return false; ++ } ++ ++ double reading = .0; ++ std::string activation; ++ std::string dwellTimeStr; ++ ++ if (!json_util::readJson(thresholdData, res, "Reading", reading, ++ "Activation", activation, "DwellTime", ++ dwellTimeStr)) ++ { ++ return false; ++ } ++ ++ std::optional dwellTime = ++ time_utils::fromDurationString(dwellTimeStr); ++ if (!dwellTime) ++ { ++ messages::propertyValueIncorrect(res, "DwellTime", dwellTimeStr); ++ return false; ++ } ++ ++ parsedParams.emplace_back(thresholdName, ++ static_cast(dwellTime->count()), ++ activation, reading); ++ } ++ ++ ctx.dbusArgs.thresholds = std::move(parsedParams); ++ return true; ++} ++ ++inline bool parseDiscreteTriggers( ++ crow::Response& res, ++ std::optional>& discreteTriggers, Context& ctx) ++{ ++ std::vector parsedParams; ++ if (!discreteTriggers) ++ { ++ ctx.dbusArgs.thresholds = std::move(parsedParams); ++ return true; ++ } ++ ++ parsedParams.reserve(discreteTriggers->size()); ++ for (nlohmann::json& thresholdInfo : *discreteTriggers) ++ { ++ std::optional name; ++ std::string value; ++ std::string dwellTimeStr; ++ std::string severity; ++ ++ if (!json_util::readJson(thresholdInfo, res, "Name", name, "Value", ++ value, "DwellTime", dwellTimeStr, "Severity", ++ severity)) ++ { ++ return false; ++ } ++ ++ std::optional dwellTime = ++ time_utils::fromDurationString(dwellTimeStr); ++ if (!dwellTime) ++ { ++ messages::propertyValueIncorrect(res, "DwellTime", dwellTimeStr); ++ return false; ++ } ++ ++ if (!name) ++ { ++ name = ""; ++ } ++ ++ parsedParams.emplace_back( ++ *name, severity, static_cast(dwellTime->count()), value); ++ } ++ ++ ctx.dbusArgs.thresholds = std::move(parsedParams); ++ return true; ++} ++ ++inline bool parseTriggerThresholds( ++ crow::Response& res, ++ std::optional>& discreteTriggers, ++ std::optional& numericThresholds, Context& ctx) ++{ ++ if (discreteTriggers && numericThresholds) ++ { ++ messages::mutualExclusiveProperties(res, "DiscreteTriggers", ++ "NumericThresholds"); ++ return false; ++ } ++ ++ if (ctx.parsedInfo.discreteCondition) ++ { ++ if (numericThresholds) ++ { ++ messages::mutualExclusiveProperties(res, "DiscreteTriggerCondition", ++ "NumericThresholds"); ++ return false; ++ } ++ } ++ ++ if (ctx.parsedInfo.metricType) ++ { ++ if (*ctx.parsedInfo.metricType == MetricType::Discrete && ++ numericThresholds) ++ { ++ messages::propertyValueConflict(res, "NumericThresholds", ++ "MetricType"); ++ return false; ++ } ++ if (*ctx.parsedInfo.metricType == MetricType::Numeric && ++ discreteTriggers) ++ { ++ messages::propertyValueConflict(res, "DiscreteTriggers", ++ "MetricType"); ++ return false; ++ } ++ if (*ctx.parsedInfo.metricType == MetricType::Numeric && ++ ctx.parsedInfo.discreteCondition) ++ { ++ messages::propertyValueConflict(res, "DiscreteTriggers", ++ "DiscreteTriggerCondition"); ++ return false; ++ } ++ } ++ ++ if (discreteTriggers || ctx.parsedInfo.discreteCondition || ++ (ctx.parsedInfo.metricType && ++ *ctx.parsedInfo.metricType == MetricType::Discrete)) ++ { ++ if (ctx.parsedInfo.discreteCondition) ++ { ++ if (*ctx.parsedInfo.discreteCondition == ++ DiscreteCondition::Specified && ++ !discreteTriggers) ++ { ++ messages::createFailedMissingReqProperties(res, ++ "DiscreteTriggers"); ++ return false; ++ } ++ if (discreteTriggers && ((*ctx.parsedInfo.discreteCondition == ++ DiscreteCondition::Specified && ++ discreteTriggers->empty()) || ++ (*ctx.parsedInfo.discreteCondition == ++ DiscreteCondition::Changed && ++ !discreteTriggers->empty()))) ++ { ++ messages::propertyValueConflict(res, "DiscreteTriggers", ++ "DiscreteTriggerCondition"); ++ return false; ++ } ++ } ++ if (!parseDiscreteTriggers(res, discreteTriggers, ctx)) ++ { ++ return false; ++ } ++ } ++ else if (numericThresholds) ++ { ++ if (!parseNumericThresholds(res, *numericThresholds, ctx)) ++ { ++ return false; ++ } ++ } ++ else ++ { ++ messages::createFailedMissingReqProperties( ++ res, "'DiscreteTriggers', 'NumericThresholds', " ++ "'DiscreteTriggerCondition' or 'MetricType'"); ++ return false; ++ } ++ return true; ++} ++ ++inline bool parseLinks(crow::Response& res, nlohmann::json& links, Context& ctx) ++{ ++ if (links.empty()) ++ { ++ return true; ++ } ++ ++ std::optional> metricReportDefinitions; ++ if (!json_util::readJson(links, res, "MetricReportDefinitions", ++ metricReportDefinitions)) ++ { ++ return false; ++ } ++ ++ if (metricReportDefinitions) ++ { ++ ctx.dbusArgs.reportNames.reserve(metricReportDefinitions->size()); ++ for (std::string& reportDefinionUri : *metricReportDefinitions) ++ { ++ std::optional reportName = ++ getReportNameFromReportDefinitionUri(reportDefinionUri); ++ if (!reportName) ++ { ++ messages::propertyValueIncorrect(res, "MetricReportDefinitions", ++ reportDefinionUri); ++ return false; ++ } ++ ctx.dbusArgs.reportNames.push_back(*reportName); ++ } ++ } ++ return true; ++} ++ ++inline bool parseMetricProperties(crow::Response& res, Context& ctx) ++{ ++ if (!ctx.parsedInfo.metricProperties) ++ { ++ return true; ++ } ++ ++ ctx.dbusArgs.sensors.reserve(ctx.parsedInfo.metricProperties->size()); ++ ++ size_t uriIdx = 0; ++ for (const std::string& uri : *ctx.parsedInfo.metricProperties) ++ { ++ auto el = ctx.uriToDbusMerged.find(uri); ++ if (el == ctx.uriToDbusMerged.end()) ++ { ++ BMCWEB_LOG_ERROR << "Failed to find DBus sensor " ++ "corsresponding to URI " ++ << uri; ++ messages::propertyValueNotInList( ++ res, uri, "MetricProperties/" + std::to_string(uriIdx)); ++ return false; ++ } ++ ++ const std::string& dbusPath = el->second; ++ ctx.dbusArgs.sensors.emplace_back(dbusPath, uri); ++ uriIdx++; ++ } ++ return true; ++} ++ ++inline bool parsePostTriggerParams(crow::Response& res, ++ const crow::Request& req, Context& ctx) ++{ ++ std::optional id; ++ std::optional name; ++ std::optional metricType; ++ std::optional> triggerActions; ++ std::optional discreteTriggerCondition; ++ std::optional> discreteTriggers; ++ std::optional numericThresholds; ++ std::optional links; ++ if (!json_util::readJson( ++ req, res, "Id", id, "Name", name, "MetricType", metricType, ++ "TriggerActions", triggerActions, "DiscreteTriggerCondition", ++ discreteTriggerCondition, "DiscreteTriggers", discreteTriggers, ++ "NumericThresholds", numericThresholds, "MetricProperties", ++ ctx.parsedInfo.metricProperties, "Links", links)) ++ { ++ return false; ++ } ++ ++ ctx.dbusArgs.id = id.value_or(""); ++ ctx.dbusArgs.name = name.value_or(""); ++ ++ if (metricType) ++ { ++ if (!(ctx.parsedInfo.metricType = getMetricType(*metricType))) ++ { ++ messages::propertyValueIncorrect(res, "MetricType", *metricType); ++ return false; ++ } ++ } ++ ++ if (discreteTriggerCondition) ++ { ++ if (!(ctx.parsedInfo.discreteCondition = ++ getDiscreteCondition(*discreteTriggerCondition))) ++ { ++ messages::propertyValueIncorrect(res, "DiscreteTriggerCondition", ++ *discreteTriggerCondition); ++ return false; ++ } ++ } ++ ++ if (triggerActions) ++ { ++ ctx.dbusArgs.actions.reserve(triggerActions->size()); ++ for (const std::string& action : *triggerActions) ++ { ++ if (const std::optional& dbusAction = ++ redfishActionToDbusAction(action)) ++ { ++ ctx.dbusArgs.actions.emplace_back(*dbusAction); ++ } ++ else ++ { ++ messages::propertyValueNotInList(res, action, "TriggerActions"); ++ return false; ++ } ++ } ++ } ++ ++ if (!parseTriggerThresholds(res, discreteTriggers, numericThresholds, ctx)) ++ { ++ return false; ++ } ++ ++ if (links) ++ { ++ if (!parseLinks(res, *links, ctx)) ++ { ++ return false; ++ } ++ } ++ return true; ++} ++ ++inline void createTrigger(const std::shared_ptr& asyncResp, ++ Context& ctx) ++{ ++ crow::connections::systemBus->async_method_call( ++ [aResp = asyncResp, id = ctx.dbusArgs.id]( ++ const boost::system::error_code ec, const std::string& dbusPath) { ++ if (ec == boost::system::errc::file_exists) ++ { ++ messages::resourceAlreadyExists(aResp->res, "Trigger", "Id", ++ id); ++ return; ++ } ++ if (ec == boost::system::errc::too_many_files_open) ++ { ++ messages::createLimitReachedForResource(aResp->res); ++ return; ++ } ++ if (ec) ++ { ++ messages::internalError(aResp->res); ++ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; ++ return; ++ } ++ ++ const std::optional& triggerId = ++ getTriggerIdFromDbusPath(dbusPath); ++ if (!triggerId) ++ { ++ messages::internalError(aResp->res); ++ BMCWEB_LOG_ERROR << "Unknown data returned by " ++ "AddTrigger DBus method"; ++ return; ++ } ++ ++ messages::created(aResp->res); ++ aResp->res.addHeader("Location", ++ triggerUri + std::string("/") + *triggerId); ++ }, ++ service, "/xyz/openbmc_project/Telemetry/Triggers", ++ "xyz.openbmc_project.Telemetry.TriggerManager", "AddTrigger", ++ "TelemetryService/" + ctx.dbusArgs.id, ctx.dbusArgs.name, ++ ctx.dbusArgs.actions, ctx.dbusArgs.sensors, ctx.dbusArgs.reportNames, ++ ctx.dbusArgs.thresholds); ++} ++ ++} // namespace add_trigger ++ ++namespace get_trigger ++{ ++ + inline std::optional + getRedfishFromDbusAction(const std::string& dbusAction) + { +@@ -270,6 +726,8 @@ inline bool fillTrigger( + return true; + } + ++} // namespace get_trigger ++ + } // namespace telemetry + + inline void requestRoutesTriggerCollection(App& app) +@@ -290,6 +748,62 @@ inline void requestRoutesTriggerCollection(App& app) + asyncResp, telemetry::triggerUri, interfaces, + "/xyz/openbmc_project/Telemetry/Triggers/TelemetryService"); + }); ++ ++ BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/Triggers/") ++ .privileges(redfish::privileges::postTriggersCollection) ++ .methods(boost::beast::http::verb::post)( ++ [](const crow::Request& req, ++ const std::shared_ptr& asyncResp) { ++ const auto ctx = ++ std::make_shared(); ++ if (!telemetry::add_trigger::parsePostTriggerParams( ++ asyncResp->res, req, *ctx)) ++ { ++ return; ++ } ++ ++ if (!ctx->parsedInfo.metricProperties || ++ ctx->parsedInfo.metricProperties->empty()) ++ { ++ telemetry::add_trigger::createTrigger(asyncResp, *ctx); ++ return; ++ } ++ ++ boost::container::flat_set> ++ chassisSensors; ++ if (!telemetry::getChassisSensorNode( ++ asyncResp, *ctx->parsedInfo.metricProperties, ++ chassisSensors)) ++ { ++ return; ++ } ++ ++ const auto finalizer = ++ std::make_shared([asyncResp, ctx] { ++ if (!telemetry::add_trigger::parseMetricProperties( ++ asyncResp->res, *ctx)) ++ { ++ return; ++ } ++ telemetry::add_trigger::createTrigger(asyncResp, *ctx); ++ }); ++ ++ for (const auto& [chassis, sensorType] : chassisSensors) ++ { ++ retrieveUriToDbusMap( ++ chassis, sensorType, ++ [asyncResp, ctx, ++ finalizer](const boost::beast::http::status status, ++ const boost::container::flat_map< ++ std::string, std::string>& uriToDbus) { ++ if (status == boost::beast::http::status::ok) ++ { ++ ctx->uriToDbusMerged.insert(uriToDbus.begin(), ++ uriToDbus.end()); ++ } ++ }); ++ } ++ }); + } + + inline void requestRoutesTrigger(App& app) +@@ -320,8 +834,8 @@ inline void requestRoutesTrigger(App& app) + return; + } + +- if (!telemetry::fillTrigger(asyncResp->res.jsonValue, +- id, ret)) ++ if (!telemetry::get_trigger::fillTrigger( ++ asyncResp->res.jsonValue, id, ret)) + { + messages::internalError(asyncResp->res); + } +-- +2.25.1 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Sync-Telmetry-service-with-EventService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Sync-Telmetry-service-with-EventService.patch new file mode 100644 index 000000000..f86f48528 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Sync-Telmetry-service-with-EventService.patch @@ -0,0 +1,284 @@ +From 383848b9088056371743a28eb1f9a3ed415dc46b Mon Sep 17 00:00:00 2001 +From: "Wludzik, Jozef" +Date: Tue, 15 Dec 2020 12:30:31 +0100 +Subject: [PATCH] Sync Telmetry service with EventService + +Synced the latest changes in Telemetry service with Event Service +code. Now assembling MetricReport is covered in single place in +code. Updated method of fetching Readings from Telemetry by +Event Service. Using ReportUpdate signal is no longer +supported. Now Event Service monitors for PropertiesChanged signal +from /xyz/openbmc_project/Telemetry/Reports path. + +Tested: + - Verified that EventListener received MetricReport response from + Event Service in insecure http push style eventing mode + +Change-Id: I2fc1841a6c9259a8bff30b34bddc0d4aabd41912 +Signed-off-by: Wludzik, Jozef +Signed-off-by: Lukasz Kazmierczak +--- + .../include/event_service_manager.hpp | 135 ++++++------------ + redfish-core/lib/metric_report.hpp | 29 ++-- + 2 files changed, 59 insertions(+), 105 deletions(-) + +diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp +index 010c991..38ab879 100644 +--- a/redfish-core/include/event_service_manager.hpp ++++ b/redfish-core/include/event_service_manager.hpp +@@ -14,6 +14,7 @@ + // limitations under the License. + */ + #pragma once ++#include "metric_report.hpp" + #include "registries.hpp" + #include "registries/base_message_registry.hpp" + #include "registries/openbmc_message_registry.hpp" +@@ -503,47 +504,32 @@ class Subscription : public persistent_data::UserSubscription + } + #endif + +- void filterAndSendReports(const std::string& id2, +- const std::string& readingsTs, +- const ReadingsObjType& readings) ++ void filterAndSendReports( ++ const std::string& id, ++ const std::variant& var) + { +- std::string metricReportDef = +- "/redfish/v1/TelemetryService/MetricReportDefinitions/" + id2; ++ std::string mrdUri = telemetry::metricReportDefinitionUri + id; + + // Empty list means no filter. Send everything. + if (metricReportDefinitions.size()) + { + if (std::find(metricReportDefinitions.begin(), + metricReportDefinitions.end(), +- metricReportDef) == metricReportDefinitions.end()) ++ mrdUri) == metricReportDefinitions.end()) + { + return; + } + } + +- nlohmann::json metricValuesArray = nlohmann::json::array(); +- for (const auto& it : readings) ++ nlohmann::json msg; ++ if (!telemetry::fillReport(msg, id, var)) + { +- metricValuesArray.push_back({}); +- nlohmann::json& entry = metricValuesArray.back(); +- +- auto& [id, property, value, timestamp] = it; +- +- entry = {{"MetricId", id}, +- {"MetricProperty", property}, +- {"MetricValue", std::to_string(value)}, +- {"Timestamp", crow::utility::getDateTime(timestamp)}}; ++ BMCWEB_LOG_ERROR << "Failed to fill the MetricReport for DBus " ++ "Report with id " ++ << id; ++ return; + } + +- nlohmann::json msg = { +- {"@odata.id", "/redfish/v1/TelemetryService/MetricReports/" + id}, +- {"@odata.type", "#MetricReport.v1_3_0.MetricReport"}, +- {"Id", id2}, +- {"Name", id2}, +- {"Timestamp", readingsTs}, +- {"MetricReportDefinition", {{"@odata.id", metricReportDef}}}, +- {"MetricValues", metricValuesArray}}; +- + this->sendEvent( + msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace)); + } +@@ -1309,73 +1295,43 @@ class EventServiceManager + } + + #endif +- +- void getMetricReading(const std::string& service, +- const std::string& objPath, const std::string& intf) ++ void getReadingsForReport(sdbusplus::message::message& msg) + { +- std::size_t found = objPath.find_last_of('/'); +- if (found == std::string::npos) ++ sdbusplus::message::object_path path(msg.get_path()); ++ std::string id = path.filename(); ++ if (id.empty()) + { +- BMCWEB_LOG_DEBUG << "Invalid objPath received"; ++ BMCWEB_LOG_ERROR << "Failed to get Id from path"; + return; + } + +- std::string idStr = objPath.substr(found + 1); +- if (idStr.empty()) ++ std::string interface; ++ std::vector< ++ std::pair>> ++ props; ++ std::vector invalidProps; ++ msg.read(interface, props, invalidProps); ++ ++ auto found = ++ std::find_if(props.begin(), props.end(), ++ [](const auto& x) { return x.first == "Readings"; }); ++ if (found == props.end()) + { +- BMCWEB_LOG_DEBUG << "Invalid ID in objPath"; ++ BMCWEB_LOG_INFO << "Failed to get Readings from Report properties"; + return; + } + +- crow::connections::systemBus->async_method_call( +- [idStr{std::move(idStr)}]( +- const boost::system::error_code ec, +- boost::container::flat_map< +- std::string, std::variant>& +- resp) { +- if (ec) +- { +- BMCWEB_LOG_DEBUG +- << "D-Bus call failed to GetAll metric readings."; +- return; +- } +- +- const int32_t* timestampPtr = +- std::get_if(&resp["Timestamp"]); +- if (!timestampPtr) +- { +- BMCWEB_LOG_DEBUG << "Failed to Get timestamp."; +- return; +- } +- +- ReadingsObjType* readingsPtr = +- std::get_if(&resp["Readings"]); +- if (!readingsPtr) +- { +- BMCWEB_LOG_DEBUG << "Failed to Get Readings property."; +- return; +- } +- +- if (!readingsPtr->size()) +- { +- BMCWEB_LOG_DEBUG << "No metrics report to be transferred"; +- return; +- } +- +- for (const auto& it : +- EventServiceManager::getInstance().subscriptionsMap) +- { +- std::shared_ptr entry = it.second; +- if (entry->eventFormatType == metricReportFormatType) +- { +- entry->filterAndSendReports( +- idStr, crow::utility::getDateTime(*timestampPtr), +- *readingsPtr); +- } +- } +- }, +- service, objPath, "org.freedesktop.DBus.Properties", "GetAll", +- intf); ++ const std::variant& readings = ++ found->second; ++ for (const auto& it : ++ EventServiceManager::getInstance().subscriptionsMap) ++ { ++ Subscription& entry = *it.second.get(); ++ if (entry.eventFormatType == metricReportFormatType) ++ { ++ entry.filterAndSendReports(id, readings); ++ } ++ } + } + + void unregisterMetricReportSignal() +@@ -1397,9 +1353,9 @@ class EventServiceManager + } + + BMCWEB_LOG_DEBUG << "Metrics report signal - Register"; +- std::string matchStr( +- "type='signal',member='ReportUpdate', " +- "interface='xyz.openbmc_project.MonitoringService.Report'"); ++ std::string matchStr = "type='signal',member='PropertiesChanged'," ++ "interface='org.freedesktop.DBus.Properties'," ++ "arg0=xyz.openbmc_project.Telemetry.Report"; + + matchTelemetryMonitor = std::make_shared( + *crow::connections::systemBus, matchStr, +@@ -1410,10 +1366,7 @@ class EventServiceManager + return; + } + +- std::string service = msg.get_sender(); +- std::string objPath = msg.get_path(); +- std::string intf = msg.get_interface(); +- getMetricReading(service, objPath, intf); ++ getReadingsForReport(msg); + }); + } + +diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp +index 159968a..c959495 100644 +--- a/redfish-core/lib/metric_report.hpp ++++ b/redfish-core/lib/metric_report.hpp +@@ -34,17 +34,14 @@ inline nlohmann::json toMetricValues(const Readings& readings) + return metricValues; + } + +-inline void fillReport(const std::shared_ptr& asyncResp, +- const std::string& id, ++inline bool fillReport(nlohmann::json& json, const std::string& id, + const std::variant& var) + { +- asyncResp->res.jsonValue["@odata.type"] = +- "#MetricReport.v1_3_0.MetricReport"; +- asyncResp->res.jsonValue["@odata.id"] = +- telemetry::metricReportUri + std::string("/") + id; +- asyncResp->res.jsonValue["Id"] = id; +- asyncResp->res.jsonValue["Name"] = id; +- asyncResp->res.jsonValue["MetricReportDefinition"]["@odata.id"] = ++ json["@odata.type"] = "#MetricReport.v1_3_0.MetricReport"; ++ json["@odata.id"] = telemetry::metricReportUri + std::string("/") + id; ++ json["Id"] = id; ++ json["Name"] = id; ++ json["MetricReportDefinition"]["@odata.id"] = + telemetry::metricReportDefinitionUri + std::string("/") + id; + + const TimestampReadings* timestampReadings = +@@ -52,14 +49,14 @@ inline void fillReport(const std::shared_ptr& asyncResp, + if (!timestampReadings) + { + BMCWEB_LOG_ERROR << "Property type mismatch or property is missing"; +- messages::internalError(asyncResp->res); +- return; ++ return false; + } + + const auto& [timestamp, readings] = *timestampReadings; +- asyncResp->res.jsonValue["Timestamp"] = ++ json["Timestamp"] = + crow::utility::getDateTime(static_cast(timestamp)); +- asyncResp->res.jsonValue["MetricValues"] = toMetricValues(readings); ++ json["MetricValues"] = toMetricValues(readings); ++ return true; + } + } // namespace telemetry + +@@ -122,7 +119,11 @@ inline void requestRoutesMetricReport(App& app) + return; + } + +- telemetry::fillReport(asyncResp, id, ret); ++ if (!telemetry::fillReport( ++ asyncResp->res.jsonValue, id, ret)) ++ { ++ messages::internalError(asyncResp->res); ++ } + }, + telemetry::service, reportPath, + "org.freedesktop.DBus.Properties", "Get", +-- +2.25.1 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Revert-Remove-LogService-from-TelemetryService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Revert-Remove-LogService-from-TelemetryService.patch new file mode 100644 index 000000000..6b57dc912 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Revert-Remove-LogService-from-TelemetryService.patch @@ -0,0 +1,26 @@ +From 71b55e9773c387d6510650e7cf64f050a853ac77 Mon Sep 17 00:00:00 2001 +From: Krzysztof Grobelny +Date: Tue, 30 Nov 2021 16:29:12 +0100 +Subject: [PATCH] Revert "Remove LogService from TelemetryService" + +This reverts commit 2b3da45876aac57a36d3093379a992d699e7e396. +--- + redfish-core/lib/telemetry_service.hpp | 2 + + 1 files changed, 2 insertions(+), 0 deletions(-) + +diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp +index b79a5cd..e3e4a25 100644 +--- a/redfish-core/lib/telemetry_service.hpp ++++ b/redfish-core/lib/telemetry_service.hpp +@@ -25,6 +25,8 @@ inline void handleTelemetryServiceGet( + "/redfish/v1/TelemetryService/MetricReports"; + asyncResp->res.jsonValue["Triggers"]["@odata.id"] = + "/redfish/v1/TelemetryService/Triggers"; ++ asyncResp->res.jsonValue["LogService"]["@odata.id"] = ++ "/redfish/v1/Managers/bmc/LogServices/Journal"; + + crow::connections::systemBus->async_method_call( + [asyncResp](const boost::system::error_code ec, +-- +2.25.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch deleted file mode 100644 index 3088a7f9d..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch +++ /dev/null @@ -1,295 +0,0 @@ -From 541353a4e4b06de42b6a9a400629f5a5fba04e86 Mon Sep 17 00:00:00 2001 -From: "Wludzik, Jozef" -Date: Tue, 15 Dec 2020 12:30:31 +0100 -Subject: [PATCH] Sync Telmetry service with EventService - -Synced the latest changes in Telemetry service with Event Service -code. Now assembling MetricReport is covered in single place in -code. Updated method of fetching Readings from Telemetry by -Event Service. Using ReportUpdate signal is no longer -supported. Now Event Service monitors for PropertiesChanged signal -from /xyz/openbmc_project/Telemetry/Reports path. - -Tested: - - Verified that EventListener received MetricReport response from - Event Service in insecure http push style eventing mode - -Change-Id: I2fc1841a6c9259a8bff30b34bddc0d4aabd41912 -Signed-off-by: Wludzik, Jozef -Signed-off-by: Lukasz Kazmierczak ---- - .../include/event_service_manager.hpp | 156 ++++++------------ - redfish-core/lib/metric_report.hpp | 28 ++-- - 2 files changed, 69 insertions(+), 115 deletions(-) - -diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index 3f398d7..cf9f658 100644 ---- a/redfish-core/include/event_service_manager.hpp -+++ b/redfish-core/include/event_service_manager.hpp -@@ -14,6 +14,7 @@ - // limitations under the License. - */ - #pragma once -+#include "metric_report.hpp" - #include "registries.hpp" - #include "registries/base_message_registry.hpp" - #include "registries/openbmc_message_registry.hpp" -@@ -511,47 +512,32 @@ class Subscription : public persistent_data::UserSubscription - } - #endif - -- void filterAndSendReports(const std::string& id2, -- const std::string& readingsTs, -- const ReadingsObjType& readings) -+ void filterAndSendReports( -+ const std::string& id, -+ const std::variant& var) - { -- std::string metricReportDef = -- "/redfish/v1/TelemetryService/MetricReportDefinitions/" + id2; -+ std::string mrdUri = telemetry::metricReportDefinitionUri + id; - - // Empty list means no filter. Send everything. - if (metricReportDefinitions.size()) - { - if (std::find(metricReportDefinitions.begin(), - metricReportDefinitions.end(), -- metricReportDef) == metricReportDefinitions.end()) -+ mrdUri) == metricReportDefinitions.end()) - { - return; - } - } - -- nlohmann::json metricValuesArray = nlohmann::json::array(); -- for (const auto& it : readings) -+ nlohmann::json msg; -+ if (!telemetry::fillReport(msg, id, var)) - { -- metricValuesArray.push_back({}); -- nlohmann::json& entry = metricValuesArray.back(); -- -- auto& [id, property, value, timestamp] = it; -- -- entry = {{"MetricId", id}, -- {"MetricProperty", property}, -- {"MetricValue", std::to_string(value)}, -- {"Timestamp", crow::utility::getDateTime(timestamp)}}; -+ BMCWEB_LOG_ERROR << "Failed to fill the MetricReport for DBus " -+ "Report with id " -+ << id; -+ return; - } - -- nlohmann::json msg = { -- {"@odata.id", "/redfish/v1/TelemetryService/MetricReports/" + id}, -- {"@odata.type", "#MetricReport.v1_3_0.MetricReport"}, -- {"Id", id2}, -- {"Name", id2}, -- {"Timestamp", readingsTs}, -- {"MetricReportDefinition", {{"@odata.id", metricReportDef}}}, -- {"MetricValues", metricValuesArray}}; -- - this->sendEvent( - msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace)); - } -@@ -1317,75 +1303,6 @@ class EventServiceManager - } - - #endif -- -- void getMetricReading(const std::string& service, -- const std::string& objPath, const std::string& intf) -- { -- std::size_t found = objPath.find_last_of('/'); -- if (found == std::string::npos) -- { -- BMCWEB_LOG_DEBUG << "Invalid objPath received"; -- return; -- } -- -- std::string idStr = objPath.substr(found + 1); -- if (idStr.empty()) -- { -- BMCWEB_LOG_DEBUG << "Invalid ID in objPath"; -- return; -- } -- -- crow::connections::systemBus->async_method_call( -- [idStr{std::move(idStr)}]( -- const boost::system::error_code ec, -- boost::container::flat_map< -- std::string, std::variant>& -- resp) { -- if (ec) -- { -- BMCWEB_LOG_DEBUG -- << "D-Bus call failed to GetAll metric readings."; -- return; -- } -- -- const int32_t* timestampPtr = -- std::get_if(&resp["Timestamp"]); -- if (!timestampPtr) -- { -- BMCWEB_LOG_DEBUG << "Failed to Get timestamp."; -- return; -- } -- -- ReadingsObjType* readingsPtr = -- std::get_if(&resp["Readings"]); -- if (!readingsPtr) -- { -- BMCWEB_LOG_DEBUG << "Failed to Get Readings property."; -- return; -- } -- -- if (!readingsPtr->size()) -- { -- BMCWEB_LOG_DEBUG << "No metrics report to be transferred"; -- return; -- } -- -- for (const auto& it : -- EventServiceManager::getInstance().subscriptionsMap) -- { -- std::shared_ptr entry = it.second; -- if (entry->eventFormatType == metricReportFormatType) -- { -- entry->filterAndSendReports( -- idStr, crow::utility::getDateTime(*timestampPtr), -- *readingsPtr); -- } -- } -- }, -- service, objPath, "org.freedesktop.DBus.Properties", "GetAll", -- intf); -- } -- - void unregisterMetricReportSignal() - { - if (matchTelemetryMonitor) -@@ -1405,9 +1322,11 @@ class EventServiceManager - } - - BMCWEB_LOG_DEBUG << "Metrics report signal - Register"; -- std::string matchStr( -- "type='signal',member='ReportUpdate', " -- "interface='xyz.openbmc_project.MonitoringService.Report'"); -+ std::string matchStr = "type='signal',member='PropertiesChanged'," -+ "interface='org.freedesktop.DBus.Properties'," -+ "path_namespace=/xyz/openbmc_project/Telemetry/" -+ "Reports/TelemetryService," -+ "arg0=xyz.openbmc_project.Telemetry.Report"; - - matchTelemetryMonitor = std::make_shared( - *crow::connections::systemBus, matchStr, -@@ -1418,10 +1337,43 @@ class EventServiceManager - return; - } - -- std::string service = msg.get_sender(); -- std::string objPath = msg.get_path(); -- std::string intf = msg.get_interface(); -- getMetricReading(service, objPath, intf); -+ sdbusplus::message::object_path path(msg.get_path()); -+ std::string id = path.filename(); -+ if (id.empty()) -+ { -+ BMCWEB_LOG_ERROR << "Failed to get Id from path"; -+ return; -+ } -+ -+ std::string intf; -+ std::vector>> -+ props; -+ std::vector invalidProps; -+ msg.read(intf, props, invalidProps); -+ -+ auto found = -+ std::find_if(props.begin(), props.end(), [](const auto& x) { -+ return x.first == "Readings"; -+ }); -+ if (found == props.end()) -+ { -+ BMCWEB_LOG_INFO -+ << "Failed to get Readings from Report properties"; -+ return; -+ } -+ -+ const std::variant& readings = -+ found->second; -+ for (const auto& it : -+ EventServiceManager::getInstance().subscriptionsMap) -+ { -+ Subscription& entry = *it.second.get(); -+ if (entry.eventFormatType == metricReportFormatType) -+ { -+ entry.filterAndSendReports(id, readings); -+ } -+ } - }); - } - -diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp -index 63c8c19..7fe281d 100644 ---- a/redfish-core/lib/metric_report.hpp -+++ b/redfish-core/lib/metric_report.hpp -@@ -33,16 +33,14 @@ inline nlohmann::json toMetricValues(const Readings& readings) - return metricValues; - } - --inline void fillReport(const std::shared_ptr& asyncResp, -- const std::string& id, -+inline bool fillReport(nlohmann::json& json, const std::string& id, - const std::variant& var) - { -- asyncResp->res.jsonValue["@odata.type"] = -- "#MetricReport.v1_3_0.MetricReport"; -- asyncResp->res.jsonValue["@odata.id"] = telemetry::metricReportUri + id; -- asyncResp->res.jsonValue["Id"] = id; -- asyncResp->res.jsonValue["Name"] = id; -- asyncResp->res.jsonValue["MetricReportDefinition"]["@odata.id"] = -+ json["@odata.type"] = "#MetricReport.v1_3_0.MetricReport"; -+ json["@odata.id"] = telemetry::metricReportUri + id; -+ json["Id"] = id; -+ json["Name"] = id; -+ json["MetricReportDefinition"]["@odata.id"] = - telemetry::metricReportDefinitionUri + id; - - const TimestampReadings* timestampReadings = -@@ -50,14 +48,14 @@ inline void fillReport(const std::shared_ptr& asyncResp, - if (!timestampReadings) - { - BMCWEB_LOG_ERROR << "Property type mismatch or property is missing"; -- messages::internalError(asyncResp->res); -- return; -+ return false; - } - - const auto& [timestamp, readings] = *timestampReadings; -- asyncResp->res.jsonValue["Timestamp"] = -+ json["Timestamp"] = - crow::utility::getDateTime(static_cast(timestamp)); -- asyncResp->res.jsonValue["MetricValues"] = toMetricValues(readings); -+ json["MetricValues"] = toMetricValues(readings); -+ return true; - } - } // namespace telemetry - -@@ -118,7 +116,11 @@ inline void requestRoutesMetricReport(App& app) - return; - } - -- telemetry::fillReport(asyncResp, id, ret); -+ if (!telemetry::fillReport( -+ asyncResp->res.jsonValue, id, ret)) -+ { -+ messages::internalError(asyncResp->res); -+ } - }, - telemetry::service, reportPath, - "org.freedesktop.DBus.Properties", "Get", --- -2.25.1 diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Switched-bmcweb-to-use-new-telemetry-service-API.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Switched-bmcweb-to-use-new-telemetry-service-API.patch index 5dd2f51bc..a71511a96 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Switched-bmcweb-to-use-new-telemetry-service-API.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Switched-bmcweb-to-use-new-telemetry-service-API.patch @@ -1,6 +1,6 @@ -From 8ba1bcc3503cafb33b1a06356d4f8f92ae23e39a Mon Sep 17 00:00:00 2001 +From 41ee20f46f2c6d2e9e5418128993cd176d03a927 Mon Sep 17 00:00:00 2001 From: Krzysztof Grobelny -Date: Thu, 17 Jun 2021 13:37:57 +0000 +Date: Wed, 5 Jan 2022 14:54:18 +0100 Subject: [PATCH] Switched bmcweb to use new telemetry service API Added support for multiple MetricProperties. Added support for new @@ -15,51 +15,66 @@ Tested: Change-Id: I2cd17069e3ea015c8f5571c29278f1d50536272a Signed-off-by: Krzysztof Grobelny +Signed-off-by: Lukasz Kazmierczak --- - redfish-core/lib/metric_report_definition.hpp | 212 ++++++++++-------- - 1 file changed, 114 insertions(+), 98 deletions(-) + include/dbus_utility.hpp | 5 +- + redfish-core/lib/metric_report_definition.hpp | 310 +++++++++++------- + 2 files changed, 189 insertions(+), 126 deletions(-) +diff --git a/include/dbus_utility.hpp b/include/dbus_utility.hpp +index a971325..35109c4 100644 +--- a/include/dbus_utility.hpp ++++ b/include/dbus_utility.hpp +@@ -51,8 +51,9 @@ using DbusVariantType = sdbusplus::utility::dedup_variant_t< + std::vector>, + std::vector>>, + std::vector>, +- std::vector> ++ std::vector>, ++ std::string, std::string, std::string, uint64_t>> + >; + + // clang-format on diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp -index a0c4f1d..7c26787 100644 +index 2584afc..9512381 100644 --- a/redfish-core/lib/metric_report_definition.hpp +++ b/redfish-core/lib/metric_report_definition.hpp -@@ -7,6 +7,8 @@ - #include +@@ -8,6 +8,8 @@ #include + #include #include +#include +#include #include #include -@@ -17,87 +19,90 @@ namespace redfish +@@ -18,119 +20,156 @@ namespace redfish namespace telemetry { -using ReadingParameters = - std::vector>; -+using ReadingParameters = std::vector< -+ std::tuple, std::string, -+ std::string, std::string, std::string, uint64_t>>; ++using ReadingParameters = std::vector>, ++ std::string, std::string, std::string, uint64_t>>; - inline void fillReportDefinition( - const std::shared_ptr& asyncResp, const std::string& id, - const std::vector< -- std::pair>>& ret) -+ std::pair>>& -+ properties) +-inline void fillReportDefinition( +- const std::shared_ptr& asyncResp, const std::string& id, +- const std::vector>& +- ret) ++std::string toReadfishReportAction(std::string_view action) { - asyncResp->res.jsonValue["@odata.type"] = - "#MetricReportDefinition.v1_3_0.MetricReportDefinition"; - asyncResp->res.jsonValue["@odata.id"] = -- telemetry::metricReportDefinitionUri + id; +- telemetry::metricReportDefinitionUri + std::string("/") + id; - asyncResp->res.jsonValue["Id"] = id; - asyncResp->res.jsonValue["Name"] = id; - asyncResp->res.jsonValue["MetricReport"]["@odata.id"] = -- telemetry::metricReportUri + id; +- telemetry::metricReportUri + std::string("/") + id; - asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; - asyncResp->res.jsonValue["ReportUpdates"] = "Overwrite"; - @@ -69,34 +84,16 @@ index a0c4f1d..7c26787 100644 - const std::string* reportingType = nullptr; - const uint64_t* interval = nullptr; - for (const auto& [key, var] : ret) -+ try ++ if (action == "EmitsReadingsUpdate") { - if (key == "EmitsReadingsUpdate") -+ bool emitsReadingsUpdate = false; -+ bool logToMetricReportsCollection = false; -+ ReadingParameters readingParams; -+ std::string reportingType; -+ uint64_t interval = 0u; -+ -+ sdbusplus::unpackProperties( -+ properties, "EmitsReadingsUpdate", emitsReadingsUpdate, -+ "LogToMetricReportsCollection", logToMetricReportsCollection, -+ "ReadingParametersFutureVersion", readingParams, "ReportingType", -+ reportingType, "Interval", interval); -+ -+ std::vector redfishReportActions; -+ redfishReportActions.reserve(2); -+ if (emitsReadingsUpdate) - { +- { - emitsReadingsUpdate = std::get_if(&var); -+ redfishReportActions.emplace_back("RedfishEvent"); - } +- } - else if (key == "LogToMetricReportsCollection") -+ if (logToMetricReportsCollection) - { +- { - logToMetricReportsCollection = std::get_if(&var); -+ redfishReportActions.emplace_back("LogToMetricReportsCollection"); - } +- } - else if (key == "ReadingParameters") - { - readingParams = std::get_if(&var); @@ -106,76 +103,126 @@ index a0c4f1d..7c26787 100644 - reportingType = std::get_if(&var); - } - else if (key == "Interval") -+ -+ nlohmann::json metrics = nlohmann::json::array(); -+ for (auto& [sensorPath, operationType, id, metadata, -+ collectionTimeScope, collectionDuration] : readingParams) - { +- { - interval = std::get_if(&var); -+ std::vector metricProperties; -+ -+ nlohmann::json parsedMetadata = nlohmann::json::parse(metadata); -+ if (!json_util::readJson(parsedMetadata, asyncResp->res, -+ "MetricProperties", metricProperties)) -+ { -+ BMCWEB_LOG_ERROR << "Failed to read metadata"; -+ messages::internalError(asyncResp->res); -+ return; -+ } -+ -+ metrics.push_back({ -+ {"MetricId", id}, -+ {"MetricProperties", std::move(metricProperties)}, -+ }); - } -- } +- } ++ return "RedfishEvent"; + } - if (!emitsReadingsUpdate || !logToMetricReportsCollection || - !readingParams || !reportingType || !interval) -- { ++ if (action == "LogToMetricReportsCollection") + { - BMCWEB_LOG_ERROR << "Property type mismatch or property is missing"; - messages::internalError(asyncResp->res); - return; -- } ++ return "LogToMetricReportsCollection"; + } ++ return ""; ++} - std::vector redfishReportActions; - redfishReportActions.reserve(2); - if (*emitsReadingsUpdate) -- { ++std::string toDbusReportAction(std::string_view action) ++{ ++ if (action == "RedfishEvent") + { - redfishReportActions.emplace_back("RedfishEvent"); ++ return "EmitsReadingsUpdate"; + } +- if (*logToMetricReportsCollection) ++ if (action == "LogToMetricReportsCollection") + { +- redfishReportActions.emplace_back("LogToMetricReportsCollection"); ++ return "LogToMetricReportsCollection"; + } ++ return ""; ++} + +- nlohmann::json metrics = nlohmann::json::array(); +- for (auto& [sensorPath, operationType, id, metadata] : *readingParams) ++inline void fillReportDefinition( ++ const std::shared_ptr& asyncResp, const std::string& id, ++ const std::vector>& ++ properties) ++{ ++ try + { +- metrics.push_back({ +- {"MetricId", id}, +- {"MetricProperties", {metadata}}, +- }); ++ std::vector reportActions; ++ ReadingParameters readingParams; ++ std::string reportingType; ++ std::string reportUpdates; ++ std::string name; ++ uint64_t appendLimit = 0u; ++ uint64_t interval = 0u; ++ ++ sdbusplus::unpackProperties( ++ properties, "ReportActions", reportActions, "ReportUpdates", ++ reportUpdates, "AppendLimit", appendLimit, ++ "ReadingParametersFutureVersion", readingParams, "ReportingType", ++ reportingType, "Interval", interval, "Name", name); ++ ++ for (std::string& action : reportActions) ++ { ++ action = toReadfishReportAction(action); ++ ++ if (action.empty()) ++ { ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ } ++ ++ nlohmann::json metrics = nlohmann::json::array(); ++ for (auto& [sensorData, collectionFunction, id, collectionTimeScope, ++ collectionDuration] : readingParams) ++ { ++ std::vector metricProperties; ++ ++ for (auto& [sensorPath, sensorMetadata] : sensorData) ++ { ++ metricProperties.emplace_back(std::move(sensorMetadata)); ++ } ++ ++ metrics.push_back( ++ {{"MetricId", std::move(id)}, ++ {"MetricProperties", std::move(metricProperties)}, ++ {"CollectionFunction", std::move(collectionFunction)}, ++ {"CollectionDuration", ++ time_utils::toDurationString( ++ std::chrono::milliseconds(collectionDuration))}, ++ {"CollectionTimeScope", std::move(collectionTimeScope)}}); ++ } ++ + asyncResp->res.jsonValue["@odata.type"] = + "#MetricReportDefinition.v1_3_0.MetricReportDefinition"; + asyncResp->res.jsonValue["@odata.id"] = -+ telemetry::metricReportDefinitionUri + id; ++ telemetry::metricReportDefinitionUri + std::string("/") + id; + asyncResp->res.jsonValue["Id"] = id; -+ asyncResp->res.jsonValue["Name"] = id; ++ asyncResp->res.jsonValue["Name"] = name; + asyncResp->res.jsonValue["MetricReport"]["@odata.id"] = -+ telemetry::metricReportUri + id; ++ telemetry::metricReportUri + std::string("/") + id; + asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; -+ asyncResp->res.jsonValue["ReportUpdates"] = "Overwrite"; ++ asyncResp->res.jsonValue["ReportUpdates"] = reportUpdates; ++ asyncResp->res.jsonValue["AppendLimit"] = appendLimit; + asyncResp->res.jsonValue["Metrics"] = metrics; + asyncResp->res.jsonValue["MetricReportDefinitionType"] = reportingType; -+ asyncResp->res.jsonValue["ReportActions"] = redfishReportActions; ++ asyncResp->res.jsonValue["ReportActions"] = reportActions; + asyncResp->res.jsonValue["Schedule"]["RecurrenceInterval"] = + time_utils::toDurationString(std::chrono::milliseconds(interval)); - } -- if (*logToMetricReportsCollection) ++ } + catch (const sdbusplus::exception::UnpackPropertyError& error) - { -- redfishReportActions.emplace_back("LogToMetricReportsCollection"); ++ { + BMCWEB_LOG_ERROR << error.what() << ", property: " + << error.propertyName + ", reason: " << error.reason; -+ messages::internalError(asyncResp->res); - } -- -- nlohmann::json metrics = nlohmann::json::array(); -- for (auto& [sensorPath, operationType, id, metadata] : *readingParams) -+ catch (const nlohmann::json::parse_error& e) - { -- metrics.push_back({ -- {"MetricId", id}, -- {"MetricProperties", {metadata}}, -- }); -+ BMCWEB_LOG_ERROR << "Failed to parse metadata: " << e.what(); ++ messages::queryParameterValueFormatError( ++ asyncResp->res, ++ std::string(error.propertyName) + " " + std::string(error.reason), ++ error.what()); + messages::internalError(asyncResp->res); } - asyncResp->res.jsonValue["Metrics"] = metrics; @@ -186,33 +233,196 @@ index a0c4f1d..7c26787 100644 } struct AddReportArgs -@@ -275,6 +280,11 @@ class AddReport + { +- std::string name; ++ struct MetricArgs ++ { ++ std::string id; ++ std::vector uris; ++ std::optional collectionFunction; ++ std::optional collectionTimeScope; ++ std::optional collectionDuration; ++ }; ++ ++ std::optional id; ++ std::optional name; + std::string reportingType; +- bool emitsReadingsUpdate = false; +- bool logToMetricReportsCollection = false; ++ std::optional reportUpdates; ++ std::optional appendLimit; ++ std::vector reportActions; + uint64_t interval = 0; +- std::vector>> metrics; ++ std::vector metrics; + }; - for (const auto& [id, uris] : args.metrics) + inline bool toDbusReportActions(crow::Response& res, +- std::vector& actions, ++ const std::vector& actions, + AddReportArgs& args) + { + size_t index = 0; +- for (auto& action : actions) ++ for (const auto& action : actions) + { +- if (action == "RedfishEvent") +- { +- args.emitsReadingsUpdate = true; +- } +- else if (action == "LogToMetricReportsCollection") +- { +- args.logToMetricReportsCollection = true; +- } +- else ++ std::string dbusReportAction = toDbusReportAction(action); ++ ++ if (dbusReportAction.empty()) { -+ std::vector dbusPaths; -+ dbusPaths.reserve(uris.size()); -+ nlohmann::json metadata; -+ metadata["MetricProperties"] = nlohmann::json::array(); + messages::propertyValueNotInList( + res, action, "ReportActions/" + std::to_string(index)); + return false; + } + - for (size_t i = 0; i < uris.size(); i++) ++ args.reportActions.emplace_back(std::move(dbusReportAction)); + index++; + } + return true; +@@ -142,23 +181,12 @@ inline bool getUserParameters(crow::Response& res, const crow::Request& req, + std::vector metrics; + std::vector reportActions; + std::optional schedule; +- if (!json_util::readJson(req, res, "Id", args.name, "Metrics", metrics, +- "MetricReportDefinitionType", args.reportingType, +- "ReportActions", reportActions, "Schedule", +- schedule)) +- { +- return false; +- } +- +- constexpr const char* allowedCharactersInName = +- "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_"; +- if (args.name.empty() || args.name.find_first_not_of( +- allowedCharactersInName) != std::string::npos) ++ if (!json_util::readJson( ++ req, res, "Id", args.id, "Name", args.name, "Metrics", metrics, ++ "MetricReportDefinitionType", args.reportingType, "ReportUpdates", ++ args.reportUpdates, "AppendLimit", args.appendLimit, ++ "ReportActions", reportActions, "Schedule", schedule)) + { +- BMCWEB_LOG_ERROR << "Failed to match " << args.name +- << " with allowed character " +- << allowedCharactersInName; +- messages::propertyValueIncorrect(res, "Id", args.name); + return false; + } + +@@ -203,15 +231,35 @@ inline bool getUserParameters(crow::Response& res, const crow::Request& req, + args.metrics.reserve(metrics.size()); + for (auto& m : metrics) + { +- std::string id; +- std::vector uris; +- if (!json_util::readJson(m, res, "MetricId", id, "MetricProperties", +- uris)) ++ std::optional collectionDurationStr; ++ AddReportArgs::MetricArgs metricArgs; ++ if (!json_util::readJson( ++ m, res, "MetricId", metricArgs.id, "MetricProperties", ++ metricArgs.uris, "CollectionFunction", ++ metricArgs.collectionFunction, "CollectionTimeScope", ++ metricArgs.collectionTimeScope, "CollectionDuration", ++ collectionDurationStr)) + { + return false; + } + +- args.metrics.emplace_back(std::move(id), std::move(uris)); ++ if (collectionDurationStr) ++ { ++ std::optional duration = ++ time_utils::fromDurationString(*collectionDurationStr); ++ ++ if (!duration || duration->count() < 0) ++ { ++ messages::propertyValueIncorrect(res, "CollectionDuration", ++ *collectionDurationStr); ++ return false; ++ } ++ ++ metricArgs.collectionDuration = ++ static_cast(duration->count()); ++ } ++ ++ args.metrics.emplace_back(std::move(metricArgs)); + } + + return true; +@@ -219,13 +267,12 @@ inline bool getUserParameters(crow::Response& res, const crow::Request& req, + + inline bool getChassisSensorNodeFromMetrics( + const std::shared_ptr& asyncResp, +- const std::vector>>& +- metrics, ++ const std::vector& metrics, + boost::container::flat_set>& matched) + { +- for (const auto& [id, uris] : metrics) ++ for (const auto& metric : metrics) + { +- if (!getChassisSensorNode(asyncResp, uris, matched)) ++ if (!getChassisSensorNode(asyncResp, metric.uris, matched)) + { + return false; + } +@@ -251,11 +298,16 @@ class AddReport + telemetry::ReadingParameters readingParams; + readingParams.reserve(args.metrics.size()); + +- for (const auto& [id, uris] : args.metrics) ++ for (auto& metric : args.metrics) + { +- for (size_t i = 0; i < uris.size(); i++) ++ std::vector< ++ std::tuple> ++ sensorParams; ++ sensorParams.reserve(metric.uris.size()); ++ ++ for (size_t i = 0; i < metric.uris.size(); i++) { - const std::string& uri = uris[i]; -@@ -291,8 +301,12 @@ class AddReport +- const std::string& uri = uris[i]; ++ const std::string& uri = metric.uris[i]; + auto el = uriToDbus.find(uri); + if (el == uriToDbus.end()) + { +@@ -269,17 +321,23 @@ class AddReport } const std::string& dbusPath = el->second; - readingParams.emplace_back(dbusPath, "SINGLE", id, uri); -+ dbusPaths.emplace_back(dbusPath); -+ metadata["MetricProperties"].emplace_back(uri); ++ sensorParams.emplace_back(dbusPath, uri); } + -+ readingParams.emplace_back(dbusPaths, "SINGLE", id, metadata.dump(), -+ "Point", 0u); ++ readingParams.emplace_back( ++ std::move(sensorParams), metric.collectionFunction.value_or(""), ++ std::move(metric.id), metric.collectionTimeScope.value_or(""), ++ metric.collectionDuration.value_or(0u)); } const std::shared_ptr aResp = asyncResp; crow::connections::systemBus->async_method_call( -@@ -330,10 +344,10 @@ class AddReport +- [aResp, name = args.name, uriToDbus = std::move(uriToDbus)]( ++ [aResp, id = args.id.value_or(""), ++ uriToDbus = std::move(uriToDbus)]( + const boost::system::error_code ec, const std::string&) { + if (ec == boost::system::errc::file_exists) + { + messages::resourceAlreadyExists( +- aResp->res, "MetricReportDefinition", "Id", name); ++ aResp->res, "MetricReportDefinition", "Id", id); + return; + } + if (ec == boost::system::errc::too_many_files_open) +@@ -308,10 +366,12 @@ class AddReport messages::created(aResp->res); }, telemetry::service, "/xyz/openbmc_project/Telemetry/Reports", @@ -221,81 +431,50 @@ index a0c4f1d..7c26787 100644 - args.emitsReadingsUpdate, args.logToMetricReportsCollection, - args.interval, readingParams); + "xyz.openbmc_project.Telemetry.ReportManager", -+ "AddReportFutureVersion", "TelemetryService/" + args.name, -+ args.reportingType, args.emitsReadingsUpdate, -+ args.logToMetricReportsCollection, args.interval, readingParams); ++ "AddReportFutureVersion", ++ "TelemetryService/" + args.id.value_or(""), args.name.value_or(""), ++ args.reportingType, args.reportUpdates.value_or("Overwrite"), ++ args.appendLimit.value_or(0), args.reportActions, args.interval, ++ readingParams); } void insert(const boost::container::flat_map& el) -@@ -415,37 +429,39 @@ inline void requestRoutesMetricReportDefinition(App& app) - BMCWEB_ROUTE(app, - "/redfish/v1/TelemetryService/MetricReportDefinitions//") - .privileges(redfish::privileges::getMetricReportDefinition) -- .methods(boost::beast::http::verb::get)( -- [](const crow::Request&, -- const std::shared_ptr& asyncResp, -- const std::string& id) { +@@ -399,12 +459,15 @@ inline void requestRoutesMetricReportDefinition(App& app) + [](const crow::Request&, + const std::shared_ptr& asyncResp, + const std::string& id) { - crow::connections::systemBus->async_method_call( -- [asyncResp, id]( -- const boost::system::error_code ec, -- const std::vector>>& ret) { -- if (ec.value() == EBADR || -- ec == boost::system::errc::host_unreachable) -- { -- messages::resourceNotFound( -- asyncResp->res, "MetricReportDefinition", id); -- return; -- } -- if (ec) -- { -- BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; -- messages::internalError(asyncResp->res); -- return; -- } -+ .methods( -+ boost::beast::http::verb::get)([](const crow::Request&, -+ const std::shared_ptr< -+ bmcweb::AsyncResp>& asyncResp, -+ const std::string& id) { -+ sdbusplus::asio::getAllProperties( -+ *crow::connections::systemBus, telemetry::service, -+ telemetry::getDbusReportPath(id), telemetry::reportInterface, -+ [asyncResp, -+ id](boost::system::error_code ec, -+ const std::vector>>& -+ properties) { -+ if (ec.value() == EBADR || -+ ec == boost::system::errc::host_unreachable) -+ { -+ messages::resourceNotFound( -+ asyncResp->res, "MetricReportDefinition", id); -+ return; -+ } -+ if (ec) -+ { -+ BMCWEB_LOG_ERROR << "respHandler DBus error " << ec; -+ messages::internalError(asyncResp->res); -+ return; -+ } -+ -+ telemetry::fillReportDefinition(asyncResp, id, properties); -+ }); -+ }); ++ sdbusplus::asio::getAllProperties( ++ *crow::connections::systemBus, telemetry::service, ++ telemetry::getDbusReportPath(id), ++ telemetry::reportInterface, + [asyncResp, +- id](const boost::system::error_code ec, ++ id](boost::system::error_code ec, + const std::vector>& +- ret) { ++ properties) { + if (ec.value() == EBADR || + ec == boost::system::errc::host_unreachable) + { +@@ -419,12 +482,11 @@ inline void requestRoutesMetricReportDefinition(App& app) + return; + } - telemetry::fillReportDefinition(asyncResp, id, ret); - }, - telemetry::service, telemetry::getDbusReportPath(id), - "org.freedesktop.DBus.Properties", "GetAll", - telemetry::reportInterface); -- }); ++ telemetry::fillReportDefinition(asyncResp, id, ++ properties); ++ }); + }); ++ BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions//") .privileges(redfish::privileges::deleteMetricReportDefinitionCollection) -- 2.25.1 + diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-MetricDefinition-property-in-MetricReport.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-MetricDefinition-property-in-MetricReport.patch deleted file mode 100644 index bf5a09d9d..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-MetricDefinition-property-in-MetricReport.patch +++ /dev/null @@ -1,268 +0,0 @@ -From dab3c96f9e39a89d7c359e22655650c7c16952ec Mon Sep 17 00:00:00 2001 -From: Krzysztof Grobelny -Date: Tue, 12 Oct 2021 08:06:13 +0000 -Subject: [PATCH] Add support for MetricDefinition property in MetricReport - -Added MetricDefinition as part of MetricValues array returned by -MetricReport. It contains single @odata.id with URI to proper -MetricDefinition resource - depending on MetricProperty. - -Testing done: -- GET request on redfish/v1/TelemetryService/MetricReports - got response with MetricDefinition and proper id inside - MetricValues array. - -Testing steps: -1. POST on redfish/v1/TelemetryService/MetricReportDefinitions - with body: -{ - "Id": "PeriodicReport_1", - "MetricReportDefinitionType": "Periodic", - "ReportActions": [ - "LogToMetricReportsCollection", - "RedfishEvent" - ], - "Metrics": [ - { - "MetricId": "sensor_1", - "MetricProperties": [ - "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/1/Reading" - ] - } - ], - "Schedule": { - "RecurrenceInterval": "PT10S" - } -} - -2. GET on redfish/v1/TelemetryService/MetricReports/PeriodicReport_1 - should return: -{ - "@odata.id": - "/redfish/v1/TelemetryService/MetricReports/PeriodicReport_1", - "@odata.type": "#MetricReport.v1_3_0.MetricReport", - "Id": "PeriodicReport_1", - "MetricReportDefinition": { - "@odata.id": - "/redfish/v1/TelemetryService/MetricReportDefinitions/PeriodicReport_1" - }, - "MetricValues": [ - { - "MetricDefinition": { - "@odata.id": - "/redfish/v1/TelemetryService/MetricDefinitions/Rotational" - }, - "MetricId": "sensor_1", - "MetricProperty": - "/redfish/v1/Chassis/AC_Baseboard/Thermal#/Fans/1/Reading", - "MetricValue": "nan", - "Timestamp": "1970-01-01T00:03:21+00:00" - } - ], - "Name": "PeriodicReport_1", - "Timestamp": "1970-01-01T00:03:21+00:00" -} - -Change-Id: I7181c612f9b443015d551259bae25303aa436822 -Signed-off-by: Szymon Dompke ---- - meson.build | 4 +- - .../include/utils/telemetry_utils.hpp | 40 ++++++++++++ - redfish-core/lib/metric_report.hpp | 64 +++++++++++++++---- - redfish-core/lib/sensors.hpp | 2 + - 4 files changed, 95 insertions(+), 15 deletions(-) - -diff --git a/meson.build b/meson.build -index 6b6a8ab..218ea49 100644 ---- a/meson.build -+++ b/meson.build -@@ -377,6 +377,8 @@ srcfiles_unittest = [ - 'http/ut/utility_test.cpp' - ] - -+srcfiles_unittest_dependencies = ['redfish-core/src/error_messages.cpp', 'src/boost_url.cpp'] -+ - # Gather the Configuration data - - conf_data = configuration_data() -@@ -434,7 +436,7 @@ executable('bmcweb',srcfiles_bmcweb, - if(get_option('tests').enabled()) - foreach src_test : srcfiles_unittest - testname = src_test.split('/')[-1].split('.')[0] -- test(testname,executable(testname,src_test, -+ test(testname,executable(testname,[src_test] + srcfiles_unittest_dependencies, - include_directories : incdir, - install_dir: bindir, - dependencies: [ -diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp -index 1b4f75d..c0c5ba3 100644 ---- a/redfish-core/include/utils/telemetry_utils.hpp -+++ b/redfish-core/include/utils/telemetry_utils.hpp -@@ -17,6 +17,46 @@ constexpr const char* metricReportDefinitionUri = - constexpr const char* metricReportUri = - "/redfish/v1/TelemetryService/MetricReports/"; - -+inline std::optional -+ getMetadataJson(const std::string& metadataStr) -+{ -+ std::optional res = -+ nlohmann::json::parse(metadataStr, nullptr, false); -+ if (res->is_discarded()) -+ { -+ BMCWEB_LOG_ERROR << "Malformed reading metatadata JSON provided by " -+ "telemetry service."; -+ return std::nullopt; -+ } -+ return res; -+} -+ -+inline std::optional -+ readStringFromMetadata(const nlohmann::json& metadataJson, const char* key) -+{ -+ std::optional res; -+ if (auto it = metadataJson.find(key); it != metadataJson.end()) -+ { -+ if (const std::string* value = it->get_ptr()) -+ { -+ res = *value; -+ } -+ else -+ { -+ BMCWEB_LOG_ERROR << "Incorrect reading metatadata JSON provided by " -+ "telemetry service. Missing key '" -+ << key << "'."; -+ } -+ } -+ else -+ { -+ BMCWEB_LOG_ERROR << "Incorrect reading metatadata JSON provided by " -+ "telemetry service. Key '" -+ << key << "' has a wrong type."; -+ } -+ return res; -+} -+ - inline void - getReportCollection(const std::shared_ptr& asyncResp, - const std::string& uri) -diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp -index 7fe281d..13bf792 100644 ---- a/redfish-core/lib/metric_report.hpp -+++ b/redfish-core/lib/metric_report.hpp -@@ -1,5 +1,6 @@ - #pragma once - -+#include "sensors.hpp" - #include "utils/telemetry_utils.hpp" - - #include -@@ -15,34 +16,56 @@ using Readings = - std::vector>; - using TimestampReadings = std::tuple; - --inline nlohmann::json toMetricValues(const Readings& readings) -+inline bool fillMetricValues(nlohmann::json& metricValues, -+ const Readings& readings) - { -- nlohmann::json metricValues = nlohmann::json::array_t(); -- -- for (auto& [id, metadata, sensorValue, timestamp] : readings) -+ for (auto& [id, metadataStr, sensorValue, timestamp] : readings) - { -+ std::optional readingMetadataJson = -+ getMetadataJson(metadataStr); -+ if (!readingMetadataJson) -+ { -+ return false; -+ } -+ -+ std::optional sensorDbusPath = -+ readStringFromMetadata(*readingMetadataJson, "SensorDbusPath"); -+ if (!sensorDbusPath) -+ { -+ return false; -+ } -+ -+ std::optional sensorRedfishUri = -+ readStringFromMetadata(*readingMetadataJson, "SensorRedfishUri"); -+ if (!sensorRedfishUri) -+ { -+ return false; -+ } -+ -+ std::string metricDefinition = -+ std::string(metricDefinitionUri) + -+ sensors::toReadingType( -+ sdbusplus::message::object_path(*sensorDbusPath) -+ .parent_path() -+ .filename()); -+ - metricValues.push_back({ -+ {"MetricDefinition", -+ nlohmann::json{{"@odata.id", metricDefinition}}}, - {"MetricId", id}, -- {"MetricProperty", metadata}, -+ {"MetricProperty", *sensorRedfishUri}, - {"MetricValue", std::to_string(sensorValue)}, - {"Timestamp", - crow::utility::getDateTime(static_cast(timestamp))}, - }); - } - -- return metricValues; -+ return true; - } - - inline bool fillReport(nlohmann::json& json, const std::string& id, - const std::variant& var) - { -- json["@odata.type"] = "#MetricReport.v1_3_0.MetricReport"; -- json["@odata.id"] = telemetry::metricReportUri + id; -- json["Id"] = id; -- json["Name"] = id; -- json["MetricReportDefinition"]["@odata.id"] = -- telemetry::metricReportDefinitionUri + id; -- - const TimestampReadings* timestampReadings = - std::get_if(&var); - if (!timestampReadings) -@@ -52,9 +75,22 @@ inline bool fillReport(nlohmann::json& json, const std::string& id, - } - - const auto& [timestamp, readings] = *timestampReadings; -+ nlohmann::json metricValues = nlohmann::json::array(); -+ if (!fillMetricValues(metricValues, readings)) -+ { -+ return false; -+ } -+ -+ json["@odata.type"] = "#MetricReport.v1_3_0.MetricReport"; -+ json["@odata.id"] = telemetry::metricReportUri + id; -+ json["Id"] = id; -+ json["Name"] = id; -+ json["MetricReportDefinition"]["@odata.id"] = -+ telemetry::metricReportDefinitionUri + id; - json["Timestamp"] = - crow::utility::getDateTime(static_cast(timestamp)); -- json["MetricValues"] = toMetricValues(readings); -+ json["MetricValues"] = metricValues; -+ - return true; - } - } // namespace telemetry -diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp -index 7405e5a..9850b24 100644 ---- a/redfish-core/lib/sensors.hpp -+++ b/redfish-core/lib/sensors.hpp -@@ -21,6 +21,8 @@ - #include - #include - #include -+#include -+#include - #include - #include - --- -2.25.1 - diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-GET-method-for-TriggerCollection.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-GET-method-for-TriggerCollection.patch deleted file mode 100644 index 0646aba5c..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-GET-method-for-TriggerCollection.patch +++ /dev/null @@ -1,313 +0,0 @@ -From a1e89d356ba5ed594a1494efe8257946e1062396 Mon Sep 17 00:00:00 2001 -From: Lukasz Kazmierczak -Date: Tue, 31 Aug 2021 14:35:31 +0200 -Subject: [PATCH] Add GET method for TriggerCollection - -Added GET method for retrieving list of Triggers from Telemetry service - -Tested: -- Added single Trigger and requested result from bmcweb via - /redfish/v1/TelemetryService/Triggers -- Added multiple Triggers numeric and discrete, and requested results - from bmcweb via /redfish/v1/TelemetryService/Triggers -- Verified uri /redfish/v1/TelemetryService/Triggers by using - Redfish-Service-Validator (all passed) - -Signed-off-by: Lukasz Kazmierczak -Change-Id: Ide00eb44901ea1b97b80fc5c5ddfd97e393d4a04 ---- - redfish-core/include/redfish.hpp | 2 + - .../include/utils/telemetry_utils.hpp | 40 ++++++++--- - redfish-core/lib/metric_report.hpp | 6 +- - redfish-core/lib/metric_report_definition.hpp | 6 +- - redfish-core/lib/trigger.hpp | 31 ++++++++ - scripts/update_schemas.py | 1 + - static/redfish/v1/$metadata/index.xml | 3 + - .../v1/schema/TriggersCollection_v1.xml | 70 +++++++++++++++++++ - 8 files changed, 144 insertions(+), 15 deletions(-) - create mode 100644 redfish-core/lib/trigger.hpp - create mode 100644 static/redfish/v1/schema/TriggersCollection_v1.xml - -diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp -index 9fb0ffe..99b3fe6 100644 ---- a/redfish-core/include/redfish.hpp -+++ b/redfish-core/include/redfish.hpp -@@ -42,6 +42,7 @@ - #include "../lib/task.hpp" - #include "../lib/telemetry_service.hpp" - #include "../lib/thermal.hpp" -+#include "../lib/trigger.hpp" - #include "../lib/update_service.hpp" - #include "../lib/virtual_media.hpp" - -@@ -197,6 +198,7 @@ class RedfishService - - hypervisor::requestRoutesHypervisorSystems(app); - -+ requestRoutesTriggerCollection(app); - requestRoutesTelemetryService(app); - requestRoutesMetricReportDefinitionCollection(app); - requestRoutesMetricReportDefinition(app); -diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp -index c0c5ba3..df1aa68 100644 ---- a/redfish-core/include/utils/telemetry_utils.hpp -+++ b/redfish-core/include/utils/telemetry_utils.hpp -@@ -9,6 +9,8 @@ namespace telemetry - { - - constexpr const char* service = "xyz.openbmc_project.Telemetry"; -+constexpr const char* reportSubtree = -+ "/xyz/openbmc_project/Telemetry/Reports/TelemetryService"; - constexpr const char* reportInterface = "xyz.openbmc_project.Telemetry.Report"; - constexpr const char* metricDefinitionUri = - "/redfish/v1/TelemetryService/MetricDefinitions/"; -@@ -16,6 +18,11 @@ constexpr const char* metricReportDefinitionUri = - "/redfish/v1/TelemetryService/MetricReportDefinitions/"; - constexpr const char* metricReportUri = - "/redfish/v1/TelemetryService/MetricReports/"; -+constexpr const char* triggerSubtree = -+ "/xyz/openbmc_project/Telemetry/Triggers/TelemetryService"; -+constexpr const char* triggerInterface = -+ "xyz.openbmc_project.Telemetry.Trigger"; -+constexpr const char* triggerUri = "/redfish/v1/TelemetryService/Triggers/"; - - inline std::optional - getMetadataJson(const std::string& metadataStr) -@@ -57,15 +64,27 @@ inline std::optional - return res; - } - --inline void -- getReportCollection(const std::shared_ptr& asyncResp, -- const std::string& uri) -+struct CollectionParams - { -- const std::array interfaces = {reportInterface}; -+ const char* subtree; -+ int depth; -+ std::array interfaces; - -+ CollectionParams() = delete; -+ CollectionParams(const char* st, int dp, -+ const std::array& ifaces) : -+ subtree{st}, -+ depth{dp}, interfaces{ifaces} -+ {} -+}; -+ -+inline void getCollection(const std::shared_ptr& asyncResp, -+ const std::string& uri, -+ const CollectionParams& params) -+{ - crow::connections::systemBus->async_method_call( - [asyncResp, uri](const boost::system::error_code ec, -- const std::vector& reports) { -+ const std::vector& items) { - if (ec == boost::system::errc::io_error) - { - asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); -@@ -82,13 +101,13 @@ inline void - nlohmann::json& members = asyncResp->res.jsonValue["Members"]; - members = nlohmann::json::array(); - -- for (const std::string& report : reports) -+ for (const std::string& item : items) - { -- sdbusplus::message::object_path path(report); -+ sdbusplus::message::object_path path(item); - std::string name = path.filename(); - if (name.empty()) - { -- BMCWEB_LOG_ERROR << "Received invalid path: " << report; -+ BMCWEB_LOG_ERROR << "Received invalid path: " << item; - messages::internalError(asyncResp->res); - return; - } -@@ -99,9 +118,8 @@ inline void - }, - "xyz.openbmc_project.ObjectMapper", - "/xyz/openbmc_project/object_mapper", -- "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", -- "/xyz/openbmc_project/Telemetry/Reports/TelemetryService", 1, -- interfaces); -+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", params.subtree, -+ params.depth, params.interfaces); - } - - inline std::string getDbusReportPath(const std::string& id) -diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp -index 13bf792..ea4cd62 100644 ---- a/redfish-core/lib/metric_report.hpp -+++ b/redfish-core/lib/metric_report.hpp -@@ -108,8 +108,10 @@ inline void requestRoutesMetricReportCollection(App& app) - "/redfish/v1/TelemetryService/MetricReports"; - asyncResp->res.jsonValue["Name"] = "Metric Report Collection"; - -- telemetry::getReportCollection(asyncResp, -- telemetry::metricReportUri); -+ telemetry::getCollection( -+ asyncResp, telemetry::metricReportUri, -+ telemetry::CollectionParams(telemetry::reportSubtree, 1, -+ {telemetry::reportInterface})); - }); - } - -diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp -index 7c26787..c97a1df 100644 ---- a/redfish-core/lib/metric_report_definition.hpp -+++ b/redfish-core/lib/metric_report_definition.hpp -@@ -377,8 +377,10 @@ inline void requestRoutesMetricReportDefinitionCollection(App& app) - asyncResp->res.jsonValue["Name"] = - "Metric Definition Collection"; - -- telemetry::getReportCollection( -- asyncResp, telemetry::metricReportDefinitionUri); -+ telemetry::getCollection( -+ asyncResp, telemetry::metricReportDefinitionUri, -+ telemetry::CollectionParams(telemetry::reportSubtree, 1, -+ {telemetry::reportInterface})); - }); - - BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/") -diff --git a/redfish-core/lib/trigger.hpp b/redfish-core/lib/trigger.hpp -new file mode 100644 -index 0000000..681b3b4 ---- /dev/null -+++ b/redfish-core/lib/trigger.hpp -@@ -0,0 +1,31 @@ -+#pragma once -+ -+#include "utils/telemetry_utils.hpp" -+ -+#include -+#include -+ -+namespace redfish -+{ -+ -+inline void requestRoutesTriggerCollection(App& app) -+{ -+ BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/Triggers/") -+ .privileges(redfish::privileges::getTriggersCollection) -+ .methods(boost::beast::http::verb::get)( -+ [](const crow::Request&, -+ const std::shared_ptr& asyncResp) { -+ asyncResp->res.jsonValue["@odata.type"] = -+ "#TriggersCollection.TriggersCollection"; -+ asyncResp->res.jsonValue["@odata.id"] = -+ "/redfish/v1/TelemetryService/Triggers"; -+ asyncResp->res.jsonValue["Name"] = "Triggers Collection"; -+ -+ telemetry::getCollection( -+ asyncResp, telemetry::triggerUri, -+ telemetry::CollectionParams(telemetry::triggerSubtree, 1, -+ {telemetry::triggerInterface})); -+ }); -+} -+ -+} // namespace redfish -diff --git a/scripts/update_schemas.py b/scripts/update_schemas.py -index dd39278..d66a59a 100755 ---- a/scripts/update_schemas.py -+++ b/scripts/update_schemas.py -@@ -93,6 +93,7 @@ include_list = [ - 'TaskService', - 'TelemetryService', - 'Thermal', -+ 'TriggersCollection', - 'UpdateService', - 'VLanNetworkInterfaceCollection', - 'VLanNetworkInterface', -diff --git a/static/redfish/v1/$metadata/index.xml b/static/redfish/v1/$metadata/index.xml -index 876ebfb..75e3dd4 100644 ---- a/static/redfish/v1/$metadata/index.xml -+++ b/static/redfish/v1/$metadata/index.xml -@@ -2215,6 +2215,9 @@ - - - -+ -+ -+ - - - -diff --git a/static/redfish/v1/schema/TriggersCollection_v1.xml b/static/redfish/v1/schema/TriggersCollection_v1.xml -new file mode 100644 -index 0000000..399bebd ---- /dev/null -+++ b/static/redfish/v1/schema/TriggersCollection_v1.xml -@@ -0,0 +1,70 @@ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ /redfish/v1/TelemetryService/Triggers -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ --- -2.25.1 - diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Revert-Remove-LogService-from-TelemetryService.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Revert-Remove-LogService-from-TelemetryService.patch deleted file mode 100644 index a80ac61c7..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Revert-Remove-LogService-from-TelemetryService.patch +++ /dev/null @@ -1,26 +0,0 @@ -From da575aaf0bdcb15be261d58314cf7bbbcd92dd74 Mon Sep 17 00:00:00 2001 -From: Krzysztof Grobelny -Date: Tue, 12 Oct 2021 08:08:06 +0000 -Subject: [PATCH] Revert "Remove LogService from TelemetryService" - -This reverts commit 2b3da45876aac57a36d3093379a992d699e7e396. ---- - redfish-core/lib/telemetry_service.hpp | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp -index 027b51b..49471fe 100644 ---- a/redfish-core/lib/telemetry_service.hpp -+++ b/redfish-core/lib/telemetry_service.hpp -@@ -24,6 +24,8 @@ inline void handleTelemetryServiceGet( - "/redfish/v1/TelemetryService/MetricReports"; - asyncResp->res.jsonValue["MetricDefinitions"]["@odata.id"] = - "/redfish/v1/TelemetryService/MetricDefinitions"; -+ asyncResp->res.jsonValue["LogService"]["@odata.id"] = -+ "/redfish/v1/Managers/bmc/LogServices/Journal"; - - crow::connections::systemBus->async_method_call( - [asyncResp](const boost::system::error_code ec, --- -2.25.1 - diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0007-event-service-fix-added-Context-field-to-response.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0007-event-service-fix-added-Context-field-to-response.patch deleted file mode 100644 index ffab743f6..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0007-event-service-fix-added-Context-field-to-response.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 0ca8c383db8c9afbce63380955a20ada0acc20b7 Mon Sep 17 00:00:00 2001 -From: Krzysztof Grobelny -Date: Wed, 2 Jun 2021 12:44:43 +0000 -Subject: [PATCH] event service fix, added Context field to response - -Tested: - - Context field is present - - No regression detected - -Signed-off-by: Krzysztof Grobelny ---- - redfish-core/include/event_service_manager.hpp | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index 2b957ea..289886b 100644 ---- a/redfish-core/include/event_service_manager.hpp -+++ b/redfish-core/include/event_service_manager.hpp -@@ -556,6 +556,7 @@ class Subscription - << id; - return; - } -+ msg["Context"] = customText; - - this->sendEvent( - msg.dump(2, ' ', true, nlohmann::json::error_handler_t::replace)); --- -2.25.1 - diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0009-Add-support-for-deleting-terminated-subscriptions.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0009-Add-support-for-deleting-terminated-subscriptions.patch deleted file mode 100644 index 548e3d9c6..000000000 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0009-Add-support-for-deleting-terminated-subscriptions.patch +++ /dev/null @@ -1,46 +0,0 @@ -From ef83a4fb14648edc6c8370363ff88fb6f060a43b Mon Sep 17 00:00:00 2001 -From: P Dheeraj Srujan Kumar -Date: Mon, 20 Sep 2021 21:55:57 +0530 -Subject: [PATCH] Add support for deleting terminated subscriptions - -Added functionality to delete/remove event subscription(s) which are -configured to Terminate after retries. - -Currently, when an Event is subscribed with Retry Policy as -"TerminateAfterRetries", the state of the connection is set to -"Terminated" after retrying, but the Subscription is not removed. -This commit adds the functionality to detect terminated connection and -remove the respective subscription. - -This commit adds this check for metric reports. - -Tested: - - Created a Subscription with - DeliveryRetryPolicy: "TerminateAfterRetries" - - Received Events successfully on Event listener - - Once the Event listener was stopped, the Subscription was - removed/deleted after retries. - -Change-Id: I3cb0af5bc24411cddcdb3d1d9de25e8e9144106c -Signed-off-by: P Dheeraj Srujan Kumar ---- - redfish-core/include/event_service_manager.hpp | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp -index c9e2812..c2fefb3 100644 ---- a/redfish-core/include/event_service_manager.hpp -+++ b/redfish-core/include/event_service_manager.hpp -@@ -1535,6 +1535,9 @@ class EventServiceManager - - std::variant& readings = - found->second; -+ -+ this->deleteTerminatedSubcriptions(); -+ - for (const auto& it : - EventServiceManager::getInstance().subscriptionsMap) - { --- -2.17.1 - diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README index 90916ecec..541fa6aba 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README @@ -2,29 +2,11 @@ These patches are mirror of upstream TelemetryService implementation. Until change is integrated they will be manually merged here to enable feature in Intel builds. Current revisions: -- Add support for MetricDefinition scheme - https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/33363/102 - -- Sync Telmetry service with EventService - https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/38798/53 - -- Switched bmcweb to use new telemetry service API - https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/44270/19 - -- Add support for MetricDefinition property in MetricReport - https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/44512/24 - -- Add GET method for TriggerCollection - file://telemetry/0005-Add-GET-method-for-TriggerCollection.patch +- Add support for POST on TriggersCollection + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/44935/19 - LogService field, actual implementation will be upstreamed with triggers feature - file://telemetry/0006-Revert-Remove-LogService-from-TelemetryService.patch - -- Event service fix for Context field - file://telemetry/0007-event-service-fix-added-Context-field-to-response.patch + file://telemetry/0002-Revert-Remove-LogService-from-TelemetryService.patch -- Generalize ReadingType in MetricDefinition - file://telemetry/0008-Generalize-ReadingType-in-MetricDefinition.patch - -- Add support for deleting terminated subscriptions - file://telemetry/0009-Add-support-for-deleting-terminated-subscriptions.patch +- Switched bmcweb to use new telemetry service API + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/44270/28 -- cgit v1.2.3