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