xref: /openbmc/bmcweb/features/redfish/lib/metric_report_definition.hpp (revision 4dbb8aea7651dc61a4dc384625567b34393742a2)
1081ebf06SWludzik, Jozef #pragma once
2081ebf06SWludzik, Jozef 
3081ebf06SWludzik, Jozef #include "node.hpp"
4*4dbb8aeaSWludzik, Jozef #include "sensors.hpp"
5081ebf06SWludzik, Jozef #include "utils/telemetry_utils.hpp"
6081ebf06SWludzik, Jozef #include "utils/time_utils.hpp"
7081ebf06SWludzik, Jozef 
8*4dbb8aeaSWludzik, Jozef #include <boost/container/flat_map.hpp>
9*4dbb8aeaSWludzik, Jozef 
10081ebf06SWludzik, Jozef #include <tuple>
11081ebf06SWludzik, Jozef #include <variant>
12081ebf06SWludzik, Jozef 
13081ebf06SWludzik, Jozef namespace redfish
14081ebf06SWludzik, Jozef {
15081ebf06SWludzik, Jozef 
16081ebf06SWludzik, Jozef namespace telemetry
17081ebf06SWludzik, Jozef {
18081ebf06SWludzik, Jozef 
19081ebf06SWludzik, Jozef using ReadingParameters =
20081ebf06SWludzik, Jozef     std::vector<std::tuple<sdbusplus::message::object_path, std::string,
21081ebf06SWludzik, Jozef                            std::string, std::string>>;
22081ebf06SWludzik, Jozef 
23081ebf06SWludzik, Jozef inline void fillReportDefinition(
24081ebf06SWludzik, Jozef     const std::shared_ptr<AsyncResp>& asyncResp, const std::string& id,
25081ebf06SWludzik, Jozef     const std::vector<
26081ebf06SWludzik, Jozef         std::pair<std::string, std::variant<std::string, bool, uint64_t,
27081ebf06SWludzik, Jozef                                             ReadingParameters>>>& ret)
28081ebf06SWludzik, Jozef {
29081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["@odata.type"] =
30081ebf06SWludzik, Jozef         "#MetricReportDefinition.v1_3_0.MetricReportDefinition";
31081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["@odata.id"] =
32081ebf06SWludzik, Jozef         telemetry::metricReportDefinitionUri + id;
33081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["Id"] = id;
34081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["Name"] = id;
35081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["MetricReport"]["@odata.id"] =
36081ebf06SWludzik, Jozef         telemetry::metricReportUri + id;
37081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
38081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["ReportUpdates"] = "Overwrite";
39081ebf06SWludzik, Jozef 
40081ebf06SWludzik, Jozef     const bool* emitsReadingsUpdate = nullptr;
41081ebf06SWludzik, Jozef     const bool* logToMetricReportsCollection = nullptr;
42081ebf06SWludzik, Jozef     const ReadingParameters* readingParams = nullptr;
43081ebf06SWludzik, Jozef     const std::string* reportingType = nullptr;
44081ebf06SWludzik, Jozef     const uint64_t* interval = nullptr;
45081ebf06SWludzik, Jozef     for (const auto& [key, var] : ret)
46081ebf06SWludzik, Jozef     {
47081ebf06SWludzik, Jozef         if (key == "EmitsReadingsUpdate")
48081ebf06SWludzik, Jozef         {
49081ebf06SWludzik, Jozef             emitsReadingsUpdate = std::get_if<bool>(&var);
50081ebf06SWludzik, Jozef         }
51081ebf06SWludzik, Jozef         else if (key == "LogToMetricReportsCollection")
52081ebf06SWludzik, Jozef         {
53081ebf06SWludzik, Jozef             logToMetricReportsCollection = std::get_if<bool>(&var);
54081ebf06SWludzik, Jozef         }
55081ebf06SWludzik, Jozef         else if (key == "ReadingParameters")
56081ebf06SWludzik, Jozef         {
57081ebf06SWludzik, Jozef             readingParams = std::get_if<ReadingParameters>(&var);
58081ebf06SWludzik, Jozef         }
59081ebf06SWludzik, Jozef         else if (key == "ReportingType")
60081ebf06SWludzik, Jozef         {
61081ebf06SWludzik, Jozef             reportingType = std::get_if<std::string>(&var);
62081ebf06SWludzik, Jozef         }
63081ebf06SWludzik, Jozef         else if (key == "Interval")
64081ebf06SWludzik, Jozef         {
65081ebf06SWludzik, Jozef             interval = std::get_if<uint64_t>(&var);
66081ebf06SWludzik, Jozef         }
67081ebf06SWludzik, Jozef     }
68081ebf06SWludzik, Jozef     if (!emitsReadingsUpdate || !logToMetricReportsCollection ||
69081ebf06SWludzik, Jozef         !readingParams || !reportingType || !interval)
70081ebf06SWludzik, Jozef     {
71081ebf06SWludzik, Jozef         BMCWEB_LOG_ERROR << "Property type mismatch or property is missing";
72081ebf06SWludzik, Jozef         messages::internalError(asyncResp->res);
73081ebf06SWludzik, Jozef         return;
74081ebf06SWludzik, Jozef     }
75081ebf06SWludzik, Jozef 
76081ebf06SWludzik, Jozef     std::vector<std::string> redfishReportActions;
77081ebf06SWludzik, Jozef     redfishReportActions.reserve(2);
78081ebf06SWludzik, Jozef     if (*emitsReadingsUpdate)
79081ebf06SWludzik, Jozef     {
80081ebf06SWludzik, Jozef         redfishReportActions.emplace_back("RedfishEvent");
81081ebf06SWludzik, Jozef     }
82081ebf06SWludzik, Jozef     if (*logToMetricReportsCollection)
83081ebf06SWludzik, Jozef     {
84081ebf06SWludzik, Jozef         redfishReportActions.emplace_back("LogToMetricReportsCollection");
85081ebf06SWludzik, Jozef     }
86081ebf06SWludzik, Jozef 
87081ebf06SWludzik, Jozef     nlohmann::json metrics = nlohmann::json::array();
88081ebf06SWludzik, Jozef     for (auto& [sensorPath, operationType, id, metadata] : *readingParams)
89081ebf06SWludzik, Jozef     {
90081ebf06SWludzik, Jozef         metrics.push_back({
91081ebf06SWludzik, Jozef             {"MetricId", id},
92081ebf06SWludzik, Jozef             {"MetricProperties", {metadata}},
93081ebf06SWludzik, Jozef         });
94081ebf06SWludzik, Jozef     }
95081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["Metrics"] = metrics;
96081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["MetricReportDefinitionType"] = *reportingType;
97081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["ReportActions"] = redfishReportActions;
98081ebf06SWludzik, Jozef     asyncResp->res.jsonValue["Schedule"]["RecurrenceInterval"] =
99081ebf06SWludzik, Jozef         time_utils::toDurationString(std::chrono::milliseconds(*interval));
100081ebf06SWludzik, Jozef }
101*4dbb8aeaSWludzik, Jozef 
102*4dbb8aeaSWludzik, Jozef struct AddReportArgs
103*4dbb8aeaSWludzik, Jozef {
104*4dbb8aeaSWludzik, Jozef     std::string name;
105*4dbb8aeaSWludzik, Jozef     std::string reportingType;
106*4dbb8aeaSWludzik, Jozef     bool emitsReadingsUpdate = false;
107*4dbb8aeaSWludzik, Jozef     bool logToMetricReportsCollection = false;
108*4dbb8aeaSWludzik, Jozef     uint64_t interval = 0;
109*4dbb8aeaSWludzik, Jozef     std::vector<std::pair<std::string, std::vector<std::string>>> metrics;
110*4dbb8aeaSWludzik, Jozef };
111*4dbb8aeaSWludzik, Jozef 
112*4dbb8aeaSWludzik, Jozef inline bool toDbusReportActions(crow::Response& res,
113*4dbb8aeaSWludzik, Jozef                                 std::vector<std::string>& actions,
114*4dbb8aeaSWludzik, Jozef                                 AddReportArgs& args)
115*4dbb8aeaSWludzik, Jozef {
116*4dbb8aeaSWludzik, Jozef     size_t index = 0;
117*4dbb8aeaSWludzik, Jozef     for (auto& action : actions)
118*4dbb8aeaSWludzik, Jozef     {
119*4dbb8aeaSWludzik, Jozef         if (action == "RedfishEvent")
120*4dbb8aeaSWludzik, Jozef         {
121*4dbb8aeaSWludzik, Jozef             args.emitsReadingsUpdate = true;
122*4dbb8aeaSWludzik, Jozef         }
123*4dbb8aeaSWludzik, Jozef         else if (action == "LogToMetricReportsCollection")
124*4dbb8aeaSWludzik, Jozef         {
125*4dbb8aeaSWludzik, Jozef             args.logToMetricReportsCollection = true;
126*4dbb8aeaSWludzik, Jozef         }
127*4dbb8aeaSWludzik, Jozef         else
128*4dbb8aeaSWludzik, Jozef         {
129*4dbb8aeaSWludzik, Jozef             messages::propertyValueNotInList(
130*4dbb8aeaSWludzik, Jozef                 res, action, "ReportActions/" + std::to_string(index));
131*4dbb8aeaSWludzik, Jozef             return false;
132*4dbb8aeaSWludzik, Jozef         }
133*4dbb8aeaSWludzik, Jozef         index++;
134*4dbb8aeaSWludzik, Jozef     }
135*4dbb8aeaSWludzik, Jozef     return true;
136*4dbb8aeaSWludzik, Jozef }
137*4dbb8aeaSWludzik, Jozef 
138*4dbb8aeaSWludzik, Jozef inline bool getUserParameters(crow::Response& res, const crow::Request& req,
139*4dbb8aeaSWludzik, Jozef                               AddReportArgs& args)
140*4dbb8aeaSWludzik, Jozef {
141*4dbb8aeaSWludzik, Jozef     std::vector<nlohmann::json> metrics;
142*4dbb8aeaSWludzik, Jozef     std::vector<std::string> reportActions;
143*4dbb8aeaSWludzik, Jozef     std::optional<nlohmann::json> schedule;
144*4dbb8aeaSWludzik, Jozef     if (!json_util::readJson(req, res, "Id", args.name, "Metrics", metrics,
145*4dbb8aeaSWludzik, Jozef                              "MetricReportDefinitionType", args.reportingType,
146*4dbb8aeaSWludzik, Jozef                              "ReportActions", reportActions, "Schedule",
147*4dbb8aeaSWludzik, Jozef                              schedule))
148*4dbb8aeaSWludzik, Jozef     {
149*4dbb8aeaSWludzik, Jozef         return false;
150*4dbb8aeaSWludzik, Jozef     }
151*4dbb8aeaSWludzik, Jozef 
152*4dbb8aeaSWludzik, Jozef     constexpr const char* allowedCharactersInName =
153*4dbb8aeaSWludzik, Jozef         "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
154*4dbb8aeaSWludzik, Jozef     if (args.name.empty() || args.name.find_first_not_of(
155*4dbb8aeaSWludzik, Jozef                                  allowedCharactersInName) != std::string::npos)
156*4dbb8aeaSWludzik, Jozef     {
157*4dbb8aeaSWludzik, Jozef         BMCWEB_LOG_ERROR << "Failed to match " << args.name
158*4dbb8aeaSWludzik, Jozef                          << " with allowed character "
159*4dbb8aeaSWludzik, Jozef                          << allowedCharactersInName;
160*4dbb8aeaSWludzik, Jozef         messages::propertyValueIncorrect(res, "Id", args.name);
161*4dbb8aeaSWludzik, Jozef         return false;
162*4dbb8aeaSWludzik, Jozef     }
163*4dbb8aeaSWludzik, Jozef 
164*4dbb8aeaSWludzik, Jozef     if (args.reportingType != "Periodic" && args.reportingType != "OnRequest")
165*4dbb8aeaSWludzik, Jozef     {
166*4dbb8aeaSWludzik, Jozef         messages::propertyValueNotInList(res, args.reportingType,
167*4dbb8aeaSWludzik, Jozef                                          "MetricReportDefinitionType");
168*4dbb8aeaSWludzik, Jozef         return false;
169*4dbb8aeaSWludzik, Jozef     }
170*4dbb8aeaSWludzik, Jozef 
171*4dbb8aeaSWludzik, Jozef     if (!toDbusReportActions(res, reportActions, args))
172*4dbb8aeaSWludzik, Jozef     {
173*4dbb8aeaSWludzik, Jozef         return false;
174*4dbb8aeaSWludzik, Jozef     }
175*4dbb8aeaSWludzik, Jozef 
176*4dbb8aeaSWludzik, Jozef     if (args.reportingType == "Periodic")
177*4dbb8aeaSWludzik, Jozef     {
178*4dbb8aeaSWludzik, Jozef         if (!schedule)
179*4dbb8aeaSWludzik, Jozef         {
180*4dbb8aeaSWludzik, Jozef             messages::createFailedMissingReqProperties(res, "Schedule");
181*4dbb8aeaSWludzik, Jozef             return false;
182*4dbb8aeaSWludzik, Jozef         }
183*4dbb8aeaSWludzik, Jozef 
184*4dbb8aeaSWludzik, Jozef         std::string durationStr;
185*4dbb8aeaSWludzik, Jozef         if (!json_util::readJson(*schedule, res, "RecurrenceInterval",
186*4dbb8aeaSWludzik, Jozef                                  durationStr))
187*4dbb8aeaSWludzik, Jozef         {
188*4dbb8aeaSWludzik, Jozef             return false;
189*4dbb8aeaSWludzik, Jozef         }
190*4dbb8aeaSWludzik, Jozef 
191*4dbb8aeaSWludzik, Jozef         std::optional<std::chrono::milliseconds> durationNum =
192*4dbb8aeaSWludzik, Jozef             time_utils::fromDurationString(durationStr);
193*4dbb8aeaSWludzik, Jozef         if (!durationNum)
194*4dbb8aeaSWludzik, Jozef         {
195*4dbb8aeaSWludzik, Jozef             messages::propertyValueIncorrect(res, "RecurrenceInterval",
196*4dbb8aeaSWludzik, Jozef                                              durationStr);
197*4dbb8aeaSWludzik, Jozef             return false;
198*4dbb8aeaSWludzik, Jozef         }
199*4dbb8aeaSWludzik, Jozef         args.interval = static_cast<uint64_t>(durationNum->count());
200*4dbb8aeaSWludzik, Jozef     }
201*4dbb8aeaSWludzik, Jozef 
202*4dbb8aeaSWludzik, Jozef     args.metrics.reserve(metrics.size());
203*4dbb8aeaSWludzik, Jozef     for (auto& m : metrics)
204*4dbb8aeaSWludzik, Jozef     {
205*4dbb8aeaSWludzik, Jozef         std::string id;
206*4dbb8aeaSWludzik, Jozef         std::vector<std::string> uris;
207*4dbb8aeaSWludzik, Jozef         if (!json_util::readJson(m, res, "MetricId", id, "MetricProperties",
208*4dbb8aeaSWludzik, Jozef                                  uris))
209*4dbb8aeaSWludzik, Jozef         {
210*4dbb8aeaSWludzik, Jozef             return false;
211*4dbb8aeaSWludzik, Jozef         }
212*4dbb8aeaSWludzik, Jozef 
213*4dbb8aeaSWludzik, Jozef         args.metrics.emplace_back(std::move(id), std::move(uris));
214*4dbb8aeaSWludzik, Jozef     }
215*4dbb8aeaSWludzik, Jozef 
216*4dbb8aeaSWludzik, Jozef     return true;
217*4dbb8aeaSWludzik, Jozef }
218*4dbb8aeaSWludzik, Jozef 
219*4dbb8aeaSWludzik, Jozef inline bool getChassisSensorNode(
220*4dbb8aeaSWludzik, Jozef     const std::shared_ptr<AsyncResp>& asyncResp,
221*4dbb8aeaSWludzik, Jozef     const std::vector<std::pair<std::string, std::vector<std::string>>>&
222*4dbb8aeaSWludzik, Jozef         metrics,
223*4dbb8aeaSWludzik, Jozef     boost::container::flat_set<std::pair<std::string, std::string>>& matched)
224*4dbb8aeaSWludzik, Jozef {
225*4dbb8aeaSWludzik, Jozef     for (const auto& [id, uris] : metrics)
226*4dbb8aeaSWludzik, Jozef     {
227*4dbb8aeaSWludzik, Jozef         for (size_t i = 0; i < uris.size(); i++)
228*4dbb8aeaSWludzik, Jozef         {
229*4dbb8aeaSWludzik, Jozef             const std::string& uri = uris[i];
230*4dbb8aeaSWludzik, Jozef             std::string chassis;
231*4dbb8aeaSWludzik, Jozef             std::string node;
232*4dbb8aeaSWludzik, Jozef 
233*4dbb8aeaSWludzik, Jozef             if (!boost::starts_with(uri, "/redfish/v1/Chassis/") ||
234*4dbb8aeaSWludzik, Jozef                 !dbus::utility::getNthStringFromPath(uri, 3, chassis) ||
235*4dbb8aeaSWludzik, Jozef                 !dbus::utility::getNthStringFromPath(uri, 4, node))
236*4dbb8aeaSWludzik, Jozef             {
237*4dbb8aeaSWludzik, Jozef                 BMCWEB_LOG_ERROR << "Failed to get chassis and sensor Node "
238*4dbb8aeaSWludzik, Jozef                                     "from "
239*4dbb8aeaSWludzik, Jozef                                  << uri;
240*4dbb8aeaSWludzik, Jozef                 messages::propertyValueIncorrect(asyncResp->res, uri,
241*4dbb8aeaSWludzik, Jozef                                                  "MetricProperties/" +
242*4dbb8aeaSWludzik, Jozef                                                      std::to_string(i));
243*4dbb8aeaSWludzik, Jozef                 return false;
244*4dbb8aeaSWludzik, Jozef             }
245*4dbb8aeaSWludzik, Jozef 
246*4dbb8aeaSWludzik, Jozef             if (boost::ends_with(node, "#"))
247*4dbb8aeaSWludzik, Jozef             {
248*4dbb8aeaSWludzik, Jozef                 node.pop_back();
249*4dbb8aeaSWludzik, Jozef             }
250*4dbb8aeaSWludzik, Jozef 
251*4dbb8aeaSWludzik, Jozef             matched.emplace(std::move(chassis), std::move(node));
252*4dbb8aeaSWludzik, Jozef         }
253*4dbb8aeaSWludzik, Jozef     }
254*4dbb8aeaSWludzik, Jozef     return true;
255*4dbb8aeaSWludzik, Jozef }
256*4dbb8aeaSWludzik, Jozef 
257*4dbb8aeaSWludzik, Jozef class AddReport
258*4dbb8aeaSWludzik, Jozef {
259*4dbb8aeaSWludzik, Jozef   public:
260*4dbb8aeaSWludzik, Jozef     AddReport(AddReportArgs argsIn, std::shared_ptr<AsyncResp> asyncResp) :
261*4dbb8aeaSWludzik, Jozef         asyncResp{std::move(asyncResp)}, args{std::move(argsIn)}
262*4dbb8aeaSWludzik, Jozef     {}
263*4dbb8aeaSWludzik, Jozef     ~AddReport()
264*4dbb8aeaSWludzik, Jozef     {
265*4dbb8aeaSWludzik, Jozef         if (asyncResp->res.result() != boost::beast::http::status::ok)
266*4dbb8aeaSWludzik, Jozef         {
267*4dbb8aeaSWludzik, Jozef             return;
268*4dbb8aeaSWludzik, Jozef         }
269*4dbb8aeaSWludzik, Jozef 
270*4dbb8aeaSWludzik, Jozef         telemetry::ReadingParameters readingParams;
271*4dbb8aeaSWludzik, Jozef         readingParams.reserve(args.metrics.size());
272*4dbb8aeaSWludzik, Jozef 
273*4dbb8aeaSWludzik, Jozef         for (const auto& [id, uris] : args.metrics)
274*4dbb8aeaSWludzik, Jozef         {
275*4dbb8aeaSWludzik, Jozef             for (size_t i = 0; i < uris.size(); i++)
276*4dbb8aeaSWludzik, Jozef             {
277*4dbb8aeaSWludzik, Jozef                 const std::string& uri = uris[i];
278*4dbb8aeaSWludzik, Jozef                 auto el = uriToDbus.find(uri);
279*4dbb8aeaSWludzik, Jozef                 if (el == uriToDbus.end())
280*4dbb8aeaSWludzik, Jozef                 {
281*4dbb8aeaSWludzik, Jozef                     BMCWEB_LOG_ERROR << "Failed to find DBus sensor "
282*4dbb8aeaSWludzik, Jozef                                         "corresponding to URI "
283*4dbb8aeaSWludzik, Jozef                                      << uri;
284*4dbb8aeaSWludzik, Jozef                     messages::propertyValueNotInList(asyncResp->res, uri,
285*4dbb8aeaSWludzik, Jozef                                                      "MetricProperties/" +
286*4dbb8aeaSWludzik, Jozef                                                          std::to_string(i));
287*4dbb8aeaSWludzik, Jozef                     return;
288*4dbb8aeaSWludzik, Jozef                 }
289*4dbb8aeaSWludzik, Jozef 
290*4dbb8aeaSWludzik, Jozef                 const std::string& dbusPath = el->second;
291*4dbb8aeaSWludzik, Jozef                 readingParams.emplace_back(dbusPath, "SINGLE", id, uri);
292*4dbb8aeaSWludzik, Jozef             }
293*4dbb8aeaSWludzik, Jozef         }
294*4dbb8aeaSWludzik, Jozef 
295*4dbb8aeaSWludzik, Jozef         crow::connections::systemBus->async_method_call(
296*4dbb8aeaSWludzik, Jozef             [asyncResp = std::move(asyncResp), name = args.name,
297*4dbb8aeaSWludzik, Jozef              uriToDbus = std::move(uriToDbus)](
298*4dbb8aeaSWludzik, Jozef                 const boost::system::error_code ec, const std::string&) {
299*4dbb8aeaSWludzik, Jozef                 if (ec == boost::system::errc::file_exists)
300*4dbb8aeaSWludzik, Jozef                 {
301*4dbb8aeaSWludzik, Jozef                     messages::resourceAlreadyExists(
302*4dbb8aeaSWludzik, Jozef                         asyncResp->res, "MetricReportDefinition", "Id", name);
303*4dbb8aeaSWludzik, Jozef                     return;
304*4dbb8aeaSWludzik, Jozef                 }
305*4dbb8aeaSWludzik, Jozef                 if (ec == boost::system::errc::too_many_files_open)
306*4dbb8aeaSWludzik, Jozef                 {
307*4dbb8aeaSWludzik, Jozef                     messages::createLimitReachedForResource(asyncResp->res);
308*4dbb8aeaSWludzik, Jozef                     return;
309*4dbb8aeaSWludzik, Jozef                 }
310*4dbb8aeaSWludzik, Jozef                 if (ec == boost::system::errc::argument_list_too_long)
311*4dbb8aeaSWludzik, Jozef                 {
312*4dbb8aeaSWludzik, Jozef                     nlohmann::json metricProperties = nlohmann::json::array();
313*4dbb8aeaSWludzik, Jozef                     for (const auto& [uri, _] : uriToDbus)
314*4dbb8aeaSWludzik, Jozef                     {
315*4dbb8aeaSWludzik, Jozef                         metricProperties.emplace_back(uri);
316*4dbb8aeaSWludzik, Jozef                     }
317*4dbb8aeaSWludzik, Jozef                     messages::propertyValueIncorrect(
318*4dbb8aeaSWludzik, Jozef                         asyncResp->res, metricProperties, "MetricProperties");
319*4dbb8aeaSWludzik, Jozef                     return;
320*4dbb8aeaSWludzik, Jozef                 }
321*4dbb8aeaSWludzik, Jozef                 if (ec)
322*4dbb8aeaSWludzik, Jozef                 {
323*4dbb8aeaSWludzik, Jozef                     messages::internalError(asyncResp->res);
324*4dbb8aeaSWludzik, Jozef                     BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
325*4dbb8aeaSWludzik, Jozef                     return;
326*4dbb8aeaSWludzik, Jozef                 }
327*4dbb8aeaSWludzik, Jozef 
328*4dbb8aeaSWludzik, Jozef                 messages::created(asyncResp->res);
329*4dbb8aeaSWludzik, Jozef             },
330*4dbb8aeaSWludzik, Jozef             telemetry::service, "/xyz/openbmc_project/Telemetry/Reports",
331*4dbb8aeaSWludzik, Jozef             "xyz.openbmc_project.Telemetry.ReportManager", "AddReport",
332*4dbb8aeaSWludzik, Jozef             "TelemetryService/" + args.name, args.reportingType,
333*4dbb8aeaSWludzik, Jozef             args.emitsReadingsUpdate, args.logToMetricReportsCollection,
334*4dbb8aeaSWludzik, Jozef             args.interval, readingParams);
335*4dbb8aeaSWludzik, Jozef     }
336*4dbb8aeaSWludzik, Jozef 
337*4dbb8aeaSWludzik, Jozef     void insert(const boost::container::flat_map<std::string, std::string>& el)
338*4dbb8aeaSWludzik, Jozef     {
339*4dbb8aeaSWludzik, Jozef         uriToDbus.insert(el.begin(), el.end());
340*4dbb8aeaSWludzik, Jozef     }
341*4dbb8aeaSWludzik, Jozef 
342*4dbb8aeaSWludzik, Jozef   private:
343*4dbb8aeaSWludzik, Jozef     std::shared_ptr<AsyncResp> asyncResp;
344*4dbb8aeaSWludzik, Jozef     AddReportArgs args;
345*4dbb8aeaSWludzik, Jozef     boost::container::flat_map<std::string, std::string> uriToDbus{};
346*4dbb8aeaSWludzik, Jozef };
347081ebf06SWludzik, Jozef } // namespace telemetry
348081ebf06SWludzik, Jozef 
349081ebf06SWludzik, Jozef class MetricReportDefinitionCollection : public Node
350081ebf06SWludzik, Jozef {
351081ebf06SWludzik, Jozef   public:
352081ebf06SWludzik, Jozef     MetricReportDefinitionCollection(App& app) :
353081ebf06SWludzik, Jozef         Node(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/")
354081ebf06SWludzik, Jozef     {
355081ebf06SWludzik, Jozef         entityPrivileges = {
356081ebf06SWludzik, Jozef             {boost::beast::http::verb::get, {{"Login"}}},
357081ebf06SWludzik, Jozef             {boost::beast::http::verb::head, {{"Login"}}},
358081ebf06SWludzik, Jozef             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
359081ebf06SWludzik, Jozef             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
360081ebf06SWludzik, Jozef             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
361081ebf06SWludzik, Jozef             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
362081ebf06SWludzik, Jozef     }
363081ebf06SWludzik, Jozef 
364081ebf06SWludzik, Jozef   private:
365081ebf06SWludzik, Jozef     void doGet(crow::Response& res, const crow::Request&,
366081ebf06SWludzik, Jozef                const std::vector<std::string>&) override
367081ebf06SWludzik, Jozef     {
368081ebf06SWludzik, Jozef         res.jsonValue["@odata.type"] = "#MetricReportDefinitionCollection."
369081ebf06SWludzik, Jozef                                        "MetricReportDefinitionCollection";
370081ebf06SWludzik, Jozef         res.jsonValue["@odata.id"] =
371081ebf06SWludzik, Jozef             "/redfish/v1/TelemetryService/MetricReportDefinitions";
372081ebf06SWludzik, Jozef         res.jsonValue["Name"] = "Metric Definition Collection";
373081ebf06SWludzik, Jozef 
374081ebf06SWludzik, Jozef         auto asyncResp = std::make_shared<AsyncResp>(res);
375081ebf06SWludzik, Jozef         telemetry::getReportCollection(asyncResp,
376081ebf06SWludzik, Jozef                                        telemetry::metricReportDefinitionUri);
377081ebf06SWludzik, Jozef     }
378*4dbb8aeaSWludzik, Jozef 
379*4dbb8aeaSWludzik, Jozef     void doPost(crow::Response& res, const crow::Request& req,
380*4dbb8aeaSWludzik, Jozef                 const std::vector<std::string>&) override
381*4dbb8aeaSWludzik, Jozef     {
382*4dbb8aeaSWludzik, Jozef         auto asyncResp = std::make_shared<AsyncResp>(res);
383*4dbb8aeaSWludzik, Jozef         telemetry::AddReportArgs args;
384*4dbb8aeaSWludzik, Jozef         if (!telemetry::getUserParameters(res, req, args))
385*4dbb8aeaSWludzik, Jozef         {
386*4dbb8aeaSWludzik, Jozef             return;
387*4dbb8aeaSWludzik, Jozef         }
388*4dbb8aeaSWludzik, Jozef 
389*4dbb8aeaSWludzik, Jozef         boost::container::flat_set<std::pair<std::string, std::string>>
390*4dbb8aeaSWludzik, Jozef             chassisSensors;
391*4dbb8aeaSWludzik, Jozef         if (!telemetry::getChassisSensorNode(asyncResp, args.metrics,
392*4dbb8aeaSWludzik, Jozef                                              chassisSensors))
393*4dbb8aeaSWludzik, Jozef         {
394*4dbb8aeaSWludzik, Jozef             return;
395*4dbb8aeaSWludzik, Jozef         }
396*4dbb8aeaSWludzik, Jozef 
397*4dbb8aeaSWludzik, Jozef         auto addReportReq =
398*4dbb8aeaSWludzik, Jozef             std::make_shared<telemetry::AddReport>(std::move(args), asyncResp);
399*4dbb8aeaSWludzik, Jozef         for (const auto& [chassis, sensorType] : chassisSensors)
400*4dbb8aeaSWludzik, Jozef         {
401*4dbb8aeaSWludzik, Jozef             retrieveUriToDbusMap(
402*4dbb8aeaSWludzik, Jozef                 chassis, sensorType,
403*4dbb8aeaSWludzik, Jozef                 [asyncResp, addReportReq](
404*4dbb8aeaSWludzik, Jozef                     const boost::beast::http::status status,
405*4dbb8aeaSWludzik, Jozef                     const boost::container::flat_map<std::string, std::string>&
406*4dbb8aeaSWludzik, Jozef                         uriToDbus) {
407*4dbb8aeaSWludzik, Jozef                     if (status != boost::beast::http::status::ok)
408*4dbb8aeaSWludzik, Jozef                     {
409*4dbb8aeaSWludzik, Jozef                         BMCWEB_LOG_ERROR << "Failed to retrieve URI to dbus "
410*4dbb8aeaSWludzik, Jozef                                             "sensors map with err "
411*4dbb8aeaSWludzik, Jozef                                          << static_cast<unsigned>(status);
412*4dbb8aeaSWludzik, Jozef                         return;
413*4dbb8aeaSWludzik, Jozef                     }
414*4dbb8aeaSWludzik, Jozef                     addReportReq->insert(uriToDbus);
415*4dbb8aeaSWludzik, Jozef                 });
416*4dbb8aeaSWludzik, Jozef         }
417*4dbb8aeaSWludzik, Jozef     }
418081ebf06SWludzik, Jozef };
419081ebf06SWludzik, Jozef 
420081ebf06SWludzik, Jozef class MetricReportDefinition : public Node
421081ebf06SWludzik, Jozef {
422081ebf06SWludzik, Jozef   public:
423081ebf06SWludzik, Jozef     MetricReportDefinition(App& app) :
424081ebf06SWludzik, Jozef         Node(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/",
425081ebf06SWludzik, Jozef              std::string())
426081ebf06SWludzik, Jozef     {
427081ebf06SWludzik, Jozef         entityPrivileges = {
428081ebf06SWludzik, Jozef             {boost::beast::http::verb::get, {{"Login"}}},
429081ebf06SWludzik, Jozef             {boost::beast::http::verb::head, {{"Login"}}},
430081ebf06SWludzik, Jozef             {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
431081ebf06SWludzik, Jozef             {boost::beast::http::verb::put, {{"ConfigureManager"}}},
432081ebf06SWludzik, Jozef             {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
433081ebf06SWludzik, Jozef             {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
434081ebf06SWludzik, Jozef     }
435081ebf06SWludzik, Jozef 
436081ebf06SWludzik, Jozef   private:
437081ebf06SWludzik, Jozef     void doGet(crow::Response& res, const crow::Request&,
438081ebf06SWludzik, Jozef                const std::vector<std::string>& params) override
439081ebf06SWludzik, Jozef     {
440081ebf06SWludzik, Jozef         auto asyncResp = std::make_shared<AsyncResp>(res);
441081ebf06SWludzik, Jozef 
442081ebf06SWludzik, Jozef         if (params.size() != 1)
443081ebf06SWludzik, Jozef         {
444081ebf06SWludzik, Jozef             messages::internalError(asyncResp->res);
445081ebf06SWludzik, Jozef             return;
446081ebf06SWludzik, Jozef         }
447081ebf06SWludzik, Jozef 
448081ebf06SWludzik, Jozef         const std::string& id = params[0];
449081ebf06SWludzik, Jozef         crow::connections::systemBus->async_method_call(
450081ebf06SWludzik, Jozef             [asyncResp,
451081ebf06SWludzik, Jozef              id](const boost::system::error_code ec,
452081ebf06SWludzik, Jozef                  const std::vector<std::pair<
453081ebf06SWludzik, Jozef                      std::string, std::variant<std::string, bool, uint64_t,
454081ebf06SWludzik, Jozef                                                telemetry::ReadingParameters>>>&
455081ebf06SWludzik, Jozef                      ret) {
456081ebf06SWludzik, Jozef                 if (ec.value() == EBADR ||
457081ebf06SWludzik, Jozef                     ec == boost::system::errc::host_unreachable)
458081ebf06SWludzik, Jozef                 {
459081ebf06SWludzik, Jozef                     messages::resourceNotFound(asyncResp->res,
460081ebf06SWludzik, Jozef                                                "MetricReportDefinition", id);
461081ebf06SWludzik, Jozef                     return;
462081ebf06SWludzik, Jozef                 }
463081ebf06SWludzik, Jozef                 if (ec)
464081ebf06SWludzik, Jozef                 {
465081ebf06SWludzik, Jozef                     BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
466081ebf06SWludzik, Jozef                     messages::internalError(asyncResp->res);
467081ebf06SWludzik, Jozef                     return;
468081ebf06SWludzik, Jozef                 }
469081ebf06SWludzik, Jozef 
470081ebf06SWludzik, Jozef                 telemetry::fillReportDefinition(asyncResp, id, ret);
471081ebf06SWludzik, Jozef             },
472081ebf06SWludzik, Jozef             telemetry::service, telemetry::getDbusReportPath(id),
473081ebf06SWludzik, Jozef             "org.freedesktop.DBus.Properties", "GetAll",
474081ebf06SWludzik, Jozef             telemetry::reportInterface);
475081ebf06SWludzik, Jozef     }
476*4dbb8aeaSWludzik, Jozef 
477*4dbb8aeaSWludzik, Jozef     void doDelete(crow::Response& res, const crow::Request&,
478*4dbb8aeaSWludzik, Jozef                   const std::vector<std::string>& params) override
479*4dbb8aeaSWludzik, Jozef     {
480*4dbb8aeaSWludzik, Jozef         auto asyncResp = std::make_shared<AsyncResp>(res);
481*4dbb8aeaSWludzik, Jozef         if (params.size() != 1)
482*4dbb8aeaSWludzik, Jozef         {
483*4dbb8aeaSWludzik, Jozef             messages::internalError(asyncResp->res);
484*4dbb8aeaSWludzik, Jozef             return;
485*4dbb8aeaSWludzik, Jozef         }
486*4dbb8aeaSWludzik, Jozef 
487*4dbb8aeaSWludzik, Jozef         const std::string& id = params[0];
488*4dbb8aeaSWludzik, Jozef         const std::string reportPath = telemetry::getDbusReportPath(id);
489*4dbb8aeaSWludzik, Jozef 
490*4dbb8aeaSWludzik, Jozef         crow::connections::systemBus->async_method_call(
491*4dbb8aeaSWludzik, Jozef             [asyncResp, id](const boost::system::error_code ec) {
492*4dbb8aeaSWludzik, Jozef                 /*
493*4dbb8aeaSWludzik, Jozef                  * boost::system::errc and std::errc are missing value for
494*4dbb8aeaSWludzik, Jozef                  * EBADR error that is defined in Linux.
495*4dbb8aeaSWludzik, Jozef                  */
496*4dbb8aeaSWludzik, Jozef                 if (ec.value() == EBADR)
497*4dbb8aeaSWludzik, Jozef                 {
498*4dbb8aeaSWludzik, Jozef                     messages::resourceNotFound(asyncResp->res,
499*4dbb8aeaSWludzik, Jozef                                                "MetricReportDefinition", id);
500*4dbb8aeaSWludzik, Jozef                     return;
501*4dbb8aeaSWludzik, Jozef                 }
502*4dbb8aeaSWludzik, Jozef 
503*4dbb8aeaSWludzik, Jozef                 if (ec)
504*4dbb8aeaSWludzik, Jozef                 {
505*4dbb8aeaSWludzik, Jozef                     BMCWEB_LOG_ERROR << "respHandler DBus error " << ec;
506*4dbb8aeaSWludzik, Jozef                     messages::internalError(asyncResp->res);
507*4dbb8aeaSWludzik, Jozef                     return;
508*4dbb8aeaSWludzik, Jozef                 }
509*4dbb8aeaSWludzik, Jozef 
510*4dbb8aeaSWludzik, Jozef                 asyncResp->res.result(boost::beast::http::status::no_content);
511*4dbb8aeaSWludzik, Jozef             },
512*4dbb8aeaSWludzik, Jozef             telemetry::service, reportPath, "xyz.openbmc_project.Object.Delete",
513*4dbb8aeaSWludzik, Jozef             "Delete");
514*4dbb8aeaSWludzik, Jozef     }
515081ebf06SWludzik, Jozef };
516081ebf06SWludzik, Jozef } // namespace redfish
517