xref: /openbmc/bmcweb/features/redfish/lib/metric_report.hpp (revision 081ebf06b4c947e828408029273699ff2d49a54f)
1*081ebf06SWludzik, Jozef #pragma once
2*081ebf06SWludzik, Jozef 
3*081ebf06SWludzik, Jozef #include "node.hpp"
4*081ebf06SWludzik, Jozef #include "utils/telemetry_utils.hpp"
5*081ebf06SWludzik, Jozef 
6*081ebf06SWludzik, Jozef namespace redfish
7*081ebf06SWludzik, Jozef {
8*081ebf06SWludzik, Jozef 
9*081ebf06SWludzik, Jozef namespace telemetry
10*081ebf06SWludzik, Jozef {
11*081ebf06SWludzik, Jozef 
12*081ebf06SWludzik, Jozef using Readings =
13*081ebf06SWludzik, Jozef     std::vector<std::tuple<std::string, std::string, double, uint64_t>>;
14*081ebf06SWludzik, Jozef using TimestampReadings = std::tuple<uint64_t, Readings>;
15*081ebf06SWludzik, Jozef 
16*081ebf06SWludzik, Jozef inline nlohmann::json toMetricValues(const Readings& readings)
17*081ebf06SWludzik, Jozef {
18*081ebf06SWludzik, Jozef     nlohmann::json metricValues = nlohmann::json::array_t();
19*081ebf06SWludzik, Jozef 
20*081ebf06SWludzik, Jozef     for (auto& [id, metadata, sensorValue, timestamp] : readings)
21*081ebf06SWludzik, Jozef     {
22*081ebf06SWludzik, Jozef         metricValues.push_back({
23*081ebf06SWludzik, Jozef             {"MetricId", id},
24*081ebf06SWludzik, Jozef             {"MetricProperty", metadata},
25*081ebf06SWludzik, Jozef             {"MetricValue", std::to_string(sensorValue)},
26*081ebf06SWludzik, Jozef             {"Timestamp",
27*081ebf06SWludzik, Jozef              crow::utility::getDateTime(static_cast<time_t>(timestamp))},
28*081ebf06SWludzik, Jozef         });
29*081ebf06SWludzik, Jozef     }
30*081ebf06SWludzik, Jozef 
31*081ebf06SWludzik, Jozef     return metricValues;
32*081ebf06SWludzik, Jozef }
33*081ebf06SWludzik, Jozef 
34*081ebf06SWludzik, Jozef inline void fillReport(const std::shared_ptr<AsyncResp>& asyncResp,
35*081ebf06SWludzik, Jozef                        const std::string& id,
36*081ebf06SWludzik, Jozef                        const std::variant<TimestampReadings>& var)
37*081ebf06SWludzik, Jozef {
38*081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["@odata.type"] =
39*081ebf06SWludzik, Jozef         "#MetricReport.v1_3_0.MetricReport";
40*081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["@odata.id"] = telemetry::metricReportUri + id;
41*081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["Id"] = id;
42*081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["Name"] = id;
43*081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["MetricReportDefinition"]["@odata.id"] =
44*081ebf06SWludzik, Jozef         telemetry::metricReportDefinitionUri + id;
45*081ebf06SWludzik, Jozef 
46*081ebf06SWludzik, Jozef     const TimestampReadings* timestampReadings =
47*081ebf06SWludzik, Jozef         std::get_if<TimestampReadings>(&var);
48*081ebf06SWludzik, Jozef     if (!timestampReadings)
49*081ebf06SWludzik, Jozef     {
50*081ebf06SWludzik, Jozef         BMCWEB_LOG_ERROR << "Property type mismatch or property is missing";
51*081ebf06SWludzik, Jozef         messages::internalError(asyncResp->res);
52*081ebf06SWludzik, Jozef         return;
53*081ebf06SWludzik, Jozef     }
54*081ebf06SWludzik, Jozef 
55*081ebf06SWludzik, Jozef     const auto& [timestamp, readings] = *timestampReadings;
56*081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["Timestamp"] =
57*081ebf06SWludzik, Jozef         crow::utility::getDateTime(static_cast<time_t>(timestamp));
58*081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["MetricValues"] = toMetricValues(readings);
59*081ebf06SWludzik, Jozef }
60*081ebf06SWludzik, Jozef } // namespace telemetry
61*081ebf06SWludzik, Jozef 
62*081ebf06SWludzik, Jozef class MetricReportCollection : public Node
63*081ebf06SWludzik, Jozef {
64*081ebf06SWludzik, Jozef   public:
65*081ebf06SWludzik, Jozef     MetricReportCollection(App& app) :
66*081ebf06SWludzik, Jozef         Node(app, "/redfish/v1/TelemetryService/MetricReports/")
67*081ebf06SWludzik, Jozef     {
68*081ebf06SWludzik, Jozef         entityPrivileges = {
69*081ebf06SWludzik, Jozef             {boost::beast::http::verb::get, {{"Login"}}},
70*081ebf06SWludzik, Jozef             {boost::beast::http::verb::head, {{"Login"}}},
71*081ebf06SWludzik, Jozef             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
72*081ebf06SWludzik, Jozef             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
73*081ebf06SWludzik, Jozef             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
74*081ebf06SWludzik, Jozef             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
75*081ebf06SWludzik, Jozef     }
76*081ebf06SWludzik, Jozef 
77*081ebf06SWludzik, Jozef   private:
78*081ebf06SWludzik, Jozef     void doGet(crow::Response& res, const crow::Request&,
79*081ebf06SWludzik, Jozef                const std::vector<std::string>&) override
80*081ebf06SWludzik, Jozef     {
81*081ebf06SWludzik, Jozef         res.jsonValue["@odata.type"] =
82*081ebf06SWludzik, Jozef             "#MetricReportCollection.MetricReportCollection";
83*081ebf06SWludzik, Jozef         res.jsonValue["@odata.id"] =
84*081ebf06SWludzik, Jozef             "/redfish/v1/TelemetryService/MetricReports";
85*081ebf06SWludzik, Jozef         res.jsonValue["Name"] = "Metric Report Collection";
86*081ebf06SWludzik, Jozef 
87*081ebf06SWludzik, Jozef         auto asyncResp = std::make_shared<AsyncResp>(res);
88*081ebf06SWludzik, Jozef         telemetry::getReportCollection(asyncResp, telemetry::metricReportUri);
89*081ebf06SWludzik, Jozef     }
90*081ebf06SWludzik, Jozef };
91*081ebf06SWludzik, Jozef 
92*081ebf06SWludzik, Jozef class MetricReport : public Node
93*081ebf06SWludzik, Jozef {
94*081ebf06SWludzik, Jozef   public:
95*081ebf06SWludzik, Jozef     MetricReport(App& app) :
96*081ebf06SWludzik, Jozef         Node(app, "/redfish/v1/TelemetryService/MetricReports/<str>/",
97*081ebf06SWludzik, Jozef              std::string())
98*081ebf06SWludzik, Jozef     {
99*081ebf06SWludzik, Jozef         entityPrivileges = {
100*081ebf06SWludzik, Jozef             {boost::beast::http::verb::get, {{"Login"}}},
101*081ebf06SWludzik, Jozef             {boost::beast::http::verb::head, {{"Login"}}},
102*081ebf06SWludzik, Jozef             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
103*081ebf06SWludzik, Jozef             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
104*081ebf06SWludzik, Jozef             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
105*081ebf06SWludzik, Jozef             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
106*081ebf06SWludzik, Jozef     }
107*081ebf06SWludzik, Jozef 
108*081ebf06SWludzik, Jozef   private:
109*081ebf06SWludzik, Jozef     void doGet(crow::Response& res, const crow::Request&,
110*081ebf06SWludzik, Jozef                const std::vector<std::string>& params) override
111*081ebf06SWludzik, Jozef     {
112*081ebf06SWludzik, Jozef         auto asyncResp = std::make_shared<AsyncResp>(res);
113*081ebf06SWludzik, Jozef 
114*081ebf06SWludzik, Jozef         if (params.size() != 1)
115*081ebf06SWludzik, Jozef         {
116*081ebf06SWludzik, Jozef             messages::internalError(asyncResp->res);
117*081ebf06SWludzik, Jozef             return;
118*081ebf06SWludzik, Jozef         }
119*081ebf06SWludzik, Jozef 
120*081ebf06SWludzik, Jozef         const std::string& id = params[0];
121*081ebf06SWludzik, Jozef         const std::string reportPath = telemetry::getDbusReportPath(id);
122*081ebf06SWludzik, Jozef         crow::connections::systemBus->async_method_call(
123*081ebf06SWludzik, Jozef             [asyncResp, id, reportPath](const boost::system::error_code& ec) {
124*081ebf06SWludzik, Jozef                 if (ec.value() == EBADR ||
125*081ebf06SWludzik, Jozef                     ec == boost::system::errc::host_unreachable)
126*081ebf06SWludzik, Jozef                 {
127*081ebf06SWludzik, Jozef                     messages::resourceNotFound(asyncResp->res, "MetricReport",
128*081ebf06SWludzik, Jozef                                                id);
129*081ebf06SWludzik, Jozef                     return;
130*081ebf06SWludzik, Jozef                 }
131*081ebf06SWludzik, Jozef                 if (ec)
132*081ebf06SWludzik, Jozef                 {
133*081ebf06SWludzik, Jozef                     BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
134*081ebf06SWludzik, Jozef                     messages::internalError(asyncResp->res);
135*081ebf06SWludzik, Jozef                     return;
136*081ebf06SWludzik, Jozef                 }
137*081ebf06SWludzik, Jozef 
138*081ebf06SWludzik, Jozef                 crow::connections::systemBus->async_method_call(
139*081ebf06SWludzik, Jozef                     [asyncResp, id](
140*081ebf06SWludzik, Jozef                         const boost::system::error_code ec,
141*081ebf06SWludzik, Jozef                         const std::variant<telemetry::TimestampReadings>& ret) {
142*081ebf06SWludzik, Jozef                         if (ec)
143*081ebf06SWludzik, Jozef                         {
144*081ebf06SWludzik, Jozef                             BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
145*081ebf06SWludzik, Jozef                             messages::internalError(asyncResp->res);
146*081ebf06SWludzik, Jozef                             return;
147*081ebf06SWludzik, Jozef                         }
148*081ebf06SWludzik, Jozef 
149*081ebf06SWludzik, Jozef                         telemetry::fillReport(asyncResp, id, ret);
150*081ebf06SWludzik, Jozef                     },
151*081ebf06SWludzik, Jozef                     telemetry::service, reportPath,
152*081ebf06SWludzik, Jozef                     "org.freedesktop.DBus.Properties", "Get",
153*081ebf06SWludzik, Jozef                     telemetry::reportInterface, "Readings");
154*081ebf06SWludzik, Jozef             },
155*081ebf06SWludzik, Jozef             telemetry::service, reportPath, telemetry::reportInterface,
156*081ebf06SWludzik, Jozef             "Update");
157*081ebf06SWludzik, Jozef     }
158*081ebf06SWludzik, Jozef };
159*081ebf06SWludzik, Jozef } // namespace redfish
160