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