diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch')
-rw-r--r-- | meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch | 619 |
1 files changed, 0 insertions, 619 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 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 <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 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 <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 | 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/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..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 <registries/privilege_registry.hpp> -+ -+namespace redfish -+{ -+ -+namespace telemetry -+{ -+ -+struct ValueVisitor -+{ -+ ValueVisitor(boost::system::error_code& ec) : ec(ec) -+ {} -+ -+ template <class T> -+ double operator()(T value) const -+ { -+ return static_cast<double>(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<void(boost::system::error_code, double)> callback) -+{ -+ crow::connections::systemBus->async_method_call( -+ [callback = std::move(callback)]( -+ boost::system::error_code ec, -+ const std::variant<std::monostate, double, uint64_t, int64_t, -+ uint32_t, int32_t, uint16_t, int16_t>& -+ 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<bmcweb::AsyncResp>& 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<void(boost::system::error_code, const std::string&)> callback) -+{ -+ using ResultType = std::pair< -+ std::string, -+ std::vector<std::pair<std::string, std::vector<std::string>>>>; -+ -+ crow::connections::systemBus->async_method_call( -+ [sensorPath, callback = std::move(callback)]( -+ boost::system::error_code ec, -+ const std::vector<ResultType>& 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 <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 counter = std::make_shared<std::pair< -+ boost::container::flat_map<std::string, std::string>, size_t>>(); -+ -+ auto handleRetrieveUriToDbusMap = -+ [counter, 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); -+ 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<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; -+ } -+ -+ std::set<std::string> 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/<str>/") -+ .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<std::string, std::string>& -+ 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<std::string, std::string> -+ 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 |