summaryrefslogtreecommitdiff
path: root/redfish-core
diff options
context:
space:
mode:
authorAppaRao Puli <apparao.puli@linux.intel.com>2020-04-25 03:34:05 +0300
committerAppaRao Puli <apparao.puli@linux.intel.com>2020-05-14 04:09:21 +0300
commit156d6b00a9dc06ac9f618ecd8d5fc6b1b49d5be4 (patch)
tree874fd69b33be5f9da033b10b01b340b74595b1e2 /redfish-core
parente46946ac9e5c72dbd63d36e420dba417243346bb (diff)
downloadbmcweb-156d6b00a9dc06ac9f618ecd8d5fc6b1b49d5be4.tar.xz
EventService: Add MetricReport support
Add Telemetry metric report support to EventService. - Adding MetricReport support to schema implemenation. - Dynamically register and unregister the metric report signal. - Reads Telemtry data using D-Bus calls. - Filter the metric reports depending on user configured MetricReportDefinition. - Format the Telemetry readings as per MetricReport schema. - Send the formatted data to the client. Tested: - HTTP client successfully received asynchronous metric reports data. - valdiated the register and unregister by adding and deleting subscriptions. - Ran Redfish validator successfully. Change-Id: I7b59ac3ecad169a7959a800730dbc2fe85baf068 Signed-off-by: AppaRao Puli <apparao.puli@linux.intel.com>
Diffstat (limited to 'redfish-core')
-rw-r--r--redfish-core/include/event_service_manager.hpp175
-rw-r--r--redfish-core/lib/event_service.hpp15
2 files changed, 186 insertions, 4 deletions
diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
index 553fc5f46f..297e141099 100644
--- a/redfish-core/include/event_service_manager.hpp
+++ b/redfish-core/include/event_service_manager.hpp
@@ -32,6 +32,13 @@
namespace redfish
{
+
+using ReadingsObjType =
+ std::vector<std::tuple<std::string, std::string, double, std::string>>;
+
+static constexpr const char* eventFormatType = "Event";
+static constexpr const char* metricReportFormatType = "MetricReport";
+
#ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
constexpr const char* redfishEventLogFile = "/var/log/redfish";
constexpr const uint32_t inotifyFileAction = IN_MODIFY;
@@ -263,6 +270,7 @@ class Subscription
std::vector<std::string> registryMsgIds;
std::vector<std::string> registryPrefixes;
std::vector<nlohmann::json> httpHeaders; // key-value pair
+ std::vector<nlohmann::json> metricReportDefinitions;
Subscription(const Subscription&) = delete;
Subscription& operator=(const Subscription&) = delete;
@@ -387,6 +395,48 @@ class Subscription
}
#endif
+ void filterAndSendReports(const std::string& id,
+ const std::string& readingsTs,
+ const ReadingsObjType& readings)
+ {
+ std::string metricReportDef =
+ "/redfish/v1/TelemetryService/MetricReportDefinitions/" + id;
+
+ // Empty list means no filter. Send everything.
+ if (metricReportDefinitions.size())
+ {
+ if (std::find(metricReportDefinitions.begin(),
+ metricReportDefinitions.end(),
+ metricReportDef) == metricReportDefinitions.end())
+ {
+ return;
+ }
+ }
+
+ nlohmann::json metricValuesArray = nlohmann::json::array();
+ for (const auto& it : readings)
+ {
+ metricValuesArray.push_back({});
+ nlohmann::json& entry = metricValuesArray.back();
+
+ entry = {{"MetricId", std::get<0>(it)},
+ {"MetricProperty", std::get<1>(it)},
+ {"MetricValue", std::to_string(std::get<2>(it))},
+ {"Timestamp", std::get<3>(it)}};
+ }
+
+ nlohmann::json msg = {
+ {"@odata.id", "/redfish/v1/TelemetryService/MetricReports/" + id},
+ {"@odata.type", "#MetricReport.v1_3_0.MetricReport"},
+ {"Id", id},
+ {"Name", id},
+ {"Timestamp", readingsTs},
+ {"MetricReportDefinition", {{"@odata.id", metricReportDef}}},
+ {"MetricValues", metricValuesArray}};
+
+ this->sendEvent(msg.dump());
+ }
+
private:
uint64_t eventSeqNum;
std::string host;
@@ -404,7 +454,7 @@ class EventServiceManager
EventServiceManager(EventServiceManager&&) = delete;
EventServiceManager& operator=(EventServiceManager&&) = delete;
- EventServiceManager()
+ EventServiceManager() : noOfMetricReportSubscribers(0)
{
// TODO: Read the persistent data from store and populate.
// Populating with default.
@@ -414,6 +464,8 @@ class EventServiceManager
}
std::string lastEventTStr;
+ size_t noOfMetricReportSubscribers;
+ std::shared_ptr<sdbusplus::bus::match::match> matchTelemetryMonitor;
boost::container::flat_map<std::string, std::shared_ptr<Subscription>>
subscriptionsMap;
@@ -471,6 +523,15 @@ class EventServiceManager
return std::string("");
}
+ if (subValue->eventFormatType == metricReportFormatType)
+ {
+ // If it is first entry, Register Metrics report signal.
+ if ((++noOfMetricReportSubscribers == 1))
+ {
+ registerMetricReportSignal();
+ }
+ }
+
updateSubscriptionData();
#ifndef BMCWEB_ENABLE_REDFISH_DBUS_LOG_ENTRIES
@@ -497,6 +558,15 @@ class EventServiceManager
auto obj = subscriptionsMap.find(id);
if (obj != subscriptionsMap.end())
{
+ std::shared_ptr<Subscription> entry = obj->second;
+ if (entry->eventFormatType == metricReportFormatType)
+ {
+ if ((--noOfMetricReportSubscribers == 0))
+ {
+ unregisterMetricReportSignal();
+ }
+ }
+
subscriptionsMap.erase(obj);
updateSubscriptionData();
}
@@ -699,6 +769,109 @@ class EventServiceManager
}
#endif
+
+ void getMetricReading(const std::string& service,
+ const std::string& objPath, const std::string& intf)
+ {
+ std::size_t found = objPath.find_last_of("/");
+ if (found == std::string::npos)
+ {
+ BMCWEB_LOG_DEBUG << "Invalid objPath received";
+ return;
+ }
+
+ std::string idStr = objPath.substr(found + 1);
+ if (idStr.empty())
+ {
+ BMCWEB_LOG_DEBUG << "Invalid ID in objPath";
+ return;
+ }
+
+ crow::connections::systemBus->async_method_call(
+ [idStr{std::move(idStr)}](
+ const boost::system::error_code ec,
+ boost::container::flat_map<
+ std::string, std::variant<std::string, ReadingsObjType>>&
+ resp) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG
+ << "D-Bus call failed to GetAll metric readings.";
+ return;
+ }
+
+ const std::string* timestampPtr =
+ std::get_if<std::string>(&resp["Timestamp"]);
+ if (!timestampPtr)
+ {
+ BMCWEB_LOG_DEBUG << "Failed to Get timestamp.";
+ return;
+ }
+
+ ReadingsObjType* readingsPtr =
+ std::get_if<ReadingsObjType>(&resp["Readings"]);
+ if (!readingsPtr)
+ {
+ BMCWEB_LOG_DEBUG << "Failed to Get Readings property.";
+ return;
+ }
+
+ if (!readingsPtr->size())
+ {
+ BMCWEB_LOG_DEBUG << "No metrics report to be transferred";
+ return;
+ }
+
+ for (const auto& it :
+ EventServiceManager::getInstance().subscriptionsMap)
+ {
+ std::shared_ptr<Subscription> entry = it.second;
+ if (entry->eventFormatType == metricReportFormatType)
+ {
+ entry->filterAndSendReports(idStr, *timestampPtr,
+ *readingsPtr);
+ }
+ }
+ },
+ service, objPath, "org.freedesktop.DBus.Properties", "GetAll",
+ intf);
+ }
+
+ void unregisterMetricReportSignal()
+ {
+ BMCWEB_LOG_DEBUG << "Metrics report signal - Unregister";
+ matchTelemetryMonitor.reset();
+ matchTelemetryMonitor = nullptr;
+ }
+
+ void registerMetricReportSignal()
+ {
+ if (matchTelemetryMonitor)
+ {
+ BMCWEB_LOG_DEBUG << "Metrics report signal - Already registered.";
+ return;
+ }
+
+ BMCWEB_LOG_DEBUG << "Metrics report signal - Register";
+ std::string matchStr(
+ "type='signal',member='ReportUpdate', "
+ "interface='xyz.openbmc_project.MonitoringService.Report'");
+
+ matchTelemetryMonitor = std::make_shared<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus, matchStr,
+ [this](sdbusplus::message::message& msg) {
+ if (msg.is_method_error())
+ {
+ BMCWEB_LOG_ERROR << "TelemetryMonitor Signal error";
+ return;
+ }
+
+ std::string service = msg.get_sender();
+ std::string objPath = msg.get_path();
+ std::string intf = msg.get_interface();
+ getMetricReading(service, objPath, intf);
+ });
+ }
};
} // namespace redfish
diff --git a/redfish-core/lib/event_service.hpp b/redfish-core/lib/event_service.hpp
index 3e3435ff49..63302d6072 100644
--- a/redfish-core/lib/event_service.hpp
+++ b/redfish-core/lib/event_service.hpp
@@ -19,8 +19,8 @@
namespace redfish
{
-static constexpr const std::array<const char*, 1> supportedEvtFormatTypes = {
- "Event"};
+static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
+ eventFormatType, metricReportFormatType};
static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
"Base", "OpenBMC", "Task"};
static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
@@ -217,13 +217,15 @@ class EventDestinationCollection : public Node
std::optional<std::vector<std::string>> msgIds;
std::optional<std::vector<std::string>> regPrefixes;
std::optional<std::vector<nlohmann::json>> headers;
+ std::optional<std::vector<nlohmann::json>> metricReportDefinitions;
if (!json_util::readJson(
req, res, "Destination", destUrl, "Context", context,
"Protocol", protocol, "SubscriptionType", subscriptionType,
"EventFormatType", eventFormatType, "HttpHeaders", headers,
"RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
- "DeliveryRetryPolicy", retryPolicy))
+ "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
+ metricReportDefinitions))
{
return;
}
@@ -373,6 +375,11 @@ class EventDestinationCollection : public Node
subValue->retryPolicy = "TerminateAfterRetries";
}
+ if (metricReportDefinitions)
+ {
+ subValue->metricReportDefinitions = *metricReportDefinitions;
+ }
+
std::string id =
EventServiceManager::getInstance().addSubscription(subValue);
if (id.empty())
@@ -441,6 +448,8 @@ class EventDestination : public Node
subValue->registryPrefixes;
asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
+ asyncResp->res.jsonValue["MetricReportDefinitions"] =
+ subValue->metricReportDefinitions;
}
void doPatch(crow::Response& res, const crow::Request& req,