summaryrefslogtreecommitdiff
path: root/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch')
-rw-r--r--meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch535
1 files changed, 535 insertions, 0 deletions
diff --git a/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch
new file mode 100644
index 000000000..f7da8a556
--- /dev/null
+++ b/meta-openbmc-mods/meta-common/recipes-phosphor/interfaces/bmcweb/telemetry/0005-Add-support-for-MetricDefinition-scheme.patch
@@ -0,0 +1,535 @@
+From b1da8901b5985d6a77b63ca9eb0570b46528f0bd Mon Sep 17 00:00:00 2001
+From: "Wludzik, Jozef" <jozef.wludzik@intel.com>
+Date: Mon, 8 Jun 2020 17:15:54 +0200
+Subject: [PATCH 5/5] Add support for MetricDefinition scheme
+
+Added MetricDefinition node to redfish core. Now user is able to
+get all possible metrics that are present in system and are
+supported by TelemetryService.
+
+Tested:
+ - Succesfully passed RedfishServiceValidator.py
+ - Validated a presence of MetricDefinition members
+
+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 +
+ redfish-core/include/utils/telemetry_utils.hpp | 2 +
+ redfish-core/lib/metric_definition.hpp | 300 +++++++++++++++++++++++++
+ redfish-core/lib/metric_report.hpp | 65 +++++-
+ redfish-core/lib/sensors.hpp | 43 +++-
+ redfish-core/lib/telemetry_service.hpp | 2 +
+ 6 files changed, 402 insertions(+), 13 deletions(-)
+ create mode 100644 redfish-core/lib/metric_definition.hpp
+
+diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
+index 3d4c117..2a12bf9 100644
+--- a/redfish-core/include/redfish.hpp
++++ b/redfish-core/include/redfish.hpp
+@@ -25,6 +25,7 @@
+ #include "../lib/log_services.hpp"
+ #include "../lib/managers.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"
+@@ -206,6 +207,8 @@ class RedfishService
+ nodes.emplace_back(std::make_unique<HypervisorSystem>(app));
+
+ nodes.emplace_back(std::make_unique<TelemetryService>(app));
++ nodes.emplace_back(std::make_unique<MetricDefinitionCollection>(app));
++ nodes.emplace_back(std::make_unique<MetricDefinition>(app));
+ nodes.emplace_back(
+ 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 6c4e810..bb747c4 100644
+--- a/redfish-core/include/utils/telemetry_utils.hpp
++++ b/redfish-core/include/utils/telemetry_utils.hpp
+@@ -22,6 +22,8 @@ namespace redfish
+ namespace telemetry
+ {
+
++static constexpr const char* metricDefinitionUri =
++ "/redfish/v1/TelemetryService/MetricDefinitions/";
+ static constexpr const char* metricReportDefinitionUri =
+ "/redfish/v1/TelemetryService/MetricReportDefinitions/";
+ static 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..837a068
+--- /dev/null
++++ b/redfish-core/lib/metric_definition.hpp
+@@ -0,0 +1,300 @@
++/*
++// Copyright (c) 2018-2020 Intel Corporation
++//
++// Licensed under the Apache License, Version 2.0 (the "License");
++// you may not use this file except in compliance with the License.
++// You may obtain a copy of the License at
++//
++// http://www.apache.org/licenses/LICENSE-2.0
++//
++// Unless required by applicable law or agreed to in writing, software
++// distributed under the License is distributed on an "AS IS" BASIS,
++// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
++// See the License for the specific language governing permissions and
++// limitations under the License.
++*/
++
++#pragma once
++
++#include "node.hpp"
++#include "sensors.hpp"
++#include "utils/telemetry_utils.hpp"
++
++namespace redfish
++{
++
++namespace chassis
++{
++template <typename F>
++static inline void getChassisNames(F&& callback)
++{
++ const std::array<const char*, 2> interfaces = {
++ "xyz.openbmc_project.Inventory.Item.Board",
++ "xyz.openbmc_project.Inventory.Item.Chassis"};
++
++ dbus::utility::getSubTreePaths(
++ [callback{std::move(callback)}](const boost::system::error_code ec,
++ std::vector<std::string>& chassisList) {
++ if (ec)
++ {
++ return;
++ }
++
++ std::vector<std::string> chassisNames;
++ chassisNames.reserve(chassisList.size());
++ for (auto& chassisPath : chassisList)
++ {
++ auto pos = chassisPath.rfind("/");
++ if (pos == std::string::npos)
++ {
++ continue;
++ }
++ chassisNames.push_back(chassisPath.substr(pos + 1));
++ }
++
++ callback(chassisNames);
++ },
++ "/xyz/openbmc_project/inventory", 0, interfaces);
++}
++} // namespace chassis
++
++class MetricDefinitionCollection : public Node
++{
++ public:
++ MetricDefinitionCollection(CrowApp& app) :
++ Node(app, "/redfish/v1/TelemetryService/MetricDefinitions")
++ {
++ entityPrivileges = {
++ {boost::beast::http::verb::get, {{"Login"}}},
++ {boost::beast::http::verb::head, {{"Login"}}},
++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
++ }
++
++ private:
++ void doGet(crow::Response& res, const crow::Request& req,
++ const std::vector<std::string>& params) override
++ {
++ res.jsonValue["@odata.type"] = "#MetricDefinitionCollection."
++ "MetricDefinitionCollection";
++ 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"] = sensors::dbus::types.size();
++
++ auto asyncResp = std::make_shared<AsyncResp>(res);
++ auto collectionReduce = std::make_shared<CollectionGather>(asyncResp);
++ chassis::getChassisNames(
++ [asyncResp,
++ collectionReduce](const std::vector<std::string>& chassisNames) {
++ for (auto& chassisName : chassisNames)
++ {
++ for (auto& [sensorNode, _] : sensors::dbus::types)
++ {
++ 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) {
++ *collectionReduce += uriToDbus;
++ });
++ }
++ }
++ });
++ }
++
++ class CollectionGather
++ {
++ public:
++ CollectionGather(const std::shared_ptr<AsyncResp>& asyncResp) :
++ asyncResp{asyncResp}
++ {
++ dbusTypes.reserve(sensors::dbus::paths.size());
++ }
++
++ ~CollectionGather()
++ {
++ json_util::dbusPathsToMembersArray(
++ asyncResp->res,
++ std::vector<std::string>(dbusTypes.begin(), dbusTypes.end()),
++ telemetry::metricDefinitionUri);
++ }
++
++ CollectionGather& operator+=(
++ const boost::container::flat_map<std::string, std::string>& rhs)
++ {
++ for (auto& [_, dbusSensor] : rhs)
++ {
++ auto pos = dbusSensor.rfind("/");
++ if (pos == std::string::npos)
++ {
++ BMCWEB_LOG_ERROR << "Received invalid DBus Sensor Path = "
++ << dbusSensor;
++ continue;
++ }
++
++ this->dbusTypes.insert(dbusSensor.substr(0, pos));
++ }
++ return *this;
++ }
++
++ private:
++ const std::shared_ptr<AsyncResp> asyncResp;
++ boost::container::flat_set<std::string> dbusTypes;
++ };
++};
++
++class MetricDefinition : public Node
++{
++ public:
++ MetricDefinition(CrowApp& app) :
++ Node(app, std::string(telemetry::metricDefinitionUri) + "<str>/",
++ std::string())
++ {
++ entityPrivileges = {
++ {boost::beast::http::verb::get, {{"Login"}}},
++ {boost::beast::http::verb::head, {{"Login"}}},
++ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
++ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
++ }
++
++ private:
++ void doGet(crow::Response& res, const crow::Request& req,
++ const std::vector<std::string>& params) override
++ {
++ auto asyncResp = std::make_shared<AsyncResp>(res);
++ if (params.size() != 1)
++ {
++ messages::internalError(asyncResp->res);
++ return;
++ }
++
++ const std::string& id = params[0];
++
++ size_t sensorIndex = 0;
++ for (auto& name : sensors::dbus::names)
++ {
++ if (name == id)
++ {
++ break;
++ }
++ sensorIndex++;
++ }
++ if (sensorIndex >= sensors::dbus::max)
++ {
++ messages::resourceNotFound(asyncResp->res, schemaType, id);
++ return;
++ }
++
++ auto definitionGather =
++ std::make_shared<DefinitionGather>(asyncResp, id);
++ chassis::getChassisNames(
++ [asyncResp, definitionGather,
++ sensorIndex](const std::vector<std::string>& chassisNames) {
++ for (auto& chassisName : chassisNames)
++ {
++ for (auto& [sensorNode, dbusPaths] : sensors::dbus::types)
++ {
++ auto found =
++ std::find(dbusPaths.begin(), dbusPaths.end(),
++ sensors::dbus::paths[sensorIndex]);
++ if (found == dbusPaths.end())
++ {
++ continue;
++ }
++
++ retrieveUriToDbusMap(
++ chassisName, sensorNode.data(),
++ [asyncResp, definitionGather](
++ const boost::beast::http::status status,
++ const boost::container::flat_map<
++ std::string, std::string>& uriToDbus) {
++ *definitionGather += uriToDbus;
++ });
++ }
++ }
++ });
++ }
++
++ class DefinitionGather
++ {
++ public:
++ DefinitionGather(const std::shared_ptr<AsyncResp>& asyncResp,
++ const std::string& id) :
++ id(id),
++ asyncResp{asyncResp}
++ {}
++ ~DefinitionGather()
++ {
++ if (redfishSensors.empty())
++ {
++ messages::resourceNotFound(asyncResp->res, schemaType, id);
++ return;
++ }
++
++ asyncResp->res.jsonValue["MetricProperties"] =
++ nlohmann::json::array();
++ auto& members = asyncResp->res.jsonValue["MetricProperties"];
++ for (auto& redfishSensor : redfishSensors)
++ {
++ members.push_back(redfishSensor);
++ }
++
++ asyncResp->res.jsonValue["Id"] = id;
++ asyncResp->res.jsonValue["Name"] = id;
++ asyncResp->res.jsonValue["@odata.id"] =
++ telemetry::metricDefinitionUri + id;
++ asyncResp->res.jsonValue["@odata.type"] = schemaType;
++ asyncResp->res.jsonValue["MetricDataType"] = "Decimal";
++ asyncResp->res.jsonValue["MetricType"] = "Numeric";
++ asyncResp->res.jsonValue["Implementation"] = "PhysicalSensor";
++ asyncResp->res.jsonValue["IsLinear"] = true;
++ asyncResp->res.jsonValue["TimestampAccuracy"] = "PT0.1S";
++ auto unit = sensorUnits.find(id);
++ if (unit != sensorUnits.end())
++ {
++ asyncResp->res.jsonValue["Units"] = unit->second;
++ }
++ }
++
++ DefinitionGather& operator+=(
++ const boost::container::flat_map<std::string, std::string>& rhs)
++ {
++ for (auto& [redfishSensor, dbusSensor] : rhs)
++ {
++ if (dbusSensor.find(id) != std::string::npos)
++ {
++ this->redfishSensors.push_back(redfishSensor);
++ }
++ }
++ return *this;
++ }
++
++ const std::string id;
++
++ private:
++ const std::shared_ptr<AsyncResp> asyncResp;
++ std::vector<std::string> redfishSensors;
++ const boost::container::flat_map<std::string, std::string> sensorUnits =
++ {{sensors::dbus::names[sensors::dbus::voltage], "V"},
++ {sensors::dbus::names[sensors::dbus::power], "W"},
++ {sensors::dbus::names[sensors::dbus::current], "A"},
++ {sensors::dbus::names[sensors::dbus::fan_tach], "RPM"},
++ {sensors::dbus::names[sensors::dbus::temperature], "Cel"},
++ {sensors::dbus::names[sensors::dbus::utilization], "%"},
++ {sensors::dbus::names[sensors::dbus::fan_pwm], "Duty cycle"}};
++ };
++
++ static constexpr const char* schemaType =
++ "#MetricDefinition.v1_0_3.MetricDefinition";
++};
++
++} // namespace redfish
+diff --git a/redfish-core/lib/metric_report.hpp b/redfish-core/lib/metric_report.hpp
+index 877e7f1..be72b18 100644
+--- a/redfish-core/lib/metric_report.hpp
++++ b/redfish-core/lib/metric_report.hpp
+@@ -91,6 +91,9 @@ class MetricReport : public Node
+ using Readings =
+ std::vector<std::tuple<std::string, std::string, double, int32_t>>;
+ using MetricValues = std::vector<std::map<std::string, std::string>>;
++ using ReadingParameters =
++ std::vector<std::tuple<std::vector<sdbusplus::message::object_path>,
++ std::string, std::string, std::string>>;
+
+ static MetricValues toMetricValues(const Readings& readings)
+ {
+@@ -109,6 +112,49 @@ class MetricReport : public Node
+ return metricValues;
+ }
+
++ static void addMetricDefinition(nlohmann::json& metrics,
++ const ReadingParameters& params)
++ {
++ for (auto& metric : metrics)
++ {
++ if (!metric.contains("MetricId"))
++ {
++ continue;
++ }
++
++ auto& id = metric["MetricId"].get_ref<std::string&>();
++ auto param =
++ std::find_if(params.begin(), params.end(), [id](const auto& x) {
++ return id == std::get<2>(x);
++ });
++ if (param == params.end())
++ {
++ continue;
++ }
++
++ auto& dbusPaths =
++ std::get<std::vector<sdbusplus::message::object_path>>(*param);
++ if (dbusPaths.size() > 1)
++ {
++ continue;
++ }
++
++ auto dbusPath = dbusPaths.begin();
++ for (size_t i = 0; i < sensors::dbus::paths.size(); i++)
++ {
++ if (dbusPath->str.find(sensors::dbus::paths[i]) ==
++ std::string::npos)
++ {
++ continue;
++ }
++ metric["MetricDefinition"]["@odata.id"] =
++ telemetry::metricDefinitionUri +
++ std::string(sensors::dbus::names[i]);
++ break;
++ }
++ }
++ }
++
+ static void getReportProperties(const std::shared_ptr<AsyncResp> asyncResp,
+ const std::string& reportPath,
+ const std::string& id)
+@@ -124,7 +170,8 @@ class MetricReport : public Node
+ [asyncResp](
+ const boost::system::error_code ec,
+ const boost::container::flat_map<
+- std::string, std::variant<Readings, int32_t>>& ret) {
++ std::string,
++ std::variant<Readings, int32_t, ReadingParameters>>& ret) {
+ if (ec)
+ {
+ messages::internalError(asyncResp->res);
+@@ -138,6 +185,22 @@ class MetricReport : public Node
+ json_util::assignIfPresent<Readings>(
+ ret, "Readings", asyncResp->res.jsonValue["MetricValues"],
+ toMetricValues);
++
++ auto found = ret.find("ReadingParameters");
++ if (found != ret.end())
++ {
++ auto params =
++ std::get_if<ReadingParameters>(&found->second);
++ if (params)
++ {
++ auto& jsonValue = asyncResp->res.jsonValue;
++ if (jsonValue.contains("MetricValues"))
++ {
++ addMetricDefinition(jsonValue["MetricValues"],
++ *params);
++ }
++ }
++ }
+ },
+ "xyz.openbmc_project.MonitoringService", reportPath,
+ "xyz.openbmc_project.MonitoringService.Report");
+diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
+index f12bbe0..1fa1009 100644
+--- a/redfish-core/lib/sensors.hpp
++++ b/redfish-core/lib/sensors.hpp
+@@ -53,20 +53,39 @@ static constexpr std::string_view thermal = "Thermal";
+
+ namespace dbus
+ {
++
++enum Index
++{
++ voltage = 0,
++ power,
++ current,
++ fan_tach,
++ temperature,
++ fan_pwm,
++ utilization,
++ max
++};
++
++static constexpr std::array<const char*, max> names = {
++ "voltage", "power", "current", "fan_tach",
++ "temperature", "fan_pwm", "utilization"};
++
++static constexpr std::array<const char*, max> paths = {
++ "/xyz/openbmc_project/sensors/voltage",
++ "/xyz/openbmc_project/sensors/power",
++ "/xyz/openbmc_project/sensors/current",
++ "/xyz/openbmc_project/sensors/fan_tach",
++ "/xyz/openbmc_project/sensors/temperature",
++ "/xyz/openbmc_project/sensors/fan_pwm",
++ "/xyz/openbmc_project/sensors/utilization"};
++
+ static const boost::container::flat_map<std::string_view,
+ std::vector<const char*>>
+- types = {{node::power,
+- {"/xyz/openbmc_project/sensors/voltage",
+- "/xyz/openbmc_project/sensors/power"}},
+- {node::sensors,
+- {"/xyz/openbmc_project/sensors/power",
+- "/xyz/openbmc_project/sensors/current",
+- "/xyz/openbmc_project/sensors/utilization"}},
+- {node::thermal,
+- {"/xyz/openbmc_project/sensors/fan_tach",
+- "/xyz/openbmc_project/sensors/temperature",
+- "/xyz/openbmc_project/sensors/fan_pwm"}}};
+-}
++ types = {
++ {node::power, {paths[voltage], paths[power]}},
++ {node::sensors, {paths[power], paths[current], paths[utilization]}},
++ {node::thermal, {paths[fan_tach], paths[temperature], paths[fan_pwm]}}};
++} // namespace dbus
+ } // namespace sensors
+
+ /**
+diff --git a/redfish-core/lib/telemetry_service.hpp b/redfish-core/lib/telemetry_service.hpp
+index a410700..79e4154 100644
+--- a/redfish-core/lib/telemetry_service.hpp
++++ b/redfish-core/lib/telemetry_service.hpp
+@@ -52,6 +52,8 @@ class TelemetryService : public Node
+
+ res.jsonValue["LogService"]["@odata.id"] =
+ "/redfish/v1/Managers/bmc/LogServices/Journal";
++ res.jsonValue["MetricDefinitions"]["@odata.id"] =
++ "/redfish/v1/TelemetryService/MetricDefinitions";
+ res.jsonValue["MetricReportDefinitions"]["@odata.id"] =
+ "/redfish/v1/TelemetryService/MetricReportDefinitions";
+ res.jsonValue["MetricReports"]["@odata.id"] =
+--
+2.16.6
+