diff options
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch')
-rw-r--r-- | meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch | 400 |
1 files changed, 226 insertions, 174 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch index 03feec633..8b08c6c5e 100644 --- a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch +++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0003-Add-support-for-MetricDefinition-scheme.patch @@ -1,7 +1,7 @@ -From b6ccf463b4cfb8df4a904f06c5f4852029a96c50 Mon Sep 17 00:00:00 2001 -From: "Wludzik, Jozef" <jozef.wludzik@intel.com> -Date: Tue, 15 Dec 2020 12:28:17 +0100 -Subject: [PATCH 3/4] Add support for MetricDefinition scheme +From d664a145a96a642597c74819c183410d4a04fce0 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 @@ -23,16 +23,16 @@ Change-Id: I3086e1302e1ba2e5442d1367939fd5507a0cbc00 --- redfish-core/include/redfish.hpp | 3 + .../include/utils/telemetry_utils.hpp | 2 + - redfish-core/lib/metric_definition.hpp | 283 ++++++++++++++++++ + redfish-core/lib/metric_definition.hpp | 335 ++++++++++++++++++ redfish-core/lib/telemetry_service.hpp | 2 + - 4 files changed, 290 insertions(+) + 4 files changed, 342 insertions(+) create mode 100644 redfish-core/lib/metric_definition.hpp diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp -index aad28ac..dfcb8cd 100644 +index 7a14969..d280a86 100644 --- a/redfish-core/include/redfish.hpp +++ b/redfish-core/include/redfish.hpp -@@ -25,6 +25,7 @@ +@@ -26,6 +26,7 @@ #include "../lib/managers.hpp" #include "../lib/memory.hpp" #include "../lib/message_registries.hpp" @@ -40,7 +40,7 @@ index aad28ac..dfcb8cd 100644 #include "../lib/metric_report.hpp" #include "../lib/metric_report_definition.hpp" #include "../lib/network_protocol.hpp" -@@ -215,6 +216,8 @@ class RedfishService +@@ -219,6 +220,8 @@ class RedfishService nodes.emplace_back(std::make_unique<HypervisorResetActionInfo>(app)); nodes.emplace_back(std::make_unique<TelemetryService>(app)); @@ -50,7 +50,7 @@ index aad28ac..dfcb8cd 100644 std::make_unique<MetricReportDefinitionCollection>(app)); nodes.emplace_back(std::make_unique<MetricReportDefinition>(app)); diff --git a/redfish-core/include/utils/telemetry_utils.hpp b/redfish-core/include/utils/telemetry_utils.hpp -index 0a3af5f..54b5133 100644 +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 @@ -64,12 +64,13 @@ index 0a3af5f..54b5133 100644 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..f9c7779 +index 0000000..515fe86 --- /dev/null +++ b/redfish-core/lib/metric_definition.hpp -@@ -0,0 +1,283 @@ +@@ -0,0 +1,335 @@ +#pragma once + ++#include "async_resp.hpp" +#include "node.hpp" +#include "sensors.hpp" +#include "utils/telemetry_utils.hpp" @@ -80,150 +81,138 @@ index 0000000..f9c7779 +namespace utils +{ + ++class AsyncRespWithFinalizer ++{ ++ public: ++ AsyncRespWithFinalizer( ++ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) : ++ asyncResp(asyncResp) ++ {} ++ ++ AsyncRespWithFinalizer(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, ++ std::function<void(crow::Response&)> finalizer) : ++ asyncResp(asyncResp), ++ finalizer(std::move(finalizer)) ++ {} ++ ++ AsyncRespWithFinalizer(const AsyncRespWithFinalizer&) = delete; ++ AsyncRespWithFinalizer(AsyncRespWithFinalizer&&) = delete; ++ ++ ~AsyncRespWithFinalizer() ++ { ++ if (finalizer) ++ { ++ try ++ { ++ finalizer(asyncResp->res); ++ } ++ catch (const std::exception& e) ++ { ++ BMCWEB_LOG_ERROR << "Executing finalizer failed: " << e.what(); ++ messages::internalError(asyncResp->res); ++ } ++ } ++ } ++ ++ void setFinalizer(std::function<void(crow::Response&)> newFinalizer) ++ { ++ finalizer = std::move(newFinalizer); ++ } ++ ++ private: ++ std::shared_ptr<bmcweb::AsyncResp> asyncResp; ++ std::function<void(crow::Response&)> finalizer; ++ ++ public: ++ crow::Response& res = asyncResp->res; ++}; ++ +template <typename F> -+inline void getChassisNames(F&& cb, const std::shared_ptr<AsyncResp>& asyncResp) ++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( -+ [asyncResp, -+ callback = std::move(cb)](const boost::system::error_code ec, -+ std::vector<std::string>& chassis) { ++ [callback = std::move(cb)](const boost::system::error_code ec, ++ const std::vector<std::string>& chassis) { ++ std::vector<std::string> chassisNames; ++ + if (ec) + { -+ messages::internalError(asyncResp->res); -+ BMCWEB_LOG_DEBUG << "DBus call error: " << ec.value(); ++ callback(ec, chassisNames); + return; + } + -+ std::vector<std::string> chassisNames; + chassisNames.reserve(chassis.size()); -+ for (const auto& path : chassis) ++ for (const std::string& path : chassis) + { + sdbusplus::message::object_path dbusPath = path; + std::string name = dbusPath.filename(); + if (name.empty()) + { -+ messages::internalError(asyncResp->res); -+ BMCWEB_LOG_ERROR << "Invalid chassis: " << dbusPath.str; ++ callback(boost::system::errc::make_error_code( ++ boost::system::errc::invalid_argument), ++ chassisNames); + return; + } + chassisNames.emplace_back(std::move(name)); + } + -+ callback(chassisNames); ++ 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 telemetry +{ + -+class MetricDefinitionCollectionReduce ++void addMembers(crow::Response& res, ++ const boost::container::flat_map<std::string, std::string>& el) +{ -+ public: -+ MetricDefinitionCollectionReduce( -+ const std::shared_ptr<AsyncResp>& asyncResp) : -+ asyncResp{asyncResp} -+ {} -+ -+ ~MetricDefinitionCollectionReduce() ++ for (const auto& [_, dbusSensor] : el) + { -+ if (asyncResp->res.result() != boost::beast::http::status::ok) ++ sdbusplus::message::object_path path(dbusSensor); ++ sdbusplus::message::object_path parentPath = path.parent_path(); ++ std::string type = parentPath.filename(); ++ if (type.empty()) + { -+ return; ++ BMCWEB_LOG_ERROR << "Received invalid DBus Sensor Path = " ++ << dbusSensor; ++ continue; + } + -+ nlohmann::json& members = asyncResp->res.jsonValue["Members"]; -+ members = nlohmann::json::array(); ++ nlohmann::json& members = res.jsonValue["Members"]; + -+ for (const std::string& type : dbusTypes) -+ { -+ members.push_back( -+ {{"@odata.id", telemetry::metricDefinitionUri + type}}); -+ } -+ asyncResp->res.jsonValue["Members@odata.count"] = members.size(); -+ } ++ const std::string odataId = ++ telemetry::metricDefinitionUri + std::move(type); + -+ void insert(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(); -+ std::string type = parentPath.filename(); -+ if (type.empty()) -+ { -+ BMCWEB_LOG_ERROR << "Received invalid DBus Sensor Path = " -+ << dbusSensor; -+ continue; -+ } ++ const auto it = ++ std::find_if(members.begin(), members.end(), ++ [&odataId](const nlohmann::json& item) { ++ auto kt = item.find("@odata.id"); ++ if (kt == item.end()) ++ { ++ return false; ++ } ++ return kt->get<std::string>() == odataId; ++ }); + -+ dbusTypes.insert(std::move(type)); -+ } -+ } -+ -+ private: -+ const std::shared_ptr<AsyncResp> asyncResp; -+ boost::container::flat_set<std::string> dbusTypes; -+}; -+ -+class MetricDefinitionReduce -+{ -+ public: -+ MetricDefinitionReduce(const std::shared_ptr<AsyncResp>& asyncResp, -+ const std::string& id) : -+ id(id), -+ pattern{'/' + id + '/'}, asyncResp{asyncResp} -+ {} -+ ~MetricDefinitionReduce() -+ { -+ if (asyncResp->res.result() != boost::beast::http::status::ok) -+ { -+ return; -+ } -+ if (redfishSensors.empty()) ++ if (it == members.end()) + { -+ messages::resourceNotFound(asyncResp->res, "MetricDefinition", id); -+ return; ++ members.push_back({{"@odata.id", odataId}}); + } + -+ asyncResp->res.jsonValue["MetricProperties"] = redfishSensors; -+ asyncResp->res.jsonValue["Id"] = id; -+ asyncResp->res.jsonValue["Name"] = id; -+ asyncResp->res.jsonValue["@odata.id"] = -+ telemetry::metricDefinitionUri + id; -+ 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["Units"] = sensors::toReadingUnits(id); -+ } -+ -+ void insert(const boost::container::flat_map<std::string, std::string>& el) -+ { -+ for (const auto& [redfishSensor, dbusSensor] : el) -+ { -+ if (dbusSensor.find(pattern) != std::string::npos) -+ { -+ redfishSensors.push_back(redfishSensor); -+ } -+ } ++ res.jsonValue["Members@odata.count"] = members.size(); + } ++} + -+ private: -+ const std::string id; -+ const std::string pattern; -+ const std::shared_ptr<AsyncResp> asyncResp; -+ std::vector<std::string> redfishSensors; -+}; +} // namespace telemetry + +class MetricDefinitionCollection : public Node @@ -242,52 +231,83 @@ index 0000000..f9c7779 + } + + private: -+ void doGet(crow::Response& res, const crow::Request&, -+ const std::vector<std::string>&) override ++ void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, ++ const crow::Request&, const std::vector<std::string>&) override + { -+ res.jsonValue["@odata.type"] = "#MetricDefinitionCollection." -+ "MetricDefinitionCollection"; -+ res.jsonValue["@odata.id"] = ++ asyncResp->res.jsonValue["@odata.type"] = "#MetricDefinitionCollection." ++ "MetricDefinitionCollection"; ++ asyncResp->res.jsonValue["@odata.id"] = + "/redfish/v1/TelemetryService/MetricDefinitions"; -+ res.jsonValue["Name"] = "Metric Definition Collection"; -+ res.jsonValue["Members"] = nlohmann::json::array(); -+ res.jsonValue["Members@odata.count"] = 0; ++ asyncResp->res.jsonValue["Name"] = "Metric Definition Collection"; ++ asyncResp->res.jsonValue["Members"] = nlohmann::json::array(); ++ asyncResp->res.jsonValue["Members@odata.count"] = 0; ++ ++ auto handleRetrieveUriToDbusMap = ++ [asyncResp]( ++ 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); ++ messages::internalError(asyncResp->res); ++ return; ++ } ++ telemetry::addMembers(asyncResp->res, uriToDbus); ++ }; + -+ auto asyncResp = std::make_shared<AsyncResp>(res); + utils::getChassisNames( -+ [asyncResp](const std::vector<std::string>& chassisNames) { -+ auto collectionReduce = std::make_shared< -+ telemetry::MetricDefinitionCollectionReduce>(asyncResp); ++ [handleRetrieveUriToDbusMap = std::move(handleRetrieveUriToDbusMap), ++ asyncResp](boost::system::error_code ec, ++ const std::vector<std::string>& chassisNames) { ++ if (ec) ++ { ++ messages::internalError(asyncResp->res); ++ BMCWEB_LOG_ERROR << "getChassisNames error: " << ec.value(); ++ return; ++ } ++ + for (const std::string& chassisName : chassisNames) + { + for (const auto& [sensorNode, _] : sensors::dbus::paths) + { -+ BMCWEB_LOG_INFO << "Chassis: " << chassisName -+ << " sensor: " << sensorNode; -+ retrieveUriToDbusMap( -+ chassisName, sensorNode.data(), -+ [asyncResp, collectionReduce]( -+ 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); -+ messages::internalError(asyncResp->res); -+ return; -+ } -+ collectionReduce->insert(uriToDbus); -+ }); ++ BMCWEB_LOG_DEBUG << "Chassis: " << chassisName ++ << " sensor: " << sensorNode; ++ retrieveUriToDbusMap(chassisName, sensorNode.data(), ++ handleRetrieveUriToDbusMap); + } + } -+ }, -+ asyncResp); ++ }); + } +}; + ++namespace telemetry ++{ ++ ++void addMetricProperty( ++ utils::AsyncRespWithFinalizer& asyncResp, const std::string& id, ++ 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 (sensorId == id) ++ { ++ metricProperties.push_back(redfishSensor); ++ } ++ } ++ } ++} ++ ++} // namespace telemetry ++ +class MetricDefinition : public Node +{ + public: @@ -305,65 +325,97 @@ index 0000000..f9c7779 + } + + private: -+ void doGet(crow::Response& res, const crow::Request&, ++ void doGet(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, ++ const crow::Request&, + const std::vector<std::string>& params) override + { -+ auto asyncResp = std::make_shared<AsyncResp>(res); ++ auto telemetryAsyncResp = ++ std::make_shared<utils::AsyncRespWithFinalizer>(asyncResp); ++ + if (params.size() != 1) + { -+ messages::internalError(asyncResp->res); ++ messages::internalError(telemetryAsyncResp->res); + return; + } + + const std::string& id = params[0]; ++ telemetryAsyncResp->setFinalizer([id](crow::Response& res) { ++ if (res.jsonValue["MetricProperties"].empty()) ++ { ++ messages::resourceNotFound(res, "MetricDefinition", id); ++ } ++ }); ++ ++ telemetryAsyncResp->res.jsonValue["MetricProperties"] = ++ nlohmann::json::array(); ++ telemetryAsyncResp->res.jsonValue["Id"] = id; ++ telemetryAsyncResp->res.jsonValue["Name"] = id; ++ telemetryAsyncResp->res.jsonValue["@odata.id"] = ++ telemetry::metricDefinitionUri + id; ++ telemetryAsyncResp->res.jsonValue["@odata.type"] = ++ "#MetricDefinition.v1_0_3.MetricDefinition"; ++ telemetryAsyncResp->res.jsonValue["MetricDataType"] = "Decimal"; ++ telemetryAsyncResp->res.jsonValue["MetricType"] = "Numeric"; ++ telemetryAsyncResp->res.jsonValue["IsLinear"] = true; ++ telemetryAsyncResp->res.jsonValue["Units"] = ++ sensors::toReadingUnits(id); ++ ++ auto handleRetrieveUriToDbusMap = ++ [telemetryAsyncResp, ++ id](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); ++ messages::internalError(telemetryAsyncResp->res); ++ return; ++ } ++ telemetry::addMetricProperty(*telemetryAsyncResp, id, ++ uriToDbus); ++ }; ++ + utils::getChassisNames( -+ [asyncResp, id](const std::vector<std::string>& chassisNames) { -+ auto definitionGather = -+ std::make_shared<telemetry::MetricDefinitionReduce>( -+ asyncResp, id); ++ [handleRetrieveUriToDbusMap = std::move(handleRetrieveUriToDbusMap), ++ telemetryAsyncResp, ++ id](boost::system::error_code ec, ++ const std::vector<std::string>& chassisNames) { ++ if (ec) ++ { ++ messages::internalError(telemetryAsyncResp->res); ++ BMCWEB_LOG_ERROR << "getChassisNames error: " << ec.value(); ++ return; ++ } ++ + for (const std::string& chassisName : chassisNames) + { + for (const auto& [sensorNode, dbusPaths] : + sensors::dbus::paths) + { -+ retrieveUriToDbusMap( -+ chassisName, sensorNode.data(), -+ [asyncResp, definitionGather]( -+ 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); -+ messages::internalError(asyncResp->res); -+ return; -+ } -+ definitionGather->insert(uriToDbus); -+ }); ++ retrieveUriToDbusMap(chassisName, sensorNode.data(), ++ handleRetrieveUriToDbusMap); + } + } -+ }, -+ asyncResp); ++ }); + } +}; + +} // namespace redfish diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp -index 61ca891..a8c8b03 100644 +index 9ec0737..de9c800 100644 --- a/redfish-core/lib/telemetry_service.hpp +++ b/redfish-core/lib/telemetry_service.hpp @@ -32,6 +32,8 @@ class TelemetryService : public Node - res.jsonValue["Id"] = "TelemetryService"; - res.jsonValue["Name"] = "Telemetry Service"; + asyncResp->res.jsonValue["Id"] = "TelemetryService"; + asyncResp->res.jsonValue["Name"] = "Telemetry Service"; -+ res.jsonValue["MetricDefinitions"]["@odata.id"] = ++ asyncResp->res.jsonValue["MetricDefinitions"]["@odata.id"] = + "/redfish/v1/TelemetryService/MetricDefinitions"; - res.jsonValue["MetricReportDefinitions"]["@odata.id"] = + asyncResp->res.jsonValue["MetricReportDefinitions"]["@odata.id"] = "/redfish/v1/TelemetryService/MetricReportDefinitions"; - res.jsonValue["MetricReports"]["@odata.id"] = + asyncResp->res.jsonValue["MetricReports"]["@odata.id"] = -- 2.17.1 |