diff options
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.patch | 535 |
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 + |