xref: /openbmc/bmcweb/features/redfish/lib/metric_report.hpp (revision 168e20c1306e3e689907ba43e14ea679e2328611)
1 #pragma once
2 
3 #include "utils/collection.hpp"
4 #include "utils/telemetry_utils.hpp"
5 
6 #include <app.hpp>
7 #include <dbus_utility.hpp>
8 #include <registries/privilege_registry.hpp>
9 
10 namespace redfish
11 {
12 
13 namespace telemetry
14 {
15 
16 using Readings =
17     std::vector<std::tuple<std::string, std::string, double, uint64_t>>;
18 using TimestampReadings = std::tuple<uint64_t, Readings>;
19 
20 inline nlohmann::json toMetricValues(const Readings& readings)
21 {
22     nlohmann::json metricValues = nlohmann::json::array_t();
23 
24     for (auto& [id, metadata, sensorValue, timestamp] : readings)
25     {
26         metricValues.push_back({
27             {"MetricId", id},
28             {"MetricProperty", metadata},
29             {"MetricValue", std::to_string(sensorValue)},
30             {"Timestamp", crow::utility::getDateTimeUint(timestamp)},
31         });
32     }
33 
34     return metricValues;
35 }
36 
37 inline bool fillReport(nlohmann::json& json, const std::string& id,
38                        const dbus::utility::DbusVariantType& var)
39 {
40     json["@odata.type"] = "#MetricReport.v1_3_0.MetricReport";
41     json["@odata.id"] = telemetry::metricReportUri + std::string("/") + id;
42     json["Id"] = id;
43     json["Name"] = id;
44     json["MetricReportDefinition"]["@odata.id"] =
45         telemetry::metricReportDefinitionUri + std::string("/") + id;
46 
47     const TimestampReadings* timestampReadings =
48         std::get_if<TimestampReadings>(&var);
49     if (!timestampReadings)
50     {
51         BMCWEB_LOG_ERROR << "Property type mismatch or property is missing";
52         return false;
53     }
54 
55     const auto& [timestamp, readings] = *timestampReadings;
56     json["Timestamp"] = crow::utility::getDateTimeUint(timestamp);
57     json["MetricValues"] = toMetricValues(readings);
58     return true;
59 }
60 } // namespace telemetry
61 
62 inline void requestRoutesMetricReportCollection(App& app)
63 {
64     BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReports/")
65         .privileges(redfish::privileges::getMetricReportCollection)
66         .methods(boost::beast::http::verb::get)(
67             [](const crow::Request&,
68                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
69                 asyncResp->res.jsonValue["@odata.type"] =
70                     "#MetricReportCollection.MetricReportCollection";
71                 asyncResp->res.jsonValue["@odata.id"] =
72                     "/redfish/v1/TelemetryService/MetricReports";
73                 asyncResp->res.jsonValue["Name"] = "Metric Report Collection";
74                 const std::vector<const char*> interfaces{
75                     telemetry::reportInterface};
76                 collection_util::getCollectionMembers(
77                     asyncResp, telemetry::metricReportUri, interfaces,
78                     "/xyz/openbmc_project/Telemetry/Reports/TelemetryService");
79             });
80 }
81 
82 inline void requestRoutesMetricReport(App& app)
83 {
84     BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReports/<str>/")
85         .privileges(redfish::privileges::getMetricReport)
86         .methods(boost::beast::http::verb::get)(
87             [](const crow::Request&,
88                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
89                const std::string& id) {
90                 const std::string reportPath = telemetry::getDbusReportPath(id);
91                 crow::connections::systemBus->async_method_call(
92                     [asyncResp, id,
93                      reportPath](const boost::system::error_code& ec) {
94                         if (ec.value() == EBADR ||
95                             ec == boost::system::errc::host_unreachable)
96                         {
97                             messages::resourceNotFound(asyncResp->res,
98                                                        "MetricReport", id);
99                             return;
100                         }
101                         if (ec)
102                         {
103                             BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
104                             messages::internalError(asyncResp->res);
105                             return;
106                         }
107 
108                         crow::connections::systemBus->async_method_call(
109                             [asyncResp,
110                              id](const boost::system::error_code ec,
111                                  const dbus::utility::DbusVariantType& ret) {
112                                 if (ec)
113                                 {
114                                     BMCWEB_LOG_ERROR
115                                         << "respHandler DBus error " << ec;
116                                     messages::internalError(asyncResp->res);
117                                     return;
118                                 }
119 
120                                 if (!telemetry::fillReport(
121                                         asyncResp->res.jsonValue, id, ret))
122                                 {
123                                     messages::internalError(asyncResp->res);
124                                 }
125                             },
126                             telemetry::service, reportPath,
127                             "org.freedesktop.DBus.Properties", "Get",
128                             telemetry::reportInterface, "Readings");
129                     },
130                     telemetry::service, reportPath, telemetry::reportInterface,
131                     "Update");
132             });
133 }
134 } // namespace redfish
135