1 #pragma once
2
3 #include "app.hpp"
4 #include "dbus_utility.hpp"
5 #include "generated/enums/metric_report_definition.hpp"
6 #include "query.hpp"
7 #include "registries/privilege_registry.hpp"
8 #include "sensors.hpp"
9 #include "utils/collection.hpp"
10 #include "utils/dbus_utils.hpp"
11 #include "utils/json_utils.hpp"
12 #include "utils/telemetry_utils.hpp"
13 #include "utils/time_utils.hpp"
14
15 #include <boost/container/flat_map.hpp>
16 #include <boost/url/format.hpp>
17 #include <sdbusplus/asio/property.hpp>
18 #include <sdbusplus/unpack_properties.hpp>
19
20 #include <array>
21 #include <map>
22 #include <optional>
23 #include <span>
24 #include <string>
25 #include <string_view>
26 #include <tuple>
27 #include <utility>
28 #include <variant>
29 #include <vector>
30
31 namespace redfish
32 {
33
34 namespace telemetry
35 {
36
37 using ReadingParameters = std::vector<std::tuple<
38 std::vector<std::tuple<sdbusplus::message::object_path, std::string>>,
39 std::string, std::string, uint64_t>>;
40
verifyCommonErrors(crow::Response & res,const std::string & id,const boost::system::error_code & ec)41 inline bool verifyCommonErrors(crow::Response& res, const std::string& id,
42 const boost::system::error_code& ec)
43 {
44 if (ec.value() == EBADR || ec == boost::system::errc::host_unreachable)
45 {
46 messages::resourceNotFound(res, "MetricReportDefinition", id);
47 return false;
48 }
49
50 if (ec == boost::system::errc::file_exists)
51 {
52 messages::resourceAlreadyExists(res, "MetricReportDefinition", "Id",
53 id);
54 return false;
55 }
56
57 if (ec == boost::system::errc::too_many_files_open)
58 {
59 messages::createLimitReachedForResource(res);
60 return false;
61 }
62
63 if (ec)
64 {
65 BMCWEB_LOG_ERROR("DBUS response error {}", ec);
66 messages::internalError(res);
67 return false;
68 }
69
70 return true;
71 }
72
73 inline metric_report_definition::ReportActionsEnum
toRedfishReportAction(std::string_view dbusValue)74 toRedfishReportAction(std::string_view dbusValue)
75 {
76 if (dbusValue ==
77 "xyz.openbmc_project.Telemetry.Report.ReportActions.EmitsReadingsUpdate")
78 {
79 return metric_report_definition::ReportActionsEnum::RedfishEvent;
80 }
81 if (dbusValue ==
82 "xyz.openbmc_project.Telemetry.Report.ReportActions.LogToMetricReportsCollection")
83 {
84 return metric_report_definition::ReportActionsEnum::
85 LogToMetricReportsCollection;
86 }
87 return metric_report_definition::ReportActionsEnum::Invalid;
88 }
89
toDbusReportAction(std::string_view redfishValue)90 inline std::string toDbusReportAction(std::string_view redfishValue)
91 {
92 if (redfishValue == "RedfishEvent")
93 {
94 return "xyz.openbmc_project.Telemetry.Report.ReportActions.EmitsReadingsUpdate";
95 }
96 if (redfishValue == "LogToMetricReportsCollection")
97 {
98 return "xyz.openbmc_project.Telemetry.Report.ReportActions.LogToMetricReportsCollection";
99 }
100 return "";
101 }
102
103 inline metric_report_definition::MetricReportDefinitionType
toRedfishReportingType(std::string_view dbusValue)104 toRedfishReportingType(std::string_view dbusValue)
105 {
106 if (dbusValue ==
107 "xyz.openbmc_project.Telemetry.Report.ReportingType.OnChange")
108 {
109 return metric_report_definition::MetricReportDefinitionType::OnChange;
110 }
111 if (dbusValue ==
112 "xyz.openbmc_project.Telemetry.Report.ReportingType.OnRequest")
113 {
114 return metric_report_definition::MetricReportDefinitionType::OnRequest;
115 }
116 if (dbusValue ==
117 "xyz.openbmc_project.Telemetry.Report.ReportingType.Periodic")
118 {
119 return metric_report_definition::MetricReportDefinitionType::Periodic;
120 }
121 return metric_report_definition::MetricReportDefinitionType::Invalid;
122 }
123
toDbusReportingType(std::string_view redfishValue)124 inline std::string toDbusReportingType(std::string_view redfishValue)
125 {
126 if (redfishValue == "OnChange")
127 {
128 return "xyz.openbmc_project.Telemetry.Report.ReportingType.OnChange";
129 }
130 if (redfishValue == "OnRequest")
131 {
132 return "xyz.openbmc_project.Telemetry.Report.ReportingType.OnRequest";
133 }
134 if (redfishValue == "Periodic")
135 {
136 return "xyz.openbmc_project.Telemetry.Report.ReportingType.Periodic";
137 }
138 return "";
139 }
140
141 inline metric_report_definition::CollectionTimeScope
toRedfishCollectionTimeScope(std::string_view dbusValue)142 toRedfishCollectionTimeScope(std::string_view dbusValue)
143 {
144 if (dbusValue ==
145 "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.Point")
146 {
147 return metric_report_definition::CollectionTimeScope::Point;
148 }
149 if (dbusValue ==
150 "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.Interval")
151 {
152 return metric_report_definition::CollectionTimeScope::Interval;
153 }
154 if (dbusValue ==
155 "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.StartupInterval")
156 {
157 return metric_report_definition::CollectionTimeScope::StartupInterval;
158 }
159 return metric_report_definition::CollectionTimeScope::Invalid;
160 }
161
toDbusCollectionTimeScope(std::string_view redfishValue)162 inline std::string toDbusCollectionTimeScope(std::string_view redfishValue)
163 {
164 if (redfishValue == "Point")
165 {
166 return "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.Point";
167 }
168 if (redfishValue == "Interval")
169 {
170 return "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.Interval";
171 }
172 if (redfishValue == "StartupInterval")
173 {
174 return "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.StartupInterval";
175 }
176 return "";
177 }
178
179 inline metric_report_definition::ReportUpdatesEnum
toRedfishReportUpdates(std::string_view dbusValue)180 toRedfishReportUpdates(std::string_view dbusValue)
181 {
182 if (dbusValue ==
183 "xyz.openbmc_project.Telemetry.Report.ReportUpdates.Overwrite")
184 {
185 return metric_report_definition::ReportUpdatesEnum::Overwrite;
186 }
187 if (dbusValue ==
188 "xyz.openbmc_project.Telemetry.Report.ReportUpdates.AppendWrapsWhenFull")
189 {
190 return metric_report_definition::ReportUpdatesEnum::AppendWrapsWhenFull;
191 }
192 if (dbusValue ==
193 "xyz.openbmc_project.Telemetry.Report.ReportUpdates.AppendStopsWhenFull")
194 {
195 return metric_report_definition::ReportUpdatesEnum::AppendStopsWhenFull;
196 }
197 return metric_report_definition::ReportUpdatesEnum::Invalid;
198 }
199
toDbusReportUpdates(std::string_view redfishValue)200 inline std::string toDbusReportUpdates(std::string_view redfishValue)
201 {
202 if (redfishValue == "Overwrite")
203 {
204 return "xyz.openbmc_project.Telemetry.Report.ReportUpdates.Overwrite";
205 }
206 if (redfishValue == "AppendWrapsWhenFull")
207 {
208 return "xyz.openbmc_project.Telemetry.Report.ReportUpdates.AppendWrapsWhenFull";
209 }
210 if (redfishValue == "AppendStopsWhenFull")
211 {
212 return "xyz.openbmc_project.Telemetry.Report.ReportUpdates.AppendStopsWhenFull";
213 }
214 return "";
215 }
216
getLinkedTriggers(std::span<const sdbusplus::message::object_path> triggerPaths)217 inline std::optional<nlohmann::json::array_t> getLinkedTriggers(
218 std::span<const sdbusplus::message::object_path> triggerPaths)
219 {
220 nlohmann::json::array_t triggers;
221
222 for (const sdbusplus::message::object_path& path : triggerPaths)
223 {
224 if (path.parent_path() !=
225 "/xyz/openbmc_project/Telemetry/Triggers/TelemetryService")
226 {
227 BMCWEB_LOG_ERROR("Property Triggers contains invalid value: {}",
228 path.str);
229 return std::nullopt;
230 }
231
232 std::string id = path.filename();
233 if (id.empty())
234 {
235 BMCWEB_LOG_ERROR("Property Triggers contains invalid value: {}",
236 path.str);
237 return std::nullopt;
238 }
239 nlohmann::json::object_t trigger;
240 trigger["@odata.id"] =
241 boost::urls::format("/redfish/v1/TelemetryService/Triggers/{}", id);
242 triggers.emplace_back(std::move(trigger));
243 }
244
245 return triggers;
246 }
247
248 inline void
fillReportDefinition(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & id,const dbus::utility::DBusPropertiesMap & properties)249 fillReportDefinition(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
250 const std::string& id,
251 const dbus::utility::DBusPropertiesMap& properties)
252 {
253 std::vector<std::string> reportActions;
254 ReadingParameters readingParams;
255 std::string reportingType;
256 std::string reportUpdates;
257 std::string name;
258 uint64_t appendLimit = 0;
259 uint64_t interval = 0;
260 bool enabled = false;
261 std::vector<sdbusplus::message::object_path> triggers;
262
263 const bool success = sdbusplus::unpackPropertiesNoThrow(
264 dbus_utils::UnpackErrorPrinter(), properties, "ReportingType",
265 reportingType, "Interval", interval, "ReportActions", reportActions,
266 "ReportUpdates", reportUpdates, "AppendLimit", appendLimit,
267 "ReadingParameters", readingParams, "Name", name, "Enabled", enabled,
268 "Triggers", triggers);
269
270 if (!success)
271 {
272 messages::internalError(asyncResp->res);
273 return;
274 }
275
276 metric_report_definition::MetricReportDefinitionType redfishReportingType =
277 toRedfishReportingType(reportingType);
278 if (redfishReportingType ==
279 metric_report_definition::MetricReportDefinitionType::Invalid)
280 {
281 messages::internalError(asyncResp->res);
282 return;
283 }
284
285 asyncResp->res.jsonValue["MetricReportDefinitionType"] =
286 redfishReportingType;
287
288 std::optional<nlohmann::json::array_t> linkedTriggers =
289 getLinkedTriggers(triggers);
290 if (!linkedTriggers)
291 {
292 messages::internalError(asyncResp->res);
293 return;
294 }
295
296 asyncResp->res.jsonValue["Links"]["Triggers"] = std::move(*linkedTriggers);
297
298 nlohmann::json::array_t redfishReportActions;
299 for (const std::string& action : reportActions)
300 {
301 metric_report_definition::ReportActionsEnum redfishAction =
302 toRedfishReportAction(action);
303 if (redfishAction ==
304 metric_report_definition::ReportActionsEnum::Invalid)
305 {
306 messages::internalError(asyncResp->res);
307 return;
308 }
309
310 redfishReportActions.emplace_back(redfishAction);
311 }
312
313 asyncResp->res.jsonValue["ReportActions"] = std::move(redfishReportActions);
314
315 nlohmann::json::array_t metrics = nlohmann::json::array();
316 for (const auto& [sensorData, collectionFunction, collectionTimeScope,
317 collectionDuration] : readingParams)
318 {
319 nlohmann::json::array_t metricProperties;
320
321 for (const auto& [sensorPath, sensorMetadata] : sensorData)
322 {
323 metricProperties.emplace_back(sensorMetadata);
324 }
325
326 nlohmann::json::object_t metric;
327
328 metric_report_definition::CalculationAlgorithmEnum
329 redfishCollectionFunction =
330 telemetry::toRedfishCollectionFunction(collectionFunction);
331 if (redfishCollectionFunction ==
332 metric_report_definition::CalculationAlgorithmEnum::Invalid)
333 {
334 messages::internalError(asyncResp->res);
335 return;
336 }
337 metric["CollectionFunction"] = redfishCollectionFunction;
338
339 metric_report_definition::CollectionTimeScope
340 redfishCollectionTimeScope =
341 toRedfishCollectionTimeScope(collectionTimeScope);
342 if (redfishCollectionTimeScope ==
343 metric_report_definition::CollectionTimeScope::Invalid)
344 {
345 messages::internalError(asyncResp->res);
346 return;
347 }
348 metric["CollectionTimeScope"] = redfishCollectionTimeScope;
349
350 metric["MetricProperties"] = std::move(metricProperties);
351 metric["CollectionDuration"] = time_utils::toDurationString(
352 std::chrono::milliseconds(collectionDuration));
353 metrics.emplace_back(std::move(metric));
354 }
355 asyncResp->res.jsonValue["Metrics"] = std::move(metrics);
356
357 if (enabled)
358 {
359 asyncResp->res.jsonValue["Status"]["State"] = "Enabled";
360 }
361 else
362 {
363 asyncResp->res.jsonValue["Status"]["State"] = "Disabled";
364 }
365
366 metric_report_definition::ReportUpdatesEnum redfishReportUpdates =
367 toRedfishReportUpdates(reportUpdates);
368 if (redfishReportUpdates ==
369 metric_report_definition::ReportUpdatesEnum::Invalid)
370 {
371 messages::internalError(asyncResp->res);
372 return;
373 }
374 asyncResp->res.jsonValue["ReportUpdates"] = redfishReportUpdates;
375
376 asyncResp->res.jsonValue["MetricReportDefinitionEnabled"] = enabled;
377 asyncResp->res.jsonValue["AppendLimit"] = appendLimit;
378 asyncResp->res.jsonValue["Name"] = name;
379 asyncResp->res.jsonValue["Schedule"]["RecurrenceInterval"] =
380 time_utils::toDurationString(std::chrono::milliseconds(interval));
381 asyncResp->res.jsonValue["@odata.type"] =
382 "#MetricReportDefinition.v1_3_0.MetricReportDefinition";
383 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
384 "/redfish/v1/TelemetryService/MetricReportDefinitions/{}", id);
385 asyncResp->res.jsonValue["Id"] = id;
386 asyncResp->res.jsonValue["MetricReport"]["@odata.id"] = boost::urls::format(
387 "/redfish/v1/TelemetryService/MetricReports/{}", id);
388 }
389
390 struct AddReportArgs
391 {
392 struct MetricArgs
393 {
394 std::vector<std::string> uris;
395 std::string collectionFunction;
396 std::string collectionTimeScope;
397 uint64_t collectionDuration = 0;
398 };
399
400 std::string id;
401 std::string name;
402 std::string reportingType;
403 std::string reportUpdates;
404 uint64_t appendLimit = std::numeric_limits<uint64_t>::max();
405 std::vector<std::string> reportActions;
406 uint64_t interval = std::numeric_limits<uint64_t>::max();
407 std::vector<MetricArgs> metrics;
408 bool metricReportDefinitionEnabled = true;
409 };
410
toDbusReportActions(crow::Response & res,const std::vector<std::string> & actions,std::vector<std::string> & outReportActions)411 inline bool toDbusReportActions(crow::Response& res,
412 const std::vector<std::string>& actions,
413 std::vector<std::string>& outReportActions)
414 {
415 size_t index = 0;
416 for (const std::string& action : actions)
417 {
418 std::string dbusReportAction = toDbusReportAction(action);
419 if (dbusReportAction.empty())
420 {
421 messages::propertyValueNotInList(
422 res, action, "ReportActions/" + std::to_string(index));
423 return false;
424 }
425
426 outReportActions.emplace_back(std::move(dbusReportAction));
427 index++;
428 }
429 return true;
430 }
431
getUserMetric(crow::Response & res,nlohmann::json::object_t & metric,AddReportArgs::MetricArgs & metricArgs)432 inline bool getUserMetric(crow::Response& res, nlohmann::json::object_t& metric,
433 AddReportArgs::MetricArgs& metricArgs)
434 {
435 std::optional<std::vector<std::string>> uris;
436 std::optional<std::string> collectionDurationStr;
437 std::optional<std::string> collectionFunction;
438 std::optional<std::string> collectionTimeScopeStr;
439
440 if (!json_util::readJsonObject(
441 metric, res, "MetricProperties", uris, "CollectionFunction",
442 collectionFunction, "CollectionTimeScope", collectionTimeScopeStr,
443 "CollectionDuration", collectionDurationStr))
444 {
445 return false;
446 }
447
448 if (uris)
449 {
450 metricArgs.uris = std::move(*uris);
451 }
452
453 if (collectionFunction)
454 {
455 std::string dbusCollectionFunction =
456 telemetry::toDbusCollectionFunction(*collectionFunction);
457 if (dbusCollectionFunction.empty())
458 {
459 messages::propertyValueIncorrect(res, "CollectionFunction",
460 *collectionFunction);
461 return false;
462 }
463 metricArgs.collectionFunction = std::move(dbusCollectionFunction);
464 }
465
466 if (collectionTimeScopeStr)
467 {
468 std::string dbusCollectionTimeScope =
469 toDbusCollectionTimeScope(*collectionTimeScopeStr);
470 if (dbusCollectionTimeScope.empty())
471 {
472 messages::propertyValueIncorrect(res, "CollectionTimeScope",
473 *collectionTimeScopeStr);
474 return false;
475 }
476 metricArgs.collectionTimeScope = std::move(dbusCollectionTimeScope);
477 }
478
479 if (collectionDurationStr)
480 {
481 std::optional<std::chrono::milliseconds> duration =
482 time_utils::fromDurationString(*collectionDurationStr);
483
484 if (!duration || duration->count() < 0)
485 {
486 messages::propertyValueIncorrect(res, "CollectionDuration",
487 *collectionDurationStr);
488 return false;
489 }
490
491 metricArgs.collectionDuration =
492 static_cast<uint64_t>(duration->count());
493 }
494
495 return true;
496 }
497
getUserMetrics(crow::Response & res,std::span<nlohmann::json::object_t> metrics,std::vector<AddReportArgs::MetricArgs> & result)498 inline bool getUserMetrics(crow::Response& res,
499 std::span<nlohmann::json::object_t> metrics,
500 std::vector<AddReportArgs::MetricArgs>& result)
501 {
502 result.reserve(metrics.size());
503
504 for (nlohmann::json::object_t& m : metrics)
505 {
506 AddReportArgs::MetricArgs metricArgs;
507
508 if (!getUserMetric(res, m, metricArgs))
509 {
510 return false;
511 }
512
513 result.emplace_back(std::move(metricArgs));
514 }
515
516 return true;
517 }
518
getUserParameters(crow::Response & res,const crow::Request & req,AddReportArgs & args)519 inline bool getUserParameters(crow::Response& res, const crow::Request& req,
520 AddReportArgs& args)
521 {
522 std::optional<std::string> id;
523 std::optional<std::string> name;
524 std::optional<std::string> reportingTypeStr;
525 std::optional<std::string> reportUpdatesStr;
526 std::optional<uint64_t> appendLimit;
527 std::optional<bool> metricReportDefinitionEnabled;
528 std::optional<std::vector<nlohmann::json::object_t>> metrics;
529 std::optional<std::vector<std::string>> reportActionsStr;
530 std::optional<std::string> scheduleDurationStr;
531
532 if (!json_util::readJsonPatch(
533 req, res, "Id", id, "Name", name, "Metrics", metrics,
534 "MetricReportDefinitionType", reportingTypeStr, "ReportUpdates",
535 reportUpdatesStr, "AppendLimit", appendLimit, "ReportActions",
536 reportActionsStr, "Schedule/RecurrenceInterval",
537 scheduleDurationStr, "MetricReportDefinitionEnabled",
538 metricReportDefinitionEnabled))
539 {
540 return false;
541 }
542
543 if (id)
544 {
545 constexpr const char* allowedCharactersInId =
546 "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_";
547 if (id->empty() ||
548 id->find_first_not_of(allowedCharactersInId) != std::string::npos)
549 {
550 messages::propertyValueIncorrect(res, "Id", *id);
551 return false;
552 }
553 args.id = *id;
554 }
555
556 if (name)
557 {
558 args.name = *name;
559 }
560
561 if (reportingTypeStr)
562 {
563 std::string dbusReportingType = toDbusReportingType(*reportingTypeStr);
564 if (dbusReportingType.empty())
565 {
566 messages::propertyValueNotInList(res, *reportingTypeStr,
567 "MetricReportDefinitionType");
568 return false;
569 }
570 args.reportingType = dbusReportingType;
571 }
572
573 if (reportUpdatesStr)
574 {
575 std::string dbusReportUpdates = toDbusReportUpdates(*reportUpdatesStr);
576 if (dbusReportUpdates.empty())
577 {
578 messages::propertyValueNotInList(res, *reportUpdatesStr,
579 "ReportUpdates");
580 return false;
581 }
582 args.reportUpdates = dbusReportUpdates;
583 }
584
585 if (appendLimit)
586 {
587 args.appendLimit = *appendLimit;
588 }
589
590 if (metricReportDefinitionEnabled)
591 {
592 args.metricReportDefinitionEnabled = *metricReportDefinitionEnabled;
593 }
594
595 if (reportActionsStr)
596 {
597 if (!toDbusReportActions(res, *reportActionsStr, args.reportActions))
598 {
599 return false;
600 }
601 }
602
603 if (reportingTypeStr == "Periodic")
604 {
605 if (!scheduleDurationStr)
606 {
607 messages::createFailedMissingReqProperties(res, "Schedule");
608 return false;
609 }
610
611 std::optional<std::chrono::milliseconds> durationNum =
612 time_utils::fromDurationString(*scheduleDurationStr);
613 if (!durationNum || durationNum->count() < 0)
614 {
615 messages::propertyValueIncorrect(res, "RecurrenceInterval",
616 *scheduleDurationStr);
617 return false;
618 }
619 args.interval = static_cast<uint64_t>(durationNum->count());
620 }
621
622 if (metrics)
623 {
624 if (!getUserMetrics(res, *metrics, args.metrics))
625 {
626 return false;
627 }
628 }
629
630 return true;
631 }
632
getChassisSensorNodeFromMetrics(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::span<const AddReportArgs::MetricArgs> metrics,boost::container::flat_set<std::pair<std::string,std::string>> & matched)633 inline bool getChassisSensorNodeFromMetrics(
634 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
635 std::span<const AddReportArgs::MetricArgs> metrics,
636 boost::container::flat_set<std::pair<std::string, std::string>>& matched)
637 {
638 for (const auto& metric : metrics)
639 {
640 std::optional<IncorrectMetricUri> error =
641 getChassisSensorNode(metric.uris, matched);
642 if (error)
643 {
644 messages::propertyValueIncorrect(asyncResp->res, error->uri,
645 "MetricProperties/" +
646 std::to_string(error->index));
647 return false;
648 }
649 }
650 return true;
651 }
652
653 class AddReport
654 {
655 public:
AddReport(AddReportArgs && argsIn,const std::shared_ptr<bmcweb::AsyncResp> & asyncRespIn)656 AddReport(AddReportArgs&& argsIn,
657 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
658 asyncResp(asyncRespIn),
659 args(std::move(argsIn))
660 {}
661
~AddReport()662 ~AddReport()
663 {
664 boost::asio::post(crow::connections::systemBus->get_io_context(),
665 std::bind_front(&performAddReport, asyncResp, args,
666 std::move(uriToDbus)));
667 }
668
performAddReport(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const AddReportArgs & args,const boost::container::flat_map<std::string,std::string> & uriToDbus)669 static void performAddReport(
670 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
671 const AddReportArgs& args,
672 const boost::container::flat_map<std::string, std::string>& uriToDbus)
673 {
674 if (asyncResp->res.result() != boost::beast::http::status::ok)
675 {
676 return;
677 }
678
679 telemetry::ReadingParameters readingParams;
680 readingParams.reserve(args.metrics.size());
681
682 for (const auto& metric : args.metrics)
683 {
684 std::vector<
685 std::tuple<sdbusplus::message::object_path, std::string>>
686 sensorParams;
687 sensorParams.reserve(metric.uris.size());
688
689 for (size_t i = 0; i < metric.uris.size(); i++)
690 {
691 const std::string& uri = metric.uris[i];
692 auto el = uriToDbus.find(uri);
693 if (el == uriToDbus.end())
694 {
695 BMCWEB_LOG_ERROR(
696 "Failed to find DBus sensor corresponding to URI {}",
697 uri);
698 messages::propertyValueNotInList(asyncResp->res, uri,
699 "MetricProperties/" +
700 std::to_string(i));
701 return;
702 }
703
704 const std::string& dbusPath = el->second;
705 sensorParams.emplace_back(dbusPath, uri);
706 }
707
708 readingParams.emplace_back(
709 std::move(sensorParams), metric.collectionFunction,
710 metric.collectionTimeScope, metric.collectionDuration);
711 }
712
713 crow::connections::systemBus->async_method_call(
714 [asyncResp, id = args.id, uriToDbus](
715 const boost::system::error_code& ec, const std::string&) {
716 if (ec == boost::system::errc::file_exists)
717 {
718 messages::resourceAlreadyExists(
719 asyncResp->res, "MetricReportDefinition", "Id", id);
720 return;
721 }
722 if (ec == boost::system::errc::too_many_files_open)
723 {
724 messages::createLimitReachedForResource(asyncResp->res);
725 return;
726 }
727 if (ec == boost::system::errc::argument_list_too_long)
728 {
729 nlohmann::json metricProperties = nlohmann::json::array();
730 for (const auto& [uri, _] : uriToDbus)
731 {
732 metricProperties.emplace_back(uri);
733 }
734 messages::propertyValueIncorrect(
735 asyncResp->res, "MetricProperties", metricProperties);
736 return;
737 }
738 if (ec)
739 {
740 messages::internalError(asyncResp->res);
741 BMCWEB_LOG_ERROR("respHandler DBus error {}", ec);
742 return;
743 }
744
745 messages::created(asyncResp->res);
746 },
747 telemetry::service, "/xyz/openbmc_project/Telemetry/Reports",
748 "xyz.openbmc_project.Telemetry.ReportManager", "AddReport",
749 "TelemetryService/" + args.id, args.name, args.reportingType,
750 args.reportUpdates, args.appendLimit, args.reportActions,
751 args.interval, readingParams, args.metricReportDefinitionEnabled);
752 }
753
754 AddReport(const AddReport&) = delete;
755 AddReport(AddReport&&) = delete;
756 AddReport& operator=(const AddReport&) = delete;
757 AddReport& operator=(AddReport&&) = delete;
758
insert(const std::map<std::string,std::string> & el)759 void insert(const std::map<std::string, std::string>& el)
760 {
761 uriToDbus.insert(el.begin(), el.end());
762 }
763
764 private:
765 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
766 AddReportArgs args;
767 boost::container::flat_map<std::string, std::string> uriToDbus;
768 };
769
770 class UpdateMetrics
771 {
772 public:
UpdateMetrics(std::string_view idIn,const std::shared_ptr<bmcweb::AsyncResp> & asyncRespIn)773 UpdateMetrics(std::string_view idIn,
774 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
775 id(idIn),
776 asyncResp(asyncRespIn)
777 {}
778
~UpdateMetrics()779 ~UpdateMetrics()
780 {
781 try
782 {
783 setReadingParams();
784 }
785 catch (const std::exception& e)
786 {
787 BMCWEB_LOG_ERROR("{}", e.what());
788 }
789 catch (...)
790 {
791 BMCWEB_LOG_ERROR("Unknown error");
792 }
793 }
794
795 UpdateMetrics(const UpdateMetrics&) = delete;
796 UpdateMetrics(UpdateMetrics&&) = delete;
797 UpdateMetrics& operator=(const UpdateMetrics&) = delete;
798 UpdateMetrics& operator=(UpdateMetrics&&) = delete;
799
800 std::string id;
801 std::map<std::string, std::string> metricPropertyToDbusPaths;
802
insert(const std::map<std::string,std::string> & additionalMetricPropertyToDbusPaths)803 void insert(const std::map<std::string, std::string>&
804 additionalMetricPropertyToDbusPaths)
805 {
806 metricPropertyToDbusPaths.insert(
807 additionalMetricPropertyToDbusPaths.begin(),
808 additionalMetricPropertyToDbusPaths.end());
809 }
810
emplace(std::span<const std::tuple<sdbusplus::message::object_path,std::string>> pathAndUri,const AddReportArgs::MetricArgs & metricArgs)811 void emplace(std::span<const std::tuple<sdbusplus::message::object_path,
812 std::string>>
813 pathAndUri,
814 const AddReportArgs::MetricArgs& metricArgs)
815 {
816 readingParamsUris.emplace_back(metricArgs.uris);
817 readingParams.emplace_back(
818 std::vector(pathAndUri.begin(), pathAndUri.end()),
819 metricArgs.collectionFunction, metricArgs.collectionTimeScope,
820 metricArgs.collectionDuration);
821 }
822
setReadingParams()823 void setReadingParams()
824 {
825 if (asyncResp->res.result() != boost::beast::http::status::ok)
826 {
827 return;
828 }
829
830 for (size_t index = 0; index < readingParamsUris.size(); ++index)
831 {
832 std::span<const std::string> newUris = readingParamsUris[index];
833
834 const std::optional<std::vector<
835 std::tuple<sdbusplus::message::object_path, std::string>>>
836 readingParam = sensorPathToUri(newUris);
837
838 if (!readingParam)
839 {
840 return;
841 }
842
843 std::get<0>(readingParams[index]) = *readingParam;
844 }
845
846 crow::connections::systemBus->async_method_call(
847 [asyncResp(this->asyncResp),
848 reportId = id](const boost::system::error_code& ec) {
849 if (!verifyCommonErrors(asyncResp->res, reportId, ec))
850 {
851 return;
852 }
853 },
854 "xyz.openbmc_project.Telemetry", getDbusReportPath(id),
855 "org.freedesktop.DBus.Properties", "Set",
856 "xyz.openbmc_project.Telemetry.Report", "ReadingParameters",
857 dbus::utility::DbusVariantType{readingParams});
858 }
859
860 private:
861 std::optional<
862 std::vector<std::tuple<sdbusplus::message::object_path, std::string>>>
sensorPathToUri(std::span<const std::string> uris) const863 sensorPathToUri(std::span<const std::string> uris) const
864 {
865 std::vector<std::tuple<sdbusplus::message::object_path, std::string>>
866 result;
867
868 for (const std::string& uri : uris)
869 {
870 auto it = metricPropertyToDbusPaths.find(uri);
871 if (it == metricPropertyToDbusPaths.end())
872 {
873 messages::propertyValueNotInList(asyncResp->res, uri,
874 "MetricProperties");
875 return {};
876 }
877 result.emplace_back(it->second, uri);
878 }
879
880 return result;
881 }
882
883 const std::shared_ptr<bmcweb::AsyncResp> asyncResp;
884 std::vector<std::vector<std::string>> readingParamsUris;
885 ReadingParameters readingParams;
886 };
887
888 inline void
setReportEnabled(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string_view id,bool enabled)889 setReportEnabled(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
890 std::string_view id, bool enabled)
891 {
892 crow::connections::systemBus->async_method_call(
893 [asyncResp, id = std::string(id)](const boost::system::error_code& ec) {
894 if (!verifyCommonErrors(asyncResp->res, id, ec))
895 {
896 return;
897 }
898 },
899 "xyz.openbmc_project.Telemetry", getDbusReportPath(id),
900 "org.freedesktop.DBus.Properties", "Set",
901 "xyz.openbmc_project.Telemetry.Report", "Enabled",
902 dbus::utility::DbusVariantType{enabled});
903 }
904
setReportTypeAndInterval(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string_view id,const std::string & reportingType,uint64_t recurrenceInterval)905 inline void setReportTypeAndInterval(
906 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id,
907 const std::string& reportingType, uint64_t recurrenceInterval)
908 {
909 crow::connections::systemBus->async_method_call(
910 [asyncResp, id = std::string(id)](const boost::system::error_code& ec) {
911 if (!verifyCommonErrors(asyncResp->res, id, ec))
912 {
913 return;
914 }
915 },
916 "xyz.openbmc_project.Telemetry", getDbusReportPath(id),
917 "xyz.openbmc_project.Telemetry.Report", "SetReportingProperties",
918 reportingType, recurrenceInterval);
919 }
920
921 inline void
setReportUpdates(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string_view id,const std::string & reportUpdates)922 setReportUpdates(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
923 std::string_view id, const std::string& reportUpdates)
924 {
925 crow::connections::systemBus->async_method_call(
926 [asyncResp, id = std::string(id)](const boost::system::error_code& ec) {
927 if (!verifyCommonErrors(asyncResp->res, id, ec))
928 {
929 return;
930 }
931 },
932 "xyz.openbmc_project.Telemetry", getDbusReportPath(id),
933 "org.freedesktop.DBus.Properties", "Set",
934 "xyz.openbmc_project.Telemetry.Report", "ReportUpdates",
935 dbus::utility::DbusVariantType{reportUpdates});
936 }
937
938 inline void
setReportActions(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string_view id,const std::vector<std::string> & dbusReportActions)939 setReportActions(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
940 std::string_view id,
941 const std::vector<std::string>& dbusReportActions)
942 {
943 crow::connections::systemBus->async_method_call(
944 [asyncResp, id = std::string(id)](const boost::system::error_code& ec) {
945 if (!verifyCommonErrors(asyncResp->res, id, ec))
946 {
947 return;
948 }
949 },
950 "xyz.openbmc_project.Telemetry", getDbusReportPath(id),
951 "org.freedesktop.DBus.Properties", "Set",
952 "xyz.openbmc_project.Telemetry.Report", "ReportActions",
953 dbus::utility::DbusVariantType{dbusReportActions});
954 }
955
956 inline void
setReportMetrics(const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string_view id,std::span<nlohmann::json::object_t> metrics)957 setReportMetrics(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
958 std::string_view id,
959 std::span<nlohmann::json::object_t> metrics)
960 {
961 sdbusplus::asio::getAllProperties(
962 *crow::connections::systemBus, telemetry::service,
963 telemetry::getDbusReportPath(id), telemetry::reportInterface,
964 [asyncResp, id = std::string(id),
965 redfishMetrics = std::vector<nlohmann::json::object_t>(metrics.begin(),
966 metrics.end())](
967 boost::system::error_code ec,
968 const dbus::utility::DBusPropertiesMap& properties) mutable {
969 if (!redfish::telemetry::verifyCommonErrors(asyncResp->res, id, ec))
970 {
971 return;
972 }
973
974 ReadingParameters readingParams;
975
976 const bool success = sdbusplus::unpackPropertiesNoThrow(
977 dbus_utils::UnpackErrorPrinter(), properties, "ReadingParameters",
978 readingParams);
979
980 if (!success)
981 {
982 messages::internalError(asyncResp->res);
983 return;
984 }
985
986 auto updateMetricsReq = std::make_shared<UpdateMetrics>(id, asyncResp);
987
988 boost::container::flat_set<std::pair<std::string, std::string>>
989 chassisSensors;
990
991 size_t index = 0;
992 for (nlohmann::json::object_t& metric : redfishMetrics)
993 {
994 AddReportArgs::MetricArgs metricArgs;
995 std::vector<
996 std::tuple<sdbusplus::message::object_path, std::string>>
997 pathAndUri;
998
999 if (index < readingParams.size())
1000 {
1001 const ReadingParameters::value_type& existing =
1002 readingParams[index];
1003
1004 pathAndUri = std::get<0>(existing);
1005 metricArgs.collectionFunction = std::get<1>(existing);
1006 metricArgs.collectionTimeScope = std::get<2>(existing);
1007 metricArgs.collectionDuration = std::get<3>(existing);
1008 }
1009
1010 if (!getUserMetric(asyncResp->res, metric, metricArgs))
1011 {
1012 return;
1013 }
1014
1015 std::optional<IncorrectMetricUri> error =
1016 getChassisSensorNode(metricArgs.uris, chassisSensors);
1017
1018 if (error)
1019 {
1020 messages::propertyValueIncorrect(
1021 asyncResp->res, error->uri,
1022 "MetricProperties/" + std::to_string(error->index));
1023 return;
1024 }
1025
1026 updateMetricsReq->emplace(pathAndUri, metricArgs);
1027 index++;
1028 }
1029
1030 for (const auto& [chassis, sensorType] : chassisSensors)
1031 {
1032 retrieveUriToDbusMap(
1033 chassis, sensorType,
1034 [asyncResp, updateMetricsReq](
1035 const boost::beast::http::status status,
1036 const std::map<std::string, std::string>& uriToDbus) {
1037 if (status != boost::beast::http::status::ok)
1038 {
1039 BMCWEB_LOG_ERROR(
1040 "Failed to retrieve URI to dbus sensors map with err {}",
1041 static_cast<unsigned>(status));
1042 return;
1043 }
1044 updateMetricsReq->insert(uriToDbus);
1045 });
1046 }
1047 });
1048 }
1049
handleMetricReportDefinitionCollectionHead(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1050 inline void handleMetricReportDefinitionCollectionHead(
1051 App& app, const crow::Request& req,
1052 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1053 {
1054 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1055 {
1056 return;
1057 }
1058 asyncResp->res.addHeader(
1059 boost::beast::http::field::link,
1060 "</redfish/v1/JsonSchemas/MetricReportDefinitionCollection/MetricReportDefinitionCollection.json>; rel=describedby");
1061 }
1062
handleMetricReportDefinitionCollectionGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1063 inline void handleMetricReportDefinitionCollectionGet(
1064 App& app, const crow::Request& req,
1065 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1066 {
1067 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1068 {
1069 return;
1070 }
1071 asyncResp->res.addHeader(
1072 boost::beast::http::field::link,
1073 "</redfish/v1/JsonSchemas/MetricReportDefinition/MetricReportDefinition.json>; rel=describedby");
1074
1075 asyncResp->res.jsonValue["@odata.type"] =
1076 "#MetricReportDefinitionCollection."
1077 "MetricReportDefinitionCollection";
1078 asyncResp->res.jsonValue["@odata.id"] =
1079 "/redfish/v1/TelemetryService/MetricReportDefinitions";
1080 asyncResp->res.jsonValue["Name"] = "Metric Definition Collection";
1081 constexpr std::array<std::string_view, 1> interfaces{
1082 telemetry::reportInterface};
1083 collection_util::getCollectionMembers(
1084 asyncResp,
1085 boost::urls::url(
1086 "/redfish/v1/TelemetryService/MetricReportDefinitions"),
1087 interfaces, "/xyz/openbmc_project/Telemetry/Reports/TelemetryService");
1088 }
1089
1090 inline void
handleReportPatch(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string_view id)1091 handleReportPatch(App& app, const crow::Request& req,
1092 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1093 std::string_view id)
1094 {
1095 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1096 {
1097 return;
1098 }
1099
1100 std::optional<std::string> reportingTypeStr;
1101 std::optional<std::string> reportUpdatesStr;
1102 std::optional<bool> metricReportDefinitionEnabled;
1103 std::optional<std::vector<nlohmann::json::object_t>> metrics;
1104 std::optional<std::vector<std::string>> reportActionsStr;
1105 std::optional<std::string> scheduleDurationStr;
1106
1107 if (!json_util::readJsonPatch(
1108 req, asyncResp->res, "Metrics", metrics,
1109 "MetricReportDefinitionType", reportingTypeStr, "ReportUpdates",
1110 reportUpdatesStr, "ReportActions", reportActionsStr,
1111 "Schedule/RecurrenceInterval", scheduleDurationStr,
1112 "MetricReportDefinitionEnabled", metricReportDefinitionEnabled))
1113 {
1114 return;
1115 }
1116
1117 if (metricReportDefinitionEnabled)
1118 {
1119 setReportEnabled(asyncResp, id, *metricReportDefinitionEnabled);
1120 }
1121
1122 if (reportUpdatesStr)
1123 {
1124 std::string dbusReportUpdates = toDbusReportUpdates(*reportUpdatesStr);
1125 if (dbusReportUpdates.empty())
1126 {
1127 messages::propertyValueNotInList(asyncResp->res, *reportUpdatesStr,
1128 "ReportUpdates");
1129 return;
1130 }
1131 setReportUpdates(asyncResp, id, dbusReportUpdates);
1132 }
1133
1134 if (reportActionsStr)
1135 {
1136 std::vector<std::string> dbusReportActions;
1137 if (!toDbusReportActions(asyncResp->res, *reportActionsStr,
1138 dbusReportActions))
1139 {
1140 return;
1141 }
1142 setReportActions(asyncResp, id, dbusReportActions);
1143 }
1144
1145 if (reportingTypeStr || scheduleDurationStr)
1146 {
1147 std::string dbusReportingType;
1148 if (reportingTypeStr)
1149 {
1150 dbusReportingType = toDbusReportingType(*reportingTypeStr);
1151 if (dbusReportingType.empty())
1152 {
1153 messages::propertyValueNotInList(asyncResp->res,
1154 *reportingTypeStr,
1155 "MetricReportDefinitionType");
1156 return;
1157 }
1158 }
1159
1160 uint64_t recurrenceInterval = std::numeric_limits<uint64_t>::max();
1161 if (scheduleDurationStr)
1162 {
1163 std::optional<std::chrono::milliseconds> durationNum =
1164 time_utils::fromDurationString(*scheduleDurationStr);
1165 if (!durationNum || durationNum->count() < 0)
1166 {
1167 messages::propertyValueIncorrect(
1168 asyncResp->res, "RecurrenceInterval", *scheduleDurationStr);
1169 return;
1170 }
1171
1172 recurrenceInterval = static_cast<uint64_t>(durationNum->count());
1173 }
1174
1175 setReportTypeAndInterval(asyncResp, id, dbusReportingType,
1176 recurrenceInterval);
1177 }
1178
1179 if (metrics)
1180 {
1181 setReportMetrics(asyncResp, id, *metrics);
1182 }
1183 }
1184
1185 inline void
handleReportDelete(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,std::string_view id)1186 handleReportDelete(App& app, const crow::Request& req,
1187 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1188 std::string_view id)
1189 {
1190 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1191 {
1192 return;
1193 }
1194
1195 const std::string reportPath = getDbusReportPath(id);
1196
1197 crow::connections::systemBus->async_method_call(
1198 [asyncResp,
1199 reportId = std::string(id)](const boost::system::error_code& ec) {
1200 if (!verifyCommonErrors(asyncResp->res, reportId, ec))
1201 {
1202 return;
1203 }
1204 asyncResp->res.result(boost::beast::http::status::no_content);
1205 },
1206 service, reportPath, "xyz.openbmc_project.Object.Delete", "Delete");
1207 }
1208 } // namespace telemetry
1209
afterRetrieveUriToDbusMap(const std::shared_ptr<bmcweb::AsyncResp> &,const std::shared_ptr<telemetry::AddReport> & addReportReq,const boost::beast::http::status status,const std::map<std::string,std::string> & uriToDbus)1210 inline void afterRetrieveUriToDbusMap(
1211 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
1212 const std::shared_ptr<telemetry::AddReport>& addReportReq,
1213 const boost::beast::http::status status,
1214 const std::map<std::string, std::string>& uriToDbus)
1215 {
1216 if (status != boost::beast::http::status::ok)
1217 {
1218 BMCWEB_LOG_ERROR(
1219 "Failed to retrieve URI to dbus sensors map with err {}",
1220 static_cast<unsigned>(status));
1221 return;
1222 }
1223 addReportReq->insert(uriToDbus);
1224 }
1225
handleMetricReportDefinitionsPost(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp)1226 inline void handleMetricReportDefinitionsPost(
1227 App& app, const crow::Request& req,
1228 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
1229 {
1230 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1231 {
1232 return;
1233 }
1234
1235 telemetry::AddReportArgs args;
1236 if (!telemetry::getUserParameters(asyncResp->res, req, args))
1237 {
1238 return;
1239 }
1240
1241 boost::container::flat_set<std::pair<std::string, std::string>>
1242 chassisSensors;
1243 if (!telemetry::getChassisSensorNodeFromMetrics(asyncResp, args.metrics,
1244 chassisSensors))
1245 {
1246 return;
1247 }
1248
1249 auto addReportReq = std::make_shared<telemetry::AddReport>(std::move(args),
1250 asyncResp);
1251 for (const auto& [chassis, sensorType] : chassisSensors)
1252 {
1253 retrieveUriToDbusMap(chassis, sensorType,
1254 std::bind_front(afterRetrieveUriToDbusMap,
1255 asyncResp, addReportReq));
1256 }
1257 }
1258
1259 inline void
handleMetricReportHead(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string &)1260 handleMetricReportHead(App& app, const crow::Request& req,
1261 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1262 const std::string& /*id*/)
1263 {
1264 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1265 {
1266 return;
1267 }
1268 asyncResp->res.addHeader(
1269 boost::beast::http::field::link,
1270 "</redfish/v1/JsonSchemas/MetricReport/MetricReport.json>; rel=describedby");
1271 }
1272
1273 inline void
handleMetricReportGet(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & id)1274 handleMetricReportGet(App& app, const crow::Request& req,
1275 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1276 const std::string& id)
1277 {
1278 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1279 {
1280 return;
1281 }
1282 asyncResp->res.addHeader(
1283 boost::beast::http::field::link,
1284 "</redfish/v1/JsonSchemas/MetricReport/MetricReport.json>; rel=describedby");
1285
1286 sdbusplus::asio::getAllProperties(
1287 *crow::connections::systemBus, telemetry::service,
1288 telemetry::getDbusReportPath(id), telemetry::reportInterface,
1289 [asyncResp, id](const boost::system::error_code& ec,
1290 const dbus::utility::DBusPropertiesMap& properties) {
1291 if (!redfish::telemetry::verifyCommonErrors(asyncResp->res, id, ec))
1292 {
1293 return;
1294 }
1295
1296 telemetry::fillReportDefinition(asyncResp, id, properties);
1297 });
1298 }
1299
handleMetricReportDelete(App & app,const crow::Request & req,const std::shared_ptr<bmcweb::AsyncResp> & asyncResp,const std::string & id)1300 inline void handleMetricReportDelete(
1301 App& app, const crow::Request& req,
1302 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id)
1303
1304 {
1305 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
1306 {
1307 return;
1308 }
1309
1310 const std::string reportPath = telemetry::getDbusReportPath(id);
1311
1312 crow::connections::systemBus->async_method_call(
1313 [asyncResp, id](const boost::system::error_code& ec) {
1314 /*
1315 * boost::system::errc and std::errc are missing value
1316 * for EBADR error that is defined in Linux.
1317 */
1318 if (ec.value() == EBADR)
1319 {
1320 messages::resourceNotFound(asyncResp->res, "MetricReportDefinition",
1321 id);
1322 return;
1323 }
1324
1325 if (ec)
1326 {
1327 BMCWEB_LOG_ERROR("respHandler DBus error {}", ec);
1328 messages::internalError(asyncResp->res);
1329 return;
1330 }
1331
1332 asyncResp->res.result(boost::beast::http::status::no_content);
1333 },
1334 telemetry::service, reportPath, "xyz.openbmc_project.Object.Delete",
1335 "Delete");
1336 }
1337
requestRoutesMetricReportDefinitionCollection(App & app)1338 inline void requestRoutesMetricReportDefinitionCollection(App& app)
1339 {
1340 BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/")
1341 .privileges(redfish::privileges::headMetricReportDefinitionCollection)
1342 .methods(boost::beast::http::verb::head)(std::bind_front(
1343 telemetry::handleMetricReportDefinitionCollectionHead,
1344 std::ref(app)));
1345
1346 BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/")
1347 .privileges(redfish::privileges::getMetricReportDefinitionCollection)
1348 .methods(boost::beast::http::verb::get)(std::bind_front(
1349 telemetry::handleMetricReportDefinitionCollectionGet,
1350 std::ref(app)));
1351
1352 BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/")
1353 .privileges(redfish::privileges::postMetricReportDefinitionCollection)
1354 .methods(boost::beast::http::verb::post)(
1355 std::bind_front(handleMetricReportDefinitionsPost, std::ref(app)));
1356 }
1357
requestRoutesMetricReportDefinition(App & app)1358 inline void requestRoutesMetricReportDefinition(App& app)
1359 {
1360 BMCWEB_ROUTE(app,
1361 "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/")
1362 .privileges(redfish::privileges::getMetricReportDefinition)
1363 .methods(boost::beast::http::verb::head)(
1364 std::bind_front(handleMetricReportHead, std::ref(app)));
1365
1366 BMCWEB_ROUTE(app,
1367 "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/")
1368 .privileges(redfish::privileges::getMetricReportDefinition)
1369 .methods(boost::beast::http::verb::get)(
1370 std::bind_front(handleMetricReportGet, std::ref(app)));
1371
1372 BMCWEB_ROUTE(app,
1373 "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/")
1374 .privileges(redfish::privileges::deleteMetricReportDefinition)
1375 .methods(boost::beast::http::verb::delete_)(
1376 std::bind_front(handleMetricReportDelete, std::ref(app)));
1377
1378 BMCWEB_ROUTE(app,
1379 "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/")
1380 .privileges(redfish::privileges::patchMetricReportDefinition)
1381 .methods(boost::beast::http::verb::patch)(
1382 std::bind_front(telemetry::handleReportPatch, std::ref(app)));
1383 }
1384 } // namespace redfish
1385