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 bool fillReport(nlohmann::json& json, const std::string& id,
38                        const std::variant<TimestampReadings>& 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"] =
57         crow::utility::getDateTime(static_cast<time_t>(timestamp));
58     json["MetricValues"] = toMetricValues(readings);
59     return true;
60 }
61 } // namespace telemetry
62 
63 inline void requestRoutesMetricReportCollection(App& app)
64 {
65     BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReports/")
66         .privileges(redfish::privileges::getMetricReportCollection)
67         .methods(boost::beast::http::verb::get)(
68             [](const crow::Request&,
69                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
70                 asyncResp->res.jsonValue["@odata.type"] =
71                     "#MetricReportCollection.MetricReportCollection";
72                 asyncResp->res.jsonValue["@odata.id"] =
73                     "/redfish/v1/TelemetryService/MetricReports";
74                 asyncResp->res.jsonValue["Name"] = "Metric Report Collection";
75                 const std::vector<const char*> interfaces{
76                     telemetry::reportInterface};
77                 collection_util::getCollectionMembers(
78                     asyncResp, telemetry::metricReportUri, interfaces,
79                     "/xyz/openbmc_project/Telemetry/Reports/TelemetryService");
80             });
81 }
82 
83 inline void requestRoutesMetricReport(App& app)
84 {
85     BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReports/<str>/")
86         .privileges(redfish::privileges::getMetricReport)
87         .methods(boost::beast::http::verb::get)(
88             [](const crow::Request&,
89                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
90                const std::string& id) {
91                 const std::string reportPath = telemetry::getDbusReportPath(id);
92                 crow::connections::systemBus->async_method_call(
93                     [asyncResp, id,
94                      reportPath](const boost::system::error_code& ec) {
95                         if (ec.value() == EBADR ||
96                             ec == boost::system::errc::host_unreachable)
97                         {
98                             messages::resourceNotFound(asyncResp->res,
99                                                        "MetricReport", id);
100                             return;
101                         }
102                         if (ec)
103                         {
104                             BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
105                             messages::internalError(asyncResp->res);
106                             return;
107                         }
108 
109                         crow::connections::systemBus->async_method_call(
110                             [asyncResp,
111                              id](const boost::system::error_code ec,
112                                  const std::variant<
113                                      telemetry::TimestampReadings>& ret) {
114                                 if (ec)
115                                 {
116                                     BMCWEB_LOG_ERROR
117                                         << "respHandler DBus error " << ec;
118                                     messages::internalError(asyncResp->res);
119                                     return;
120                                 }
121 
122                                 if (!telemetry::fillReport(
123                                         asyncResp->res.jsonValue, id, ret))
124                                 {
125                                     messages::internalError(asyncResp->res);
126                                 }
127                             },
128                             telemetry::service, reportPath,
129                             "org.freedesktop.DBus.Properties", "Get",
130                             telemetry::reportInterface, "Readings");
131                     },
132                     telemetry::service, reportPath, telemetry::reportInterface,
133                     "Update");
134             });
135 }
136 } // namespace redfish
137