summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0001-Add-support-for-MetricDefinition-scheme.patch
diff options
context:
space:
mode:
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.patch420
1 files changed, 224 insertions, 196 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
index f53b7013f..c19691cdc 100644
--- 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
@@ -1,12 +1,20 @@
-From e37e30943fcb1ba504658ed07d69f950ccf44585 Mon Sep 17 00:00:00 2001
+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 following categories: temperature,
-power, voltage, current, fan_tach, fan_pwm, utilization.
+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
@@ -14,18 +22,98 @@ Tested:
- 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/get_chassis_names.hpp | 58 ++++
.../include/utils/telemetry_utils.hpp | 2 +
- redfish-core/lib/metric_definition.hpp | 242 ++++++++++++++++++
- redfish-core/lib/sensors.hpp | 25 +-
+ redfish-core/lib/metric_definition.hpp | 258 ++++++++++++++++++
redfish-core/lib/telemetry_service.hpp | 2 +
- 6 files changed, 320 insertions(+), 12 deletions(-)
+ 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
@@ -129,10 +217,10 @@ index 5872350..1b4f75d 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..2443996
+index 0000000..019168b
--- /dev/null
+++ b/redfish-core/lib/metric_definition.hpp
-@@ -0,0 +1,242 @@
+@@ -0,0 +1,258 @@
+#pragma once
+
+#include "async_resp.hpp"
@@ -140,12 +228,34 @@ index 0000000..2443996
+#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)
+{
@@ -168,23 +278,7 @@ index 0000000..2443996
+ std::string(telemetry::metricDefinitionUri) +
+ sensors::toReadingType(type);
+
-+ 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;
-+ }
-+ const std::string* value =
-+ kt->get_ptr<const std::string*>();
-+ if (!value)
-+ {
-+ return false;
-+ }
-+ return *value == odataId;
-+ });
-+
-+ if (it == members.end())
++ if (!containsOdata(members, odataId))
+ {
+ members.push_back({{"@odata.id", odataId}});
+ }
@@ -193,15 +287,76 @@ index 0000000..2443996
+ }
+}
+
++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({{"Login"}})
++ .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";
@@ -211,49 +366,6 @@ index 0000000..2443996
+ "Metric Definition Collection";
+ asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
+ asyncResp->res.jsonValue["Members@odata.count"] = 0;
-+
-+ utils::getChassisNames(
-+ [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;
-+ }
-+
-+ 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);
-+ };
-+
-+ for (const std::string& chassisName : chassisNames)
-+ {
-+ for (const auto& [sensorNode, _] :
-+ sensors::dbus::paths)
-+ {
-+ BMCWEB_LOG_DEBUG << "Chassis: " << chassisName
-+ << " sensor: " << sensorNode;
-+ retrieveUriToDbusMap(
-+ chassisName, sensorNode.data(),
-+ handleRetrieveUriToDbusMap);
-+ }
-+ }
-+ });
+ });
+}
+
@@ -298,12 +410,29 @@ index 0000000..2443996
+ }
+}
+
++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({{"Login"}})
++ .privileges(privileges::getTelemetryService)
+ .methods(boost::beast::http::verb::get)(
+ [](const crow::Request&,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
@@ -315,142 +444,41 @@ index 0000000..2443996
+ return;
+ }
+
-+ asyncResp->res.jsonValue["MetricProperties"] =
-+ nlohmann::json::array();
-+ 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"] =
-+ sensors::toReadingUnits(readingType);
-+
-+ utils::getChassisNames(
-+ [asyncResp, readingType](
-+ boost::system::error_code ec,
-+ const std::vector<std::string>& chassisNames) {
++ 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 << "getChassisNames error: "
-+ << ec.value();
++ BMCWEB_LOG_ERROR
++ << "mapRedfishUriToDbusPath error: "
++ << ec.value();
+ return;
+ }
+
-+ auto handleRetrieveUriToDbusMap =
-+ [asyncResp, readingType](
-+ 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::addMetricProperty(
-+ *asyncResp, readingType, uriToDbus);
-+ };
-+
-+ for (const std::string& chassisName : chassisNames)
-+ {
-+ for (const auto& [sensorNode, dbusPaths] :
-+ sensors::dbus::paths)
-+ {
-+ retrieveUriToDbusMap(
-+ chassisName, sensorNode.data(),
-+ handleRetrieveUriToDbusMap);
-+ }
-+ }
++ 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/sensors.hpp b/redfish-core/lib/sensors.hpp
-index d986565..bccbb94 100644
---- a/redfish-core/lib/sensors.hpp
-+++ b/redfish-core/lib/sensors.hpp
-@@ -111,46 +111,47 @@ inline const char* toReadingType(const std::string& sensorType)
- return "";
- }
-
--inline const char* toReadingUnits(const std::string& sensorType)
-+inline const char* toReadingUnits(const std::string& readingType)
- {
-- if (sensorType == "voltage")
-+ if (readingType == "Voltage")
- {
- return "V";
- }
-- if (sensorType == "power")
-+ if (readingType == "Power")
- {
- return "W";
- }
-- if (sensorType == "current")
-+ if (readingType == "Current")
- {
- return "A";
- }
-- if (sensorType == "fan_tach")
-+ if (readingType == "Rotational")
- {
- return "RPM";
- }
-- if (sensorType == "temperature")
-+ if (readingType == "Temperature")
- {
- return "Cel";
- }
-- if (sensorType == "fan_pwm" || sensorType == "utilization")
-+ if (readingType == "Percent")
- {
- return "%";
- }
-- if (sensorType == "altitude")
-+ if (readingType == "Altitude")
- {
- return "m";
- }
-- if (sensorType == "airflow")
-+ if (readingType == "AirFlow")
- {
- return "cft_i/min";
- }
-- if (sensorType == "energy")
-+ if (readingType == "EnergyJoules")
- {
- return "J";
- }
- return "";
- }
-+
- } // namespace sensors
-
- /**
-@@ -953,11 +954,11 @@ inline void objectInterfacesToJson(
- sensorJson["ReadingType"] = readingType;
- }
-
-- const std::string& readingUnits = sensors::toReadingUnits(sensorType);
-+ const std::string& readingUnits = sensors::toReadingUnits(readingType);
- if (readingUnits.empty())
- {
- BMCWEB_LOG_ERROR << "Redfish cannot map reading unit for "
-- << sensorType;
-+ << readingType;
- }
- else
- {
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