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