From d3f33bdb9a53be9658f237143132adf38b7269a3 Mon Sep 17 00:00:00 2001 From: Reed Frandsen Date: Wed, 20 Nov 2024 14:50:18 -0600 Subject: [PATCH 1/4] 1110: Add support for MetricDefinition scheme (#1088) * 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. Removal of ResourceNotFound in sensors.hpp to fix MetricDefinition Collection REST Get call. 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 Signed-off-by: Ali Ahmed * Review feedback changes * review updates 2 --------- Signed-off-by: Wludzik, Jozef Signed-off-by: Krzysztof Grobelny Signed-off-by: Ali Ahmed Co-authored-by: Krzysztof Grobelny --- .../include/utils/get_chassis_names.hpp | 58 +++ .../include/utils/telemetry_utils.hpp | 2 + redfish-core/lib/metric_definition.hpp | 377 ++++++++++++++++++ redfish-core/lib/telemetry_service.hpp | 2 + redfish-core/src/redfish.cpp | 3 + 5 files changed, 442 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/utils/get_chassis_names.hpp b/redfish-core/include/utils/get_chassis_names.hpp new file mode 100644 index 000000000..e1e83baba --- /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.Chassis"}; + + crow::connections::systemBus->async_method_call( + [callback = std::forward( + 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 df71027b8..94aeb11ea 100644 --- a/redfish-core/include/utils/telemetry_utils.hpp +++ b/redfish-core/include/utils/telemetry_utils.hpp @@ -30,6 +30,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/"; inline std::string getDbusReportPath(std::string_view id) { sdbusplus::message::object_path reportsPath( diff --git a/redfish-core/lib/metric_definition.hpp b/redfish-core/lib/metric_definition.hpp new file mode 100644 index 000000000..9977ebc1b --- /dev/null +++ b/redfish-core/lib/metric_definition.hpp @@ -0,0 +1,377 @@ +#pragma once + +#include "async_resp.hpp" +#include "generated/enums/metric_definition.hpp" +#include "sensors.hpp" +#include "utils/get_chassis_names.hpp" +#include "utils/sensor_utils.hpp" +#include "utils/telemetry_utils.hpp" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace redfish +{ + +namespace telemetry +{ + +struct ValueVisitor +{ + explicit ValueVisitor(boost::system::error_code& ec) : ec3(ec) {} + + template + double operator()(T value) const + { + return static_cast(value); + } + + double operator()(std::monostate /*unused*/) const + { + ec3 = boost::system::errc::make_error_code( + boost::system::errc::invalid_argument); + return double{}; + } + + boost::system::error_code& ec3; +}; + +inline void getReadingRange( + const std::string& service2, 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); + }, + service2, 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"] = + metric_definition::MetricType::Numeric; + + telemetry::getReadingRange( + serviceName, sensorPath, "MinValue", + [asyncResp](boost::system::error_code ec, double readingRange) { + if (ec) + { + messages::internalError(asyncResp->res); + BMCWEB_LOG_ERROR( + "fillMinMaxReadingRange: getReadingRange error {}", ec); + return; + } + + if (std::isfinite(readingRange)) + { + asyncResp->res.jsonValue["MetricType"] = + metric_definition::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); + BMCWEB_LOG_ERROR( + "fillMinMaxReadingRange: getReadingRange error {}", ec); + return; + } + + if (std::isfinite(readingRange)) + { + asyncResp->res.jsonValue["MetricType"] = + metric_definition::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& [service2, interfaces] : + serviceToInterfaces) + { + callback(boost::system::errc::make_error_code( + boost::system::errc::success), + service2); + 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"}}; + +static std::string mapSensorToMetricDefinition(const std::string& sensorPath) +{ + sdbusplus::message::object_path sensorObjectPath{sensorPath}; + + const auto* const it = std::find_if( + metricDefinitionMapping.begin(), metricDefinitionMapping.end(), + [&sensorObjectPath](const auto& item) { + return item.first == sensorObjectPath.parent_path().filename(); + }); + + std::string metricDefinitionPath = + "/redfish/v1/TelemetryService/MetricDefinitions/"; + + if (it != metricDefinitionMapping.end()) + { + return metricDefinitionPath + it->second; + } + + return metricDefinitionPath + sensorObjectPath.filename(); +} + +template +inline void mapRedfishUriToDbusPath(Callback&& callback) +{ + utils::getChassisNames([callback = std::forward(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 std::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) + { + ++counter->second; + retrieveUriToDbusMap(chassisName, sensors::sensorsNodeStr.data(), + handleRetrieveUriToDbusMap); + } + }); +} + +} // namespace telemetry + +inline void requestRoutesMetricDefinitionCollection(App& app) +{ + BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricDefinitions/") + .privileges(privileges::getMetricDefinitionCollection) + .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::getMetricDefinition) + .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 ec2, + const boost::container::flat_map& + uriToDbus) { + if (ec2) + { + messages::internalError(asyncResp->res); + BMCWEB_LOG_ERROR("mapRedfishUriToDbusPath error: {}", + ec2.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 ec3, + const std::string& serviceName) { + if (ec3) + { + messages::internalError(asyncResp->res); + BMCWEB_LOG_ERROR("getServiceSensorFailed: {}", + ec3.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"] = + metric_definition::MetricDataType::Decimal; + asyncResp->res.jsonValue["IsLinear"] = true; + asyncResp->res.jsonValue["Units"] = + sensor_utils::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 49d467335..479b8b606 100644 --- a/redfish-core/lib/telemetry_service.hpp +++ b/redfish-core/lib/telemetry_service.hpp @@ -47,6 +47,8 @@ inline void handleTelemetryServiceGet( "/redfish/v1/TelemetryService/MetricReportDefinitions"; asyncResp->res.jsonValue["MetricReports"]["@odata.id"] = "/redfish/v1/TelemetryService/MetricReports"; + asyncResp->res.jsonValue["MetricDefinitions"]["@odata.id"] = + "/redfish/v1/TelemetryService/MetricDefinitions"; asyncResp->res.jsonValue["Triggers"]["@odata.id"] = "/redfish/v1/TelemetryService/Triggers"; diff --git a/redfish-core/src/redfish.cpp b/redfish-core/src/redfish.cpp index 34d455ab5..cdc8645bf 100644 --- a/redfish-core/src/redfish.cpp +++ b/redfish-core/src/redfish.cpp @@ -27,6 +27,7 @@ #include "memory.hpp" #include "message_registries.hpp" #include "metadata.hpp" +#include "metric_definition.hpp" #include "metric_report.hpp" #include "metric_report_definition.hpp" #include "network_protocol.hpp" @@ -251,6 +252,8 @@ RedfishService::RedfishService(App& app) requestRoutesMetricReportDefinition(app); requestRoutesMetricReportCollection(app); requestRoutesMetricReport(app); + requestRoutesMetricDefinitionCollection(app); + requestRoutesMetricDefinition(app); requestRoutesTriggerCollection(app); requestRoutesTrigger(app); From a293f6fe61179943bdbaf33c9fa47de247953382 Mon Sep 17 00:00:00 2001 From: Reed Frandsen Date: Fri, 9 May 2025 15:48:06 -0500 Subject: [PATCH 2/4] clang-format --- .../include/utils/get_chassis_names.hpp | 7 +- redfish-core/lib/metric_definition.hpp | 222 ++++++++++-------- 2 files changed, 126 insertions(+), 103 deletions(-) diff --git a/redfish-core/include/utils/get_chassis_names.hpp b/redfish-core/include/utils/get_chassis_names.hpp index e1e83baba..96bd753a3 100644 --- a/redfish-core/include/utils/get_chassis_names.hpp +++ b/redfish-core/include/utils/get_chassis_names.hpp @@ -1,9 +1,14 @@ #pragma once -#include +#include "dbus_singleton.hpp" + +#include +#include +#include #include #include +#include #include namespace redfish diff --git a/redfish-core/lib/metric_definition.hpp b/redfish-core/lib/metric_definition.hpp index 9977ebc1b..3ce15e5d7 100644 --- a/redfish-core/lib/metric_definition.hpp +++ b/redfish-core/lib/metric_definition.hpp @@ -1,23 +1,38 @@ #pragma once +#include "app.hpp" #include "async_resp.hpp" +#include "dbus_singleton.hpp" +#include "error_messages.hpp" #include "generated/enums/metric_definition.hpp" +#include "http_request.hpp" +#include "logging.hpp" #include "sensors.hpp" #include "utils/get_chassis_names.hpp" #include "utils/sensor_utils.hpp" #include "utils/telemetry_utils.hpp" +#include +#include #include +#include #include #include +#include #include +#include #include +#include +#include +#include #include #include +#include #include #include #include +#include namespace redfish { @@ -249,47 +264,47 @@ inline void requestRoutesMetricDefinitionCollection(App& app) .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(); + 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; }); - - 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) @@ -301,77 +316,80 @@ inline void requestRoutesMetricDefinition(App& app) const std::shared_ptr< bmcweb::AsyncResp>& asyncResp, const std::string& name) { - telemetry::mapRedfishUriToDbusPath( - [asyncResp, name]( - boost::system::error_code ec2, - const boost::container::flat_map& - uriToDbus) { - if (ec2) - { - messages::internalError(asyncResp->res); - BMCWEB_LOG_ERROR("mapRedfishUriToDbusPath error: {}", - ec2.value()); - return; - } + telemetry::mapRedfishUriToDbusPath( + [asyncResp, name]( + boost::system::error_code ec2, + const boost::container::flat_map& + uriToDbus) { + if (ec2) + { + messages::internalError(asyncResp->res); + BMCWEB_LOG_ERROR("mapRedfishUriToDbusPath error: {}", + ec2.value()); + return; + } - std::string odataId = telemetry::metricDefinitionUri + name; - boost::container::flat_map matchingUris; + std::string odataId = telemetry::metricDefinitionUri + name; + boost::container::flat_map + matchingUris; - for (const auto& [uri, dbusPath] : uriToDbus) - { - if (telemetry::mapSensorToMetricDefinition(dbusPath) == odataId) + for (const auto& [uri, dbusPath] : uriToDbus) { - matchingUris.emplace(uri, dbusPath); + 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 ec3, - const std::string& serviceName) { - if (ec3) - { - messages::internalError(asyncResp->res); - BMCWEB_LOG_ERROR("getServiceSensorFailed: {}", - ec3.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"] = - metric_definition::MetricDataType::Decimal; - asyncResp->res.jsonValue["IsLinear"] = true; - asyncResp->res.jsonValue["Units"] = - sensor_utils::sensors::toReadingUnits( - sdbusplus::message::object_path{sensorPath} - .parent_path() - .filename()); - - for (const auto& [uri, dbusPath] : matchingUris) + if (matchingUris.empty()) { - asyncResp->res.jsonValue["MetricProperties"].push_back(uri); + messages::resourceNotFound(asyncResp->res, + "MetricDefinition", name); + return; } - telemetry::fillMinMaxReadingRange(asyncResp, serviceName, - sensorPath); + std::string sensorPath = matchingUris.begin()->second; + + telemetry::getSensorService( + sensorPath, + [asyncResp, name, odataId = std::move(odataId), + sensorPath, matchingUris = std::move(matchingUris)]( + boost::system::error_code ec3, + const std::string& serviceName) { + if (ec3) + { + messages::internalError(asyncResp->res); + BMCWEB_LOG_ERROR("getServiceSensorFailed: {}", + ec3.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"] = + metric_definition::MetricDataType::Decimal; + asyncResp->res.jsonValue["IsLinear"] = true; + asyncResp->res.jsonValue["Units"] = + sensor_utils::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 From 84fefdcd7add50690c1532028addb8b68b1fed16 Mon Sep 17 00:00:00 2001 From: Reed Frandsen Date: Fri, 16 May 2025 13:40:02 -0500 Subject: [PATCH 3/4] sensorsNodeStr change --- redfish-core/lib/metric_definition.hpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/redfish-core/lib/metric_definition.hpp b/redfish-core/lib/metric_definition.hpp index 3ce15e5d7..84d4b03bb 100644 --- a/redfish-core/lib/metric_definition.hpp +++ b/redfish-core/lib/metric_definition.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -201,6 +202,13 @@ static std::string mapSensorToMetricDefinition(const std::string& sensorPath) return metricDefinitionPath + sensorObjectPath.filename(); } +static std::string& stringViewToStringRef(const std::string_view& sv) +{ + static std::string s; + s = std::string(sv); + return s; +} + template inline void mapRedfishUriToDbusPath(Callback&& callback) { @@ -249,7 +257,8 @@ inline void mapRedfishUriToDbusPath(Callback&& callback) for (const std::string& chassisName : chassisNames) { ++counter->second; - retrieveUriToDbusMap(chassisName, sensors::sensorsNodeStr.data(), + retrieveUriToDbusMap(chassisName, + stringViewToStringRef(sensors::sensorsNodeStr), handleRetrieveUriToDbusMap); } }); From c5734786e3bd3d1b8b54a0a0977d8263169a224f Mon Sep 17 00:00:00 2001 From: Reed Frandsen Date: Wed, 21 May 2025 13:52:12 -0500 Subject: [PATCH 4/4] review comment changes --- redfish-core/lib/metric_definition.hpp | 154 +++++++++++++------------ 1 file changed, 82 insertions(+), 72 deletions(-) diff --git a/redfish-core/lib/metric_definition.hpp b/redfish-core/lib/metric_definition.hpp index 84d4b03bb..a7e894c7b 100644 --- a/redfish-core/lib/metric_definition.hpp +++ b/redfish-core/lib/metric_definition.hpp @@ -316,89 +316,99 @@ inline void requestRoutesMetricDefinitionCollection(App& app) }); } -inline void requestRoutesMetricDefinition(App& app) +inline void handleMetricDefinitionsGet( + App& app, const crow::Request& req, + const std::shared_ptr& asyncResp, + const std::string& name) { - BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricDefinitions//") - .privileges(privileges::getMetricDefinition) - .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 ec2, - const boost::container::flat_map& - uriToDbus) { - if (ec2) - { - messages::internalError(asyncResp->res); - BMCWEB_LOG_ERROR("mapRedfishUriToDbusPath error: {}", - ec2.value()); - return; - } + if (!redfish::setUpRedfishRoute(app, req, asyncResp)) + { + return; + } - std::string odataId = telemetry::metricDefinitionUri + name; - boost::container::flat_map - matchingUris; + telemetry::mapRedfishUriToDbusPath( + [asyncResp, name]( + boost::system::error_code ec2, + const boost::container::flat_map& + uriToDbus) { + if (ec2) + { + messages::internalError(asyncResp->res); + BMCWEB_LOG_ERROR("mapRedfishUriToDbusPath error: {}", + ec2.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); + } + } - for (const auto& [uri, dbusPath] : uriToDbus) + 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 ec3, + const std::string& serviceName) { + if (ec3) { - if (telemetry::mapSensorToMetricDefinition(dbusPath) == - odataId) - { - matchingUris.emplace(uri, dbusPath); - } + messages::internalError(asyncResp->res); + BMCWEB_LOG_ERROR("getServiceSensorFailed: {}", + ec3.value()); + return; } - if (matchingUris.empty()) + 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"] = + metric_definition::MetricDataType::Decimal; + asyncResp->res.jsonValue["IsLinear"] = true; + asyncResp->res.jsonValue["Units"] = + sensor_utils::sensors::toReadingUnits( + sdbusplus::message::object_path{sensorPath} + .parent_path() + .filename()); + + for (const auto& [uri, dbusPath] : matchingUris) { - messages::resourceNotFound(asyncResp->res, - "MetricDefinition", name); - return; + asyncResp->res.jsonValue["MetricProperties"] + .push_back(uri); } - std::string sensorPath = matchingUris.begin()->second; - - telemetry::getSensorService( - sensorPath, - [asyncResp, name, odataId = std::move(odataId), - sensorPath, matchingUris = std::move(matchingUris)]( - boost::system::error_code ec3, - const std::string& serviceName) { - if (ec3) - { - messages::internalError(asyncResp->res); - BMCWEB_LOG_ERROR("getServiceSensorFailed: {}", - ec3.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"] = - metric_definition::MetricDataType::Decimal; - asyncResp->res.jsonValue["IsLinear"] = true; - asyncResp->res.jsonValue["Units"] = - sensor_utils::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); - }); + telemetry::fillMinMaxReadingRange( + asyncResp, serviceName, sensorPath); }); }); + +} + +inline void requestRoutesMetricDefinition(App& app) +{ + BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricDefinitions//") + .privileges(privileges::getMetricDefinition) + .methods(boost::beast::http::verb::get)( + std::bind_front(handleMetricDefinitionsGet, std::ref(app))); + } } // namespace redfish