diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry')
10 files changed, 1895 insertions, 0 deletions
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 new file mode 100644 index 000000000..c19691cdc --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch @@ -0,0 +1,496 @@ +From 80608f0d72da62426bb00e03a42fbf5daed931c9 Mon Sep 17 00:00:00 2001 +From: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +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 https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/40169 will +be merge 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/Rotational" + }, + { + "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Percent" + }, + { + "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Temperature" + }, + { + "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Power" + }, + { + "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/AirFlow" + } + ], + "Members@odata.count": 5, + "Name": "Metric Definition Collection" +} + +GET /redfish/v1/TelemetryService/MetricDefinitions/Rotational +{ + "@odata.id": "/redfish/v1/TelemetryService/MetricDefinitions/Rotational", + "@odata.type": "#MetricDefinition.v1_0_3.MetricDefinition", + "Id": "Rotational", + "Implementation": "PhysicalSensor", + "IsLinear": true, + "MetricDataType": "Decimal", + "MetricProperties": [ + "/redfish/v1/Chassis/Chassis0/Thermal#/Fans/0/Reading", + "/redfish/v1/Chassis/Chassis0/Thermal#/Fans/1/Reading", + "/redfish/v1/Chassis/Chassis0/Thermal#/Fans/2/Reading", + "/redfish/v1/Chassis/Chassis0/Thermal#/Fans/3/Reading", + "/redfish/v1/Chassis/Chassis0/Thermal#/Fans/4/Reading", + "/redfish/v1/Chassis/Chassis0/Thermal#/Fans/5/Reading", + "/redfish/v1/Chassis/Chassis0/Thermal#/Fans/6/Reading", + "/redfish/v1/Chassis/Chassis0/Thermal#/Fans/7/Reading", + "/redfish/v1/Chassis/Chassis0/Thermal#/Fans/8/Reading", + "/redfish/v1/Chassis/Chassis0/Thermal#/Fans/9/Reading" + ], + "MetricType": "Numeric", + "Name": "Rotational", + "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 <jozef.wludzik@intel.com> +Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +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 | 258 ++++++++++++++++++ + redfish-core/lib/telemetry_service.hpp | 2 + + 5 files changed, 323 insertions(+) + 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 1c7b695..9983b88 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" +@@ -199,6 +200,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/dbus_singleton.hpp> ++ ++#include <array> ++#include <string> ++#include <vector> ++ ++namespace redfish ++{ ++ ++namespace utils ++{ ++ ++template <typename F> ++inline void getChassisNames(F&& cb) ++{ ++ const std::array<const char*, 2> 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<std::string>& chassis) { ++ std::vector<std::string> 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..019168b +--- /dev/null ++++ b/redfish-core/lib/metric_definition.hpp +@@ -0,0 +1,258 @@ ++#pragma once ++ ++#include "async_resp.hpp" ++#include "sensors.hpp" ++#include "utils/get_chassis_names.hpp" ++#include "utils/telemetry_utils.hpp" ++ ++#include <registries/privilege_registry.hpp> ++ ++namespace redfish ++{ ++ ++namespace telemetry ++{ ++ ++bool containsOdata(const nlohmann::json& json, const std::string& odataId) ++{ ++ const auto it = std::find_if( ++ json.begin(), json.end(), [&odataId](const nlohmann::json& item) { ++ auto kt = item.find("@odata.id"); ++ if (kt == item.end()) ++ { ++ return false; ++ } ++ const std::string* value = kt->get_ptr<const std::string*>(); ++ if (!value) ++ { ++ return false; ++ } ++ return *value == odataId; ++ }); ++ ++ return it != json.end(); ++} ++ ++void addMembers(crow::Response& res, ++ const boost::container::flat_map<std::string, std::string>& el) ++{ ++ for (const auto& [_, dbusSensor] : el) ++ { ++ sdbusplus::message::object_path path(dbusSensor); ++ sdbusplus::message::object_path parentPath = path.parent_path(); ++ const std::string type = parentPath.filename(); ++ ++ if (type.empty()) ++ { ++ BMCWEB_LOG_ERROR << "Received invalid DBus Sensor Path = " ++ << dbusSensor; ++ continue; ++ } ++ ++ nlohmann::json& members = res.jsonValue["Members"]; ++ ++ const std::string odataId = ++ std::string(telemetry::metricDefinitionUri) + ++ sensors::toReadingType(type); ++ ++ if (!containsOdata(members, odataId)) ++ { ++ members.push_back({{"@odata.id", odataId}}); ++ } ++ ++ res.jsonValue["Members@odata.count"] = members.size(); ++ } ++} ++ ++template <class Callback> ++inline void mapRedfishUriToDbusPath(Callback&& callback) ++{ ++ utils::getChassisNames([callback = std::move(callback)]( ++ boost::system::error_code ec, ++ const std::vector<std::string>& chassisNames) { ++ if (ec) ++ { ++ BMCWEB_LOG_ERROR << "getChassisNames error: " << ec.value(); ++ callback(ec, {}); ++ return; ++ } ++ ++ auto handleRetrieveUriToDbusMap = ++ [callback = std::move(callback)]( ++ const boost::beast::http::status status, ++ const boost::container::flat_map<std::string, std::string>& ++ uriToDbus) { ++ if (status != boost::beast::http::status::ok) ++ { ++ BMCWEB_LOG_ERROR << "Failed to retrieve URI to dbus " ++ "sensors map with err " ++ << static_cast<unsigned>(status); ++ callback(boost::system::errc::make_error_code( ++ boost::system::errc::io_error), ++ {}); ++ return; ++ } ++ ++ callback(boost::system::errc::make_error_code( ++ boost::system::errc::success), ++ uriToDbus); ++ }; ++ ++ for (const std::string& chassisName : chassisNames) ++ { ++ for (const auto& [sensorNode, dbusPaths] : sensors::dbus::paths) ++ { ++ 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<bmcweb::AsyncResp>& 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; ++ } ++ ++ telemetry::addMembers(asyncResp->res, uriToDbus); ++ }); ++ ++ 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; ++ }); ++} ++ ++namespace telemetry ++{ ++ ++bool isSensorIdSupported(std::string_view readingType) ++{ ++ for (const std::pair<std::string_view, std::vector<const char*>>& ++ typeToPaths : sensors::dbus::paths) ++ { ++ for (const char* supportedPath : typeToPaths.second) ++ { ++ if (readingType == ++ sensors::toReadingType( ++ sdbusplus::message::object_path(supportedPath).filename())) ++ { ++ return true; ++ } ++ } ++ } ++ return false; ++} ++ ++void addMetricProperty( ++ bmcweb::AsyncResp& asyncResp, const std::string& readingType, ++ const boost::container::flat_map<std::string, std::string>& el) ++{ ++ nlohmann::json& metricProperties = ++ asyncResp.res.jsonValue["MetricProperties"]; ++ ++ for (const auto& [redfishSensor, dbusSensor] : el) ++ { ++ std::string sensorId; ++ if (dbus::utility::getNthStringFromPath(dbusSensor, 3, sensorId)) ++ { ++ if (sensors::toReadingType(sensorId) == readingType) ++ { ++ metricProperties.push_back(redfishSensor); ++ } ++ } ++ } ++} ++ ++inline const char* readingTypeToReadingUnits(const std::string& readingType) ++{ ++ for (const auto& [node, paths] : sensors::dbus::paths) ++ { ++ for (const char* path : paths) ++ { ++ const sdbusplus::message::object_path sensorPath = ++ sdbusplus::message::object_path(path); ++ if (sensors::toReadingType(sensorPath.filename()) == readingType) ++ { ++ return sensors::toReadingUnits(sensorPath.filename()); ++ } ++ } ++ } ++ return ""; ++} ++ ++} // namespace telemetry ++ ++inline void requestRoutesMetricDefinition(App& app) ++{ ++ BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricDefinitions/<str>/") ++ .privileges(privileges::getTelemetryService) ++ .methods(boost::beast::http::verb::get)( ++ [](const crow::Request&, ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, ++ const std::string& readingType) { ++ if (!telemetry::isSensorIdSupported(readingType)) ++ { ++ messages::resourceNotFound(asyncResp->res, ++ "MetricDefinition", readingType); ++ return; ++ } ++ ++ telemetry::mapRedfishUriToDbusPath( ++ [asyncResp, ++ readingType](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; ++ } ++ ++ asyncResp->res.jsonValue["Id"] = readingType; ++ asyncResp->res.jsonValue["Name"] = readingType; ++ asyncResp->res.jsonValue["@odata.id"] = ++ telemetry::metricDefinitionUri + readingType; ++ asyncResp->res.jsonValue["@odata.type"] = ++ "#MetricDefinition.v1_0_3.MetricDefinition"; ++ asyncResp->res.jsonValue["MetricDataType"] = "Decimal"; ++ asyncResp->res.jsonValue["MetricType"] = "Numeric"; ++ asyncResp->res.jsonValue["IsLinear"] = true; ++ asyncResp->res.jsonValue["Implementation"] = ++ "PhysicalSensor"; ++ asyncResp->res.jsonValue["Units"] = ++ telemetry::readingTypeToReadingUnits(readingType); ++ ++ telemetry::addMetricProperty(*asyncResp, readingType, ++ uriToDbus); ++ }); ++ }); ++} ++ ++} // namespace redfish +diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp +index ad86d5c..c4962e9 100644 +--- a/redfish-core/lib/telemetry_service.hpp ++++ b/redfish-core/lib/telemetry_service.hpp +@@ -29,6 +29,8 @@ inline void requestRoutesTelemetryService(App& app) + "/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]( +-- +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 new file mode 100644 index 000000000..d32c85356 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0002-Sync-Telmetry-service-with-EventService.patch @@ -0,0 +1,294 @@ +From 77e8a0b5037a555b1520823b667595ac8780c675 Mon Sep 17 00:00:00 2001 +From: "Wludzik, Jozef" <jozef.wludzik@intel.com> +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 <jozef.wludzik@intel.com> +--- + .../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 d89b789..4faaddd 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<telemetry::TimestampReadings>& 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<int32_t, ReadingsObjType>>& +- resp) { +- if (ec) +- { +- BMCWEB_LOG_DEBUG +- << "D-Bus call failed to GetAll metric readings."; +- return; +- } +- +- const int32_t* timestampPtr = +- std::get_if<int32_t>(&resp["Timestamp"]); +- if (!timestampPtr) +- { +- BMCWEB_LOG_DEBUG << "Failed to Get timestamp."; +- return; +- } +- +- ReadingsObjType* readingsPtr = +- std::get_if<ReadingsObjType>(&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<Subscription> 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<sdbusplus::bus::match::match>( + *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<std::pair< ++ std::string, std::variant<telemetry::TimestampReadings>>> ++ props; ++ std::vector<std::string> 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_ERROR ++ << "Failed to get Readings from Report properties"; ++ return; ++ } ++ ++ std::variant<telemetry::TimestampReadings>& 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<bmcweb::AsyncResp>& asyncResp, +- const std::string& id, ++inline bool fillReport(nlohmann::json& json, const std::string& id, + const std::variant<TimestampReadings>& 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<bmcweb::AsyncResp>& 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<time_t>(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 new file mode 100644 index 000000000..20bcbabfa --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Switched-bmcweb-to-use-new-telemetry-service-API.patch @@ -0,0 +1,301 @@ +From fca6f5b951a363916a83a25f6578f95a6cf32a3e Mon Sep 17 00:00:00 2001 +From: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +Date: Thu, 17 Jun 2021 13:37:57 +0000 +Subject: [PATCH] Switched bmcweb to use new telemetry service API + +Added support for multiple MetricProperties. Added support for new +parameters: CollectionTimeScope, CollectionDuration. + +Tested: + - It is possible to create MetricReportDefinitions with multiple + MetricProperties. + - Stub values for new parameters are correctly passed to telemetry + service. + - All existing telemetry service functionalities remain unchanged. + +Change-Id: I2cd17069e3ea015c8f5571c29278f1d50536272a +Signed-off-by: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +--- + redfish-core/lib/metric_report_definition.hpp | 212 ++++++++++-------- + 1 file changed, 114 insertions(+), 98 deletions(-) + +diff --git a/redfish-core/lib/metric_report_definition.hpp b/redfish-core/lib/metric_report_definition.hpp +index a0c4f1d..7c26787 100644 +--- a/redfish-core/lib/metric_report_definition.hpp ++++ b/redfish-core/lib/metric_report_definition.hpp +@@ -7,6 +7,8 @@ + #include <app.hpp> + #include <boost/container/flat_map.hpp> + #include <registries/privilege_registry.hpp> ++#include <sdbusplus/asio/property.hpp> ++#include <sdbusplus/unpack_properties.hpp> + + #include <tuple> + #include <variant> +@@ -17,87 +19,90 @@ namespace redfish + namespace telemetry + { + +-using ReadingParameters = +- std::vector<std::tuple<sdbusplus::message::object_path, std::string, +- std::string, std::string>>; ++using ReadingParameters = std::vector< ++ std::tuple<std::vector<sdbusplus::message::object_path>, std::string, ++ std::string, std::string, std::string, uint64_t>>; + + inline void fillReportDefinition( + const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id, + const std::vector< +- std::pair<std::string, std::variant<std::string, bool, uint64_t, +- ReadingParameters>>>& ret) ++ std::pair<std::string, std::variant<std::monostate, std::string, bool, ++ uint64_t, ReadingParameters>>>& ++ properties) + { +- asyncResp->res.jsonValue["@odata.type"] = +- "#MetricReportDefinition.v1_3_0.MetricReportDefinition"; +- asyncResp->res.jsonValue["@odata.id"] = +- telemetry::metricReportDefinitionUri + id; +- asyncResp->res.jsonValue["Id"] = id; +- asyncResp->res.jsonValue["Name"] = id; +- asyncResp->res.jsonValue["MetricReport"]["@odata.id"] = +- telemetry::metricReportUri + id; +- asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; +- asyncResp->res.jsonValue["ReportUpdates"] = "Overwrite"; +- +- const bool* emitsReadingsUpdate = nullptr; +- const bool* logToMetricReportsCollection = nullptr; +- const ReadingParameters* readingParams = nullptr; +- const std::string* reportingType = nullptr; +- const uint64_t* interval = nullptr; +- for (const auto& [key, var] : ret) ++ try + { +- 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<std::string> redfishReportActions; ++ redfishReportActions.reserve(2); ++ if (emitsReadingsUpdate) + { +- emitsReadingsUpdate = std::get_if<bool>(&var); ++ redfishReportActions.emplace_back("RedfishEvent"); + } +- else if (key == "LogToMetricReportsCollection") ++ if (logToMetricReportsCollection) + { +- logToMetricReportsCollection = std::get_if<bool>(&var); ++ redfishReportActions.emplace_back("LogToMetricReportsCollection"); + } +- else if (key == "ReadingParameters") +- { +- readingParams = std::get_if<ReadingParameters>(&var); +- } +- else if (key == "ReportingType") +- { +- reportingType = std::get_if<std::string>(&var); +- } +- else if (key == "Interval") ++ ++ nlohmann::json metrics = nlohmann::json::array(); ++ for (auto& [sensorPath, operationType, id, metadata, ++ collectionTimeScope, collectionDuration] : readingParams) + { +- interval = std::get_if<uint64_t>(&var); ++ std::vector<std::string> 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)}, ++ }); + } +- } +- if (!emitsReadingsUpdate || !logToMetricReportsCollection || +- !readingParams || !reportingType || !interval) +- { +- BMCWEB_LOG_ERROR << "Property type mismatch or property is missing"; +- messages::internalError(asyncResp->res); +- return; +- } + +- std::vector<std::string> redfishReportActions; +- redfishReportActions.reserve(2); +- if (*emitsReadingsUpdate) +- { +- redfishReportActions.emplace_back("RedfishEvent"); ++ asyncResp->res.jsonValue["@odata.type"] = ++ "#MetricReportDefinition.v1_3_0.MetricReportDefinition"; ++ asyncResp->res.jsonValue["@odata.id"] = ++ telemetry::metricReportDefinitionUri + id; ++ asyncResp->res.jsonValue["Id"] = id; ++ asyncResp->res.jsonValue["Name"] = id; ++ asyncResp->res.jsonValue["MetricReport"]["@odata.id"] = ++ telemetry::metricReportUri + id; ++ asyncResp->res.jsonValue["Status"]["State"] = "Enabled"; ++ asyncResp->res.jsonValue["ReportUpdates"] = "Overwrite"; ++ asyncResp->res.jsonValue["Metrics"] = metrics; ++ asyncResp->res.jsonValue["MetricReportDefinitionType"] = reportingType; ++ asyncResp->res.jsonValue["ReportActions"] = redfishReportActions; ++ 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::internalError(asyncResp->res); + } +- asyncResp->res.jsonValue["Metrics"] = metrics; +- asyncResp->res.jsonValue["MetricReportDefinitionType"] = *reportingType; +- asyncResp->res.jsonValue["ReportActions"] = redfishReportActions; +- asyncResp->res.jsonValue["Schedule"]["RecurrenceInterval"] = +- time_utils::toDurationString(std::chrono::milliseconds(*interval)); + } + + struct AddReportArgs +@@ -275,6 +280,11 @@ class AddReport + + for (const auto& [id, uris] : args.metrics) + { ++ std::vector<sdbusplus::message::object_path> dbusPaths; ++ dbusPaths.reserve(uris.size()); ++ nlohmann::json metadata; ++ metadata["MetricProperties"] = nlohmann::json::array(); ++ + for (size_t i = 0; i < uris.size(); i++) + { + const std::string& uri = uris[i]; +@@ -291,8 +301,12 @@ class AddReport + } + + const std::string& dbusPath = el->second; +- readingParams.emplace_back(dbusPath, "SINGLE", id, uri); ++ dbusPaths.emplace_back(dbusPath); ++ metadata["MetricProperties"].emplace_back(uri); + } ++ ++ readingParams.emplace_back(dbusPaths, "SINGLE", id, metadata.dump(), ++ "Point", 0u); + } + const std::shared_ptr<bmcweb::AsyncResp> aResp = asyncResp; + crow::connections::systemBus->async_method_call( +@@ -330,10 +344,10 @@ class AddReport + messages::created(aResp->res); + }, + telemetry::service, "/xyz/openbmc_project/Telemetry/Reports", +- "xyz.openbmc_project.Telemetry.ReportManager", "AddReport", +- "TelemetryService/" + args.name, args.reportingType, +- 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); + } + + void insert(const boost::container::flat_map<std::string, std::string>& el) +@@ -415,37 +429,39 @@ inline void requestRoutesMetricReportDefinition(App& app) + BMCWEB_ROUTE(app, + "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/") + .privileges(redfish::privileges::getMetricReportDefinition) +- .methods(boost::beast::http::verb::get)( +- [](const crow::Request&, +- const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, +- const std::string& id) { +- crow::connections::systemBus->async_method_call( +- [asyncResp, id]( +- const boost::system::error_code ec, +- const std::vector<std::pair< +- std::string, +- std::variant<std::string, bool, uint64_t, +- telemetry::ReadingParameters>>>& 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<std::pair< ++ std::string, ++ std::variant<std::monostate, std::string, bool, ++ uint64_t, telemetry::ReadingParameters>>>& ++ 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); ++ }); ++ }); + +- telemetry::fillReportDefinition(asyncResp, id, ret); +- }, +- telemetry::service, telemetry::getDbusReportPath(id), +- "org.freedesktop.DBus.Properties", "GetAll", +- telemetry::reportInterface); +- }); + BMCWEB_ROUTE(app, + "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/") + .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 new file mode 100644 index 000000000..3d60ae293 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0004-Add-support-for-MetricDefinition-property-in-MetricReport.patch @@ -0,0 +1,267 @@ +From 79b3d35b864a2b545b4c9b2ac9390ea5dec169f5 Mon Sep 17 00:00:00 2001 +From: Szymon Dompke <szymon.dompke@intel.com> +Date: Mon, 28 Jun 2021 11:10:23 +0200 +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 <szymon.dompke@intel.com> +--- + 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 f6a66f1..6b5d9af 100644 +--- a/meson.build ++++ b/meson.build +@@ -355,6 +355,8 @@ srcfiles_unittest = ['include/ut/dbus_utility_test.cpp', + 'redfish-core/ut/time_utils_test.cpp', + 'http/ut/utility_test.cpp'] + ++srcfiles_unittest_dependencies = ['redfish-core/src/error_messages.cpp'] ++ + # Gather the Configuration data + + conf_data = configuration_data() +@@ -412,7 +414,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<nlohmann::json> ++ getMetadataJson(const std::string& metadataStr) ++{ ++ std::optional<nlohmann::json> 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<std::string> ++ readStringFromMetadata(const nlohmann::json& metadataJson, const char* key) ++{ ++ std::optional<std::string> res; ++ if (auto it = metadataJson.find(key); it != metadataJson.end()) ++ { ++ if (const std::string* value = it->get_ptr<const std::string*>()) ++ { ++ 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<bmcweb::AsyncResp>& 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 <app.hpp> +@@ -15,34 +16,56 @@ using Readings = + std::vector<std::tuple<std::string, std::string, double, uint64_t>>; + using TimestampReadings = std::tuple<uint64_t, Readings>; + +-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<nlohmann::json> readingMetadataJson = ++ getMetadataJson(metadataStr); ++ if (!readingMetadataJson) ++ { ++ return false; ++ } ++ ++ std::optional<std::string> sensorDbusPath = ++ readStringFromMetadata(*readingMetadataJson, "SensorDbusPath"); ++ if (!sensorDbusPath) ++ { ++ return false; ++ } ++ ++ std::optional<std::string> 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<time_t>(timestamp))}, + }); + } + +- return metricValues; ++ return true; + } + + inline bool fillReport(nlohmann::json& json, const std::string& id, + const std::variant<TimestampReadings>& 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<TimestampReadings>(&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<time_t>(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 cb7ea15..44c2129 100644 +--- a/redfish-core/lib/sensors.hpp ++++ b/redfish-core/lib/sensors.hpp +@@ -21,6 +21,8 @@ + #include <boost/container/flat_map.hpp> + #include <boost/range/algorithm/replace_copy_if.hpp> + #include <dbus_singleton.hpp> ++#include <dbus_utility.hpp> ++#include <error_messages.hpp> + #include <registries/privilege_registry.hpp> + #include <utils/json_utils.hpp> + +-- +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 new file mode 100644 index 000000000..0646aba5c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-GET-method-for-TriggerCollection.patch @@ -0,0 +1,313 @@ +From a1e89d356ba5ed594a1494efe8257946e1062396 Mon Sep 17 00:00:00 2001 +From: Lukasz Kazmierczak <lukasz.kazmierczak@intel.com> +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 <lukasz.kazmierczak@intel.com> +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<nlohmann::json> + getMetadataJson(const std::string& metadataStr) +@@ -57,15 +64,27 @@ inline std::optional<std::string> + return res; + } + +-inline void +- getReportCollection(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, +- const std::string& uri) ++struct CollectionParams + { +- const std::array<const char*, 1> interfaces = {reportInterface}; ++ const char* subtree; ++ int depth; ++ std::array<const char*, 1> interfaces; + ++ CollectionParams() = delete; ++ CollectionParams(const char* st, int dp, ++ const std::array<const char*, 1>& ifaces) : ++ subtree{st}, ++ depth{dp}, interfaces{ifaces} ++ {} ++}; ++ ++inline void getCollection(const std::shared_ptr<bmcweb::AsyncResp>& 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<std::string>& reports) { ++ const std::vector<std::string>& 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 <app.hpp> ++#include <registries/privilege_registry.hpp> ++ ++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<bmcweb::AsyncResp>& 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 @@ + <edmx:Include Namespace="Thermal.v1_7_0"/> + <edmx:Include Namespace="Thermal.v1_7_1"/> + </edmx:Reference> ++ <edmx:Reference Uri="/redfish/v1/schema/TriggersCollection_v1.xml"> ++ <edmx:Include Namespace="TriggersCollection"/> ++ </edmx:Reference> + <edmx:Reference Uri="/redfish/v1/schema/UpdateService_v1.xml"> + <edmx:Include Namespace="UpdateService"/> + <edmx:Include Namespace="UpdateService.v1_0_0"/> +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 @@ ++<?xml version="1.0" encoding="UTF-8"?> ++<!----> ++<!--################################################################################ --> ++<!--# Redfish Schema: TriggerSetCollection --> ++<!--# --> ++<!--# For a detailed change log, see the README file contained in the DSP8010 bundle, --> ++<!--# available at http://www.dmtf.org/standards/redfish --> ++<!--# Copyright 2014-2021 DMTF. --> ++<!--# For the full DMTF copyright policy, see http://www.dmtf.org/about/policies/copyright --> ++<!--################################################################################ --> ++<!----> ++<edmx:Edmx xmlns:edmx="http://docs.oasis-open.org/odata/ns/edmx" Version="4.0"> ++ ++ <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/errata03/csd01/complete/vocabularies/Org.OData.Core.V1.xml"> ++ <edmx:Include Namespace="Org.OData.Core.V1" Alias="OData"/> ++ </edmx:Reference> ++ <edmx:Reference Uri="http://docs.oasis-open.org/odata/odata/v4.0/errata03/csd01/complete/vocabularies/Org.OData.Capabilities.V1.xml"> ++ <edmx:Include Namespace="Org.OData.Capabilities.V1" Alias="Capabilities"/> ++ </edmx:Reference> ++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/Resource_v1.xml"> ++ <edmx:Include Namespace="Resource.v1_0_0"/> ++ </edmx:Reference> ++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/RedfishExtensions_v1.xml"> ++ <edmx:Include Namespace="RedfishExtensions.v1_0_0" Alias="Redfish"/> ++ </edmx:Reference> ++ <edmx:Reference Uri="http://redfish.dmtf.org/schemas/v1/Triggers_v1.xml"> ++ <edmx:Include Namespace="Triggers"/> ++ </edmx:Reference> ++ ++ <edmx:DataServices> ++ ++ <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="TriggersCollection"> ++ <Annotation Term="Redfish.OwningEntity" String="DMTF"/> ++ ++ <EntityType Name="TriggersCollection" BaseType="Resource.v1_0_0.ResourceCollection"> ++ <Annotation Term="OData.Description" String="The collection of Triggers resource instances."/> ++ <Annotation Term="OData.LongDescription" String="This resource shall represent a resource collection of Triggers instances for a Redfish implementation."/> ++ <Annotation Term="Capabilities.InsertRestrictions"> ++ <Record> ++ <PropertyValue Property="Insertable" Bool="true"/> ++ <Annotation Term="OData.Description" String="Create triggers through a POST to the trigger collection."/> ++ </Record> ++ </Annotation> ++ <Annotation Term="Capabilities.UpdateRestrictions"> ++ <Record> ++ <PropertyValue Property="Updatable" Bool="false"/> ++ </Record> ++ </Annotation> ++ <Annotation Term="Capabilities.DeleteRestrictions"> ++ <Record> ++ <PropertyValue Property="Deletable" Bool="false"/> ++ </Record> ++ </Annotation> ++ <Annotation Term="Redfish.Uris"> ++ <Collection> ++ <String>/redfish/v1/TelemetryService/Triggers</String> ++ </Collection> ++ </Annotation> ++ <NavigationProperty Name="Members" Type="Collection(Triggers.Triggers)"> ++ <Annotation Term="OData.Permissions" EnumMember="OData.Permission/Read"/> ++ <Annotation Term="OData.Description" String="The members of this collection."/> ++ <Annotation Term="OData.LongDescription" String="This property shall contain an array of links to the members of this collection."/> ++ <Annotation Term="OData.AutoExpandReferences"/> ++ <Annotation Term="Redfish.Required"/> ++ </NavigationProperty> ++ </EntityType> ++ ++ </Schema> ++ </edmx:DataServices> ++</edmx:Edmx> +-- +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 new file mode 100644 index 000000000..987a43b4c --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0006-Revert-Remove-LogService-from-TelemetryService.patch @@ -0,0 +1,26 @@ +From 472ac5f15a19917042852b243e8b668b3ab49e32 Mon Sep 17 00:00:00 2001 +From: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +Date: Tue, 22 Jun 2021 13:59:48 +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 37221c3..f3a1efb 100644 +--- a/redfish-core/lib/telemetry_service.hpp ++++ b/redfish-core/lib/telemetry_service.hpp +@@ -30,6 +30,8 @@ inline void requestRoutesTelemetryService(App& app) + "/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]( +-- +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 new file mode 100644 index 000000000..ffab743f6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0007-event-service-fix-added-Context-field-to-response.patch @@ -0,0 +1,29 @@ +From 0ca8c383db8c9afbce63380955a20ada0acc20b7 Mon Sep 17 00:00:00 2001 +From: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +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 <krzysztof.grobelny@intel.com> +--- + 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/0008-Generalize-ReadingType-in-MetricDefinition.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0008-Generalize-ReadingType-in-MetricDefinition.patch new file mode 100644 index 000000000..bd6e64346 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0008-Generalize-ReadingType-in-MetricDefinition.patch @@ -0,0 +1,93 @@ +From d9baec3ccdff5ed4d1620f374a252c769de5b45b Mon Sep 17 00:00:00 2001 +From: Krzysztof Grobelny <krzysztof.grobelny@intel.com> +Date: Thu, 19 Aug 2021 10:55:38 +0000 +Subject: [PATCH] Generalize ReadingType in MetricDefinition + +Recent addition of PMT required adding new type of sensor 'count', which +doesnt comply with any of Redfish-defined Sensor.ReadingType values. + +To support property of this kind MetricDefinition implementation was +altered to support sensor types not covered by Redfish types by +a 'fallback' to direct usage of sensor type. Populating 'Units' was also +modified, so it won't be shown if value does not have any units mapped. + +Testing: +- PMT counters are shown properly in MetricDefinitions/Count +- Redfish Validator passes +--- + redfish-core/lib/metric_definition.hpp | 25 ++++++++++++++++++------- + 1 file changed, 18 insertions(+), 7 deletions(-) + +diff --git a/redfish-core/lib/metric_definition.hpp b/redfish-core/lib/metric_definition.hpp +index 019168b..df29b65 100644 +--- a/redfish-core/lib/metric_definition.hpp ++++ b/redfish-core/lib/metric_definition.hpp +@@ -33,6 +33,18 @@ bool containsOdata(const nlohmann::json& json, const std::string& odataId) + return it != json.end(); + } + ++std::string groupName(const std::string& sensorType) ++{ ++ std::string group = sensors::toReadingType(sensorType); ++ if (group.empty()) ++ { ++ // Fallback for types not covered by standard Redfish Sensor.ReadingType ++ group = sensorType; ++ group[0] = static_cast<char>(std::toupper(group[0])); ++ } ++ return group; ++} ++ + void addMembers(crow::Response& res, + const boost::container::flat_map<std::string, std::string>& el) + { +@@ -52,8 +64,7 @@ void addMembers(crow::Response& res, + nlohmann::json& members = res.jsonValue["Members"]; + + const std::string odataId = +- std::string(telemetry::metricDefinitionUri) + +- sensors::toReadingType(type); ++ std::string(telemetry::metricDefinitionUri) + groupName(type); + + if (!containsOdata(members, odataId)) + { +@@ -149,15 +160,15 @@ inline void requestRoutesMetricDefinitionCollection(App& app) + namespace telemetry + { + +-bool isSensorIdSupported(std::string_view readingType) ++bool isSensorIdSupported(std::string_view group) + { + for (const std::pair<std::string_view, std::vector<const char*>>& + typeToPaths : sensors::dbus::paths) + { + for (const char* supportedPath : typeToPaths.second) + { +- if (readingType == +- sensors::toReadingType( ++ if (group == ++ groupName( + sdbusplus::message::object_path(supportedPath).filename())) + { + return true; +@@ -168,7 +179,7 @@ bool isSensorIdSupported(std::string_view readingType) + } + + void addMetricProperty( +- bmcweb::AsyncResp& asyncResp, const std::string& readingType, ++ bmcweb::AsyncResp& asyncResp, const std::string& group, + const boost::container::flat_map<std::string, std::string>& el) + { + nlohmann::json& metricProperties = +@@ -179,7 +190,7 @@ void addMetricProperty( + std::string sensorId; + if (dbus::utility::getNthStringFromPath(dbusSensor, 3, sensorId)) + { +- if (sensors::toReadingType(sensorId) == readingType) ++ if (groupName(sensorId) == group) + { + metricProperties.push_back(redfishSensor); + } +-- +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 new file mode 100644 index 000000000..548e3d9c6 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0009-Add-support-for-deleting-terminated-subscriptions.patch @@ -0,0 +1,46 @@ +From ef83a4fb14648edc6c8370363ff88fb6f060a43b Mon Sep 17 00:00:00 2001 +From: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com> +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 <p.dheeraj.srujan.kumar@intel.com> +--- + 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<telemetry::TimestampReadings>& 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 new file mode 100644 index 000000000..fd88e9e18 --- /dev/null +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/README @@ -0,0 +1,30 @@ +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/93 + +- Sync Telmetry service with EventService + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/38798/40 + +- Switched bmcweb to use new telemetry service API + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/44270/5 + +- Add support for MetricDefinition property in MetricReport + https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/44512/9 + +- Add GET method for TriggerCollection + file://telemetry/0005-Add-GET-method-for-TriggerCollection.patch + +- 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 + +- 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 |