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