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