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