1 #pragma once 2 3 #include "app.hpp" 4 #include "dbus_utility.hpp" 5 #include "generated/enums/metric_report_definition.hpp" 6 #include "generated/enums/resource.hpp" 7 #include "query.hpp" 8 #include "registries/privilege_registry.hpp" 9 #include "sensors.hpp" 10 #include "utils/collection.hpp" 11 #include "utils/dbus_utils.hpp" 12 #include "utils/json_utils.hpp" 13 #include "utils/telemetry_utils.hpp" 14 #include "utils/time_utils.hpp" 15 16 #include <boost/container/flat_map.hpp> 17 #include <boost/url/format.hpp> 18 #include <sdbusplus/asio/property.hpp> 19 #include <sdbusplus/unpack_properties.hpp> 20 21 #include <array> 22 #include <map> 23 #include <optional> 24 #include <span> 25 #include <string> 26 #include <string_view> 27 #include <tuple> 28 #include <utility> 29 #include <variant> 30 #include <vector> 31 32 namespace redfish 33 { 34 35 namespace telemetry 36 { 37 38 using ReadingParameters = std::vector<std::tuple< 39 std::vector<std::tuple<sdbusplus::message::object_path, std::string>>, 40 std::string, std::string, uint64_t>>; 41 42 inline bool verifyCommonErrors(crow::Response& res, const std::string& id, 43 const boost::system::error_code& ec) 44 { 45 if (ec.value() == EBADR || ec == boost::system::errc::host_unreachable) 46 { 47 messages::resourceNotFound(res, "MetricReportDefinition", id); 48 return false; 49 } 50 51 if (ec == boost::system::errc::file_exists) 52 { 53 messages::resourceAlreadyExists(res, "MetricReportDefinition", "Id", 54 id); 55 return false; 56 } 57 58 if (ec == boost::system::errc::too_many_files_open) 59 { 60 messages::createLimitReachedForResource(res); 61 return false; 62 } 63 64 if (ec) 65 { 66 BMCWEB_LOG_ERROR("DBUS response error {}", ec); 67 messages::internalError(res); 68 return false; 69 } 70 71 return true; 72 } 73 74 inline metric_report_definition::ReportActionsEnum 75 toRedfishReportAction(std::string_view dbusValue) 76 { 77 if (dbusValue == 78 "xyz.openbmc_project.Telemetry.Report.ReportActions.EmitsReadingsUpdate") 79 { 80 return metric_report_definition::ReportActionsEnum::RedfishEvent; 81 } 82 if (dbusValue == 83 "xyz.openbmc_project.Telemetry.Report.ReportActions.LogToMetricReportsCollection") 84 { 85 return metric_report_definition::ReportActionsEnum:: 86 LogToMetricReportsCollection; 87 } 88 return metric_report_definition::ReportActionsEnum::Invalid; 89 } 90 91 inline std::string toDbusReportAction(std::string_view redfishValue) 92 { 93 if (redfishValue == "RedfishEvent") 94 { 95 return "xyz.openbmc_project.Telemetry.Report.ReportActions.EmitsReadingsUpdate"; 96 } 97 if (redfishValue == "LogToMetricReportsCollection") 98 { 99 return "xyz.openbmc_project.Telemetry.Report.ReportActions.LogToMetricReportsCollection"; 100 } 101 return ""; 102 } 103 104 inline metric_report_definition::MetricReportDefinitionType 105 toRedfishReportingType(std::string_view dbusValue) 106 { 107 if (dbusValue == 108 "xyz.openbmc_project.Telemetry.Report.ReportingType.OnChange") 109 { 110 return metric_report_definition::MetricReportDefinitionType::OnChange; 111 } 112 if (dbusValue == 113 "xyz.openbmc_project.Telemetry.Report.ReportingType.OnRequest") 114 { 115 return metric_report_definition::MetricReportDefinitionType::OnRequest; 116 } 117 if (dbusValue == 118 "xyz.openbmc_project.Telemetry.Report.ReportingType.Periodic") 119 { 120 return metric_report_definition::MetricReportDefinitionType::Periodic; 121 } 122 return metric_report_definition::MetricReportDefinitionType::Invalid; 123 } 124 125 inline std::string toDbusReportingType(std::string_view redfishValue) 126 { 127 if (redfishValue == "OnChange") 128 { 129 return "xyz.openbmc_project.Telemetry.Report.ReportingType.OnChange"; 130 } 131 if (redfishValue == "OnRequest") 132 { 133 return "xyz.openbmc_project.Telemetry.Report.ReportingType.OnRequest"; 134 } 135 if (redfishValue == "Periodic") 136 { 137 return "xyz.openbmc_project.Telemetry.Report.ReportingType.Periodic"; 138 } 139 return ""; 140 } 141 142 inline metric_report_definition::CollectionTimeScope 143 toRedfishCollectionTimeScope(std::string_view dbusValue) 144 { 145 if (dbusValue == 146 "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.Point") 147 { 148 return metric_report_definition::CollectionTimeScope::Point; 149 } 150 if (dbusValue == 151 "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.Interval") 152 { 153 return metric_report_definition::CollectionTimeScope::Interval; 154 } 155 if (dbusValue == 156 "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.StartupInterval") 157 { 158 return metric_report_definition::CollectionTimeScope::StartupInterval; 159 } 160 return metric_report_definition::CollectionTimeScope::Invalid; 161 } 162 163 inline std::string toDbusCollectionTimeScope(std::string_view redfishValue) 164 { 165 if (redfishValue == "Point") 166 { 167 return "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.Point"; 168 } 169 if (redfishValue == "Interval") 170 { 171 return "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.Interval"; 172 } 173 if (redfishValue == "StartupInterval") 174 { 175 return "xyz.openbmc_project.Telemetry.Report.CollectionTimescope.StartupInterval"; 176 } 177 return ""; 178 } 179 180 inline metric_report_definition::ReportUpdatesEnum 181 toRedfishReportUpdates(std::string_view dbusValue) 182 { 183 if (dbusValue == 184 "xyz.openbmc_project.Telemetry.Report.ReportUpdates.Overwrite") 185 { 186 return metric_report_definition::ReportUpdatesEnum::Overwrite; 187 } 188 if (dbusValue == 189 "xyz.openbmc_project.Telemetry.Report.ReportUpdates.AppendWrapsWhenFull") 190 { 191 return metric_report_definition::ReportUpdatesEnum::AppendWrapsWhenFull; 192 } 193 if (dbusValue == 194 "xyz.openbmc_project.Telemetry.Report.ReportUpdates.AppendStopsWhenFull") 195 { 196 return metric_report_definition::ReportUpdatesEnum::AppendStopsWhenFull; 197 } 198 return metric_report_definition::ReportUpdatesEnum::Invalid; 199 } 200 201 inline std::string toDbusReportUpdates(std::string_view redfishValue) 202 { 203 if (redfishValue == "Overwrite") 204 { 205 return "xyz.openbmc_project.Telemetry.Report.ReportUpdates.Overwrite"; 206 } 207 if (redfishValue == "AppendWrapsWhenFull") 208 { 209 return "xyz.openbmc_project.Telemetry.Report.ReportUpdates.AppendWrapsWhenFull"; 210 } 211 if (redfishValue == "AppendStopsWhenFull") 212 { 213 return "xyz.openbmc_project.Telemetry.Report.ReportUpdates.AppendStopsWhenFull"; 214 } 215 return ""; 216 } 217 218 inline std::optional<nlohmann::json::array_t> getLinkedTriggers( 219 std::span<const sdbusplus::message::object_path> triggerPaths) 220 { 221 nlohmann::json::array_t triggers; 222 223 for (const sdbusplus::message::object_path& path : triggerPaths) 224 { 225 if (path.parent_path() != 226 "/xyz/openbmc_project/Telemetry/Triggers/TelemetryService") 227 { 228 BMCWEB_LOG_ERROR("Property Triggers contains invalid value: {}", 229 path.str); 230 return std::nullopt; 231 } 232 233 std::string id = path.filename(); 234 if (id.empty()) 235 { 236 BMCWEB_LOG_ERROR("Property Triggers contains invalid value: {}", 237 path.str); 238 return std::nullopt; 239 } 240 nlohmann::json::object_t trigger; 241 trigger["@odata.id"] = 242 boost::urls::format("/redfish/v1/TelemetryService/Triggers/{}", id); 243 triggers.emplace_back(std::move(trigger)); 244 } 245 246 return triggers; 247 } 248 249 inline void fillReportDefinition( 250 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 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"] = resource::State::Enabled; 360 } 361 else 362 { 363 asyncResp->res.jsonValue["Status"]["State"] = resource::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 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 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 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 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 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( 645 asyncResp->res, error->uri, 646 "MetricProperties/" + std::to_string(error->index)); 647 return false; 648 } 649 } 650 return true; 651 } 652 653 inline std::string toRedfishProperty(std::string_view dbusMessage) 654 { 655 if (dbusMessage == "Id") 656 { 657 return "Id"; 658 } 659 if (dbusMessage == "Name") 660 { 661 return "Name"; 662 } 663 if (dbusMessage == "ReportingType") 664 { 665 return "MetricReportDefinitionType"; 666 } 667 if (dbusMessage == "AppendLimit") 668 { 669 return "AppendLimit"; 670 } 671 if (dbusMessage == "ReportActions") 672 { 673 return "ReportActions"; 674 } 675 if (dbusMessage == "Interval") 676 { 677 return "RecurrenceInterval"; 678 } 679 if (dbusMessage == "ReportUpdates") 680 { 681 return "ReportUpdates"; 682 } 683 if (dbusMessage == "ReadingParameters") 684 { 685 return "Metrics"; 686 } 687 return ""; 688 } 689 690 inline bool handleParamError(crow::Response& res, const char* errorMessage, 691 std::string_view key) 692 { 693 if (errorMessage == nullptr) 694 { 695 BMCWEB_LOG_ERROR("errorMessage was null"); 696 return true; 697 } 698 std::string_view errorMessageSv(errorMessage); 699 if (errorMessageSv.starts_with(key)) 700 { 701 std::string redfishProperty = toRedfishProperty(key); 702 if (redfishProperty.empty()) 703 { 704 // Getting here means most possibly that toRedfishProperty has 705 // incomplete implementation. Return internal error for now. 706 BMCWEB_LOG_ERROR("{} has no corresponding Redfish property", key); 707 messages::internalError(res); 708 return false; 709 } 710 messages::propertyValueError(res, redfishProperty); 711 return false; 712 } 713 714 return true; 715 } 716 717 inline void afterAddReport(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 718 const AddReportArgs& args, 719 const boost::system::error_code& ec, 720 const sdbusplus::message_t& msg) 721 { 722 if (!ec) 723 { 724 messages::created(asyncResp->res); 725 return; 726 } 727 728 if (ec == boost::system::errc::invalid_argument) 729 { 730 const sd_bus_error* errorMessage = msg.get_error(); 731 if (errorMessage != nullptr) 732 { 733 for (const auto& arg : 734 {"Id", "Name", "ReportingType", "AppendLimit", "ReportActions", 735 "Interval", "ReportUpdates", "ReadingParameters"}) 736 { 737 if (!handleParamError(asyncResp->res, errorMessage->message, 738 arg)) 739 { 740 return; 741 } 742 } 743 } 744 } 745 if (!verifyCommonErrors(asyncResp->res, args.id, ec)) 746 { 747 return; 748 } 749 messages::internalError(asyncResp->res); 750 } 751 752 class AddReport 753 { 754 public: 755 AddReport(AddReportArgs&& argsIn, 756 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) : 757 asyncResp(asyncRespIn), args(std::move(argsIn)) 758 {} 759 760 ~AddReport() 761 { 762 boost::asio::post(crow::connections::systemBus->get_io_context(), 763 std::bind_front(&performAddReport, asyncResp, args, 764 std::move(uriToDbus))); 765 } 766 767 static void performAddReport( 768 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 769 const AddReportArgs& args, 770 const boost::container::flat_map<std::string, std::string>& uriToDbus) 771 { 772 if (asyncResp->res.result() != boost::beast::http::status::ok) 773 { 774 return; 775 } 776 777 telemetry::ReadingParameters readingParams; 778 readingParams.reserve(args.metrics.size()); 779 780 for (const auto& metric : args.metrics) 781 { 782 std::vector< 783 std::tuple<sdbusplus::message::object_path, std::string>> 784 sensorParams; 785 sensorParams.reserve(metric.uris.size()); 786 787 for (size_t i = 0; i < metric.uris.size(); i++) 788 { 789 const std::string& uri = metric.uris[i]; 790 auto el = uriToDbus.find(uri); 791 if (el == uriToDbus.end()) 792 { 793 BMCWEB_LOG_ERROR( 794 "Failed to find DBus sensor corresponding to URI {}", 795 uri); 796 messages::propertyValueNotInList( 797 asyncResp->res, uri, 798 "MetricProperties/" + std::to_string(i)); 799 return; 800 } 801 802 const std::string& dbusPath = el->second; 803 sensorParams.emplace_back(dbusPath, uri); 804 } 805 806 readingParams.emplace_back( 807 std::move(sensorParams), metric.collectionFunction, 808 metric.collectionTimeScope, metric.collectionDuration); 809 } 810 crow::connections::systemBus->async_method_call( 811 [asyncResp, args](const boost::system::error_code& ec, 812 const sdbusplus::message_t& msg, 813 const std::string& /*arg1*/) { 814 afterAddReport(asyncResp, args, ec, msg); 815 }, 816 telemetry::service, "/xyz/openbmc_project/Telemetry/Reports", 817 "xyz.openbmc_project.Telemetry.ReportManager", "AddReport", 818 "TelemetryService/" + args.id, args.name, args.reportingType, 819 args.reportUpdates, args.appendLimit, args.reportActions, 820 args.interval, readingParams, args.metricReportDefinitionEnabled); 821 } 822 823 AddReport(const AddReport&) = delete; 824 AddReport(AddReport&&) = delete; 825 AddReport& operator=(const AddReport&) = delete; 826 AddReport& operator=(AddReport&&) = delete; 827 828 void insert(const std::map<std::string, std::string>& el) 829 { 830 uriToDbus.insert(el.begin(), el.end()); 831 } 832 833 private: 834 const std::shared_ptr<bmcweb::AsyncResp> asyncResp; 835 AddReportArgs args; 836 boost::container::flat_map<std::string, std::string> uriToDbus; 837 }; 838 839 inline std::optional< 840 std::vector<std::tuple<sdbusplus::message::object_path, std::string>>> 841 sensorPathToUri( 842 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 843 std::span<const std::string> uris, 844 const std::map<std::string, std::string>& metricPropertyToDbusPaths) 845 { 846 std::vector<std::tuple<sdbusplus::message::object_path, std::string>> 847 result; 848 849 for (const std::string& uri : uris) 850 { 851 auto it = metricPropertyToDbusPaths.find(uri); 852 if (it == metricPropertyToDbusPaths.end()) 853 { 854 messages::propertyValueNotInList(asyncResp->res, uri, 855 "MetricProperties"); 856 return {}; 857 } 858 result.emplace_back(it->second, uri); 859 } 860 861 return result; 862 } 863 864 inline void afterSetReadingParams( 865 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 866 const std::string& reportId, const boost::system::error_code& ec, 867 const sdbusplus::message_t& msg) 868 { 869 if (!ec) 870 { 871 messages::success(asyncResp->res); 872 return; 873 } 874 if (ec == boost::system::errc::invalid_argument) 875 { 876 const sd_bus_error* errorMessage = msg.get_error(); 877 if (errorMessage != nullptr) 878 { 879 for (const auto& arg : {"Id", "ReadingParameters"}) 880 { 881 if (!handleParamError(asyncResp->res, errorMessage->message, 882 arg)) 883 { 884 return; 885 } 886 } 887 } 888 } 889 if (!verifyCommonErrors(asyncResp->res, reportId, ec)) 890 { 891 return; 892 } 893 messages::internalError(asyncResp->res); 894 } 895 896 inline void setReadingParams( 897 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 898 const std::string& reportId, ReadingParameters readingParams, 899 const std::vector<std::vector<std::string>>& readingParamsUris, 900 const std::map<std::string, std::string>& metricPropertyToDbusPaths) 901 { 902 if (asyncResp->res.result() != boost::beast::http::status::ok) 903 { 904 return; 905 } 906 907 for (size_t index = 0; index < readingParamsUris.size(); ++index) 908 { 909 std::span<const std::string> newUris = readingParamsUris[index]; 910 911 const std::optional<std::vector< 912 std::tuple<sdbusplus::message::object_path, std::string>>> 913 readingParam = 914 sensorPathToUri(asyncResp, newUris, metricPropertyToDbusPaths); 915 916 if (!readingParam) 917 { 918 return; 919 } 920 921 for (const std::tuple<sdbusplus::message::object_path, std::string>& 922 value : *readingParam) 923 { 924 std::get<0>(readingParams[index]).emplace_back(value); 925 } 926 } 927 928 crow::connections::systemBus->async_method_call( 929 [asyncResp, reportId](const boost::system::error_code& ec, 930 const sdbusplus::message_t& msg) { 931 afterSetReadingParams(asyncResp, reportId, ec, msg); 932 }, 933 "xyz.openbmc_project.Telemetry", getDbusReportPath(reportId), 934 "org.freedesktop.DBus.Properties", "Set", 935 "xyz.openbmc_project.Telemetry.Report", "ReadingParameters", 936 dbus::utility::DbusVariantType{readingParams}); 937 } 938 939 class UpdateMetrics 940 { 941 public: 942 UpdateMetrics(std::string_view idIn, 943 const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) : 944 id(idIn), asyncResp(asyncRespIn) 945 {} 946 947 ~UpdateMetrics() 948 { 949 boost::asio::post( 950 crow::connections::systemBus->get_io_context(), 951 std::bind_front(&setReadingParams, asyncResp, id, 952 std::move(readingParams), readingParamsUris, 953 metricPropertyToDbusPaths)); 954 } 955 956 UpdateMetrics(const UpdateMetrics&) = delete; 957 UpdateMetrics(UpdateMetrics&&) = delete; 958 UpdateMetrics& operator=(const UpdateMetrics&) = delete; 959 UpdateMetrics& operator=(UpdateMetrics&&) = delete; 960 961 std::string id; 962 std::map<std::string, std::string> metricPropertyToDbusPaths; 963 964 void insert(const std::map<std::string, std::string>& 965 additionalMetricPropertyToDbusPaths) 966 { 967 metricPropertyToDbusPaths.insert( 968 additionalMetricPropertyToDbusPaths.begin(), 969 additionalMetricPropertyToDbusPaths.end()); 970 } 971 972 void emplace( 973 std::span< 974 const std::tuple<sdbusplus::message::object_path, std::string>> 975 pathAndUri, 976 const AddReportArgs::MetricArgs& metricArgs) 977 { 978 readingParamsUris.emplace_back(metricArgs.uris); 979 readingParams.emplace_back( 980 std::vector(pathAndUri.begin(), pathAndUri.end()), 981 metricArgs.collectionFunction, metricArgs.collectionTimeScope, 982 metricArgs.collectionDuration); 983 } 984 985 private: 986 const std::shared_ptr<bmcweb::AsyncResp> asyncResp; 987 std::vector<std::vector<std::string>> readingParamsUris; 988 ReadingParameters readingParams; 989 }; 990 991 inline void 992 setReportEnabled(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 993 std::string_view id, bool enabled) 994 { 995 crow::connections::systemBus->async_method_call( 996 [asyncResp, id = std::string(id)](const boost::system::error_code& ec) { 997 if (!verifyCommonErrors(asyncResp->res, id, ec)) 998 { 999 return; 1000 } 1001 }, 1002 "xyz.openbmc_project.Telemetry", getDbusReportPath(id), 1003 "org.freedesktop.DBus.Properties", "Set", 1004 "xyz.openbmc_project.Telemetry.Report", "Enabled", 1005 dbus::utility::DbusVariantType{enabled}); 1006 } 1007 1008 inline void afterSetReportingProperties( 1009 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id, 1010 const boost::system::error_code& ec, const sdbusplus::message_t& msg) 1011 { 1012 if (!ec) 1013 { 1014 asyncResp->res.result(boost::beast::http::status::no_content); 1015 return; 1016 } 1017 1018 if (ec == boost::system::errc::invalid_argument) 1019 { 1020 const sd_bus_error* errorMessage = msg.get_error(); 1021 if (errorMessage != nullptr) 1022 { 1023 for (const auto& arg : {"Id", "ReportingType", "Interval"}) 1024 { 1025 if (!handleParamError(asyncResp->res, errorMessage->message, 1026 arg)) 1027 { 1028 return; 1029 } 1030 } 1031 } 1032 } 1033 if (!verifyCommonErrors(asyncResp->res, id, ec)) 1034 { 1035 return; 1036 } 1037 messages::internalError(asyncResp->res); 1038 } 1039 1040 inline void setReportTypeAndInterval( 1041 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id, 1042 const std::optional<std::string>& reportingType, 1043 const std::optional<std::string>& recurrenceIntervalStr) 1044 { 1045 std::string dbusReportingType; 1046 if (reportingType) 1047 { 1048 dbusReportingType = toDbusReportingType(*reportingType); 1049 if (dbusReportingType.empty()) 1050 { 1051 messages::propertyValueNotInList(asyncResp->res, *reportingType, 1052 "MetricReportDefinitionType"); 1053 return; 1054 } 1055 } 1056 1057 uint64_t recurrenceInterval = std::numeric_limits<uint64_t>::max(); 1058 if (recurrenceIntervalStr) 1059 { 1060 std::optional<std::chrono::milliseconds> durationNum = 1061 time_utils::fromDurationString(*recurrenceIntervalStr); 1062 if (!durationNum || durationNum->count() < 0) 1063 { 1064 messages::propertyValueIncorrect( 1065 asyncResp->res, "RecurrenceInterval", *recurrenceIntervalStr); 1066 return; 1067 } 1068 1069 recurrenceInterval = static_cast<uint64_t>(durationNum->count()); 1070 } 1071 1072 crow::connections::systemBus->async_method_call( 1073 [asyncResp, id = std::string(id)](const boost::system::error_code& ec, 1074 const sdbusplus::message_t& msg) { 1075 afterSetReportingProperties(asyncResp, id, ec, msg); 1076 }, 1077 "xyz.openbmc_project.Telemetry", getDbusReportPath(id), 1078 "xyz.openbmc_project.Telemetry.Report", "SetReportingProperties", 1079 dbusReportingType, recurrenceInterval); 1080 } 1081 1082 inline void afterSetReportUpdates( 1083 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id, 1084 const boost::system::error_code& ec, const sdbusplus::message_t& msg) 1085 { 1086 if (!ec) 1087 { 1088 asyncResp->res.result(boost::beast::http::status::no_content); 1089 return; 1090 } 1091 if (ec == boost::system::errc::invalid_argument) 1092 { 1093 const sd_bus_error* errorMessage = msg.get_error(); 1094 if (errorMessage != nullptr) 1095 { 1096 for (const auto& arg : {"Id", "ReportUpdates"}) 1097 { 1098 if (!handleParamError(asyncResp->res, errorMessage->message, 1099 arg)) 1100 { 1101 return; 1102 } 1103 } 1104 } 1105 } 1106 if (!verifyCommonErrors(asyncResp->res, id, ec)) 1107 { 1108 return; 1109 } 1110 } 1111 1112 inline void 1113 setReportUpdates(const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1114 std::string_view id, const std::string& reportUpdates) 1115 { 1116 std::string dbusReportUpdates = toDbusReportUpdates(reportUpdates); 1117 if (dbusReportUpdates.empty()) 1118 { 1119 messages::propertyValueNotInList(asyncResp->res, reportUpdates, 1120 "ReportUpdates"); 1121 return; 1122 } 1123 crow::connections::systemBus->async_method_call( 1124 [asyncResp, id = std::string(id)](const boost::system::error_code& ec, 1125 const sdbusplus::message_t& msg) { 1126 afterSetReportUpdates(asyncResp, id, ec, msg); 1127 }, 1128 "xyz.openbmc_project.Telemetry", getDbusReportPath(id), 1129 "org.freedesktop.DBus.Properties", "Set", 1130 "xyz.openbmc_project.Telemetry.Report", "ReportUpdates", 1131 dbus::utility::DbusVariantType{dbusReportUpdates}); 1132 } 1133 1134 inline void afterSetReportActions( 1135 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id, 1136 const boost::system::error_code& ec, const sdbusplus::message_t& msg) 1137 { 1138 if (ec == boost::system::errc::invalid_argument) 1139 { 1140 const sd_bus_error* errorMessage = msg.get_error(); 1141 if (errorMessage != nullptr) 1142 { 1143 for (const auto& arg : {"Id", "ReportActions"}) 1144 { 1145 if (!handleParamError(asyncResp->res, errorMessage->message, 1146 arg)) 1147 { 1148 return; 1149 } 1150 } 1151 } 1152 } 1153 1154 if (!verifyCommonErrors(asyncResp->res, id, ec)) 1155 { 1156 return; 1157 } 1158 1159 messages::internalError(asyncResp->res); 1160 } 1161 1162 inline void setReportActions( 1163 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id, 1164 const std::vector<std::string>& reportActions) 1165 { 1166 std::vector<std::string> dbusReportActions; 1167 if (!toDbusReportActions(asyncResp->res, reportActions, dbusReportActions)) 1168 { 1169 return; 1170 } 1171 1172 crow::connections::systemBus->async_method_call( 1173 [asyncResp, id = std::string(id)](const boost::system::error_code& ec, 1174 const sdbusplus::message_t& msg) { 1175 afterSetReportActions(asyncResp, id, ec, msg); 1176 }, 1177 "xyz.openbmc_project.Telemetry", getDbusReportPath(id), 1178 "org.freedesktop.DBus.Properties", "Set", 1179 "xyz.openbmc_project.Telemetry.Report", "ReportActions", 1180 dbus::utility::DbusVariantType{dbusReportActions}); 1181 } 1182 1183 inline void setReportMetrics( 1184 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id, 1185 std::vector<nlohmann::json::object_t>&& metrics) 1186 { 1187 sdbusplus::asio::getAllProperties( 1188 *crow::connections::systemBus, telemetry::service, 1189 telemetry::getDbusReportPath(id), telemetry::reportInterface, 1190 [asyncResp, id = std::string(id), redfishMetrics = std::move(metrics)]( 1191 boost::system::error_code ec, 1192 const dbus::utility::DBusPropertiesMap& properties) mutable { 1193 if (!verifyCommonErrors(asyncResp->res, id, ec)) 1194 { 1195 return; 1196 } 1197 1198 ReadingParameters readingParams; 1199 1200 const bool success = sdbusplus::unpackPropertiesNoThrow( 1201 dbus_utils::UnpackErrorPrinter(), properties, 1202 "ReadingParameters", readingParams); 1203 1204 if (!success) 1205 { 1206 messages::internalError(asyncResp->res); 1207 return; 1208 } 1209 1210 auto updateMetricsReq = 1211 std::make_shared<UpdateMetrics>(id, asyncResp); 1212 1213 boost::container::flat_set<std::pair<std::string, std::string>> 1214 chassisSensors; 1215 1216 size_t index = 0; 1217 for (nlohmann::json::object_t& metric : redfishMetrics) 1218 { 1219 AddReportArgs::MetricArgs metricArgs; 1220 std::vector< 1221 std::tuple<sdbusplus::message::object_path, std::string>> 1222 pathAndUri; 1223 1224 if (index < readingParams.size()) 1225 { 1226 const ReadingParameters::value_type& existing = 1227 readingParams[index]; 1228 1229 pathAndUri = std::get<0>(existing); 1230 metricArgs.collectionFunction = std::get<1>(existing); 1231 metricArgs.collectionTimeScope = std::get<2>(existing); 1232 metricArgs.collectionDuration = std::get<3>(existing); 1233 } 1234 1235 if (!getUserMetric(asyncResp->res, metric, metricArgs)) 1236 { 1237 return; 1238 } 1239 1240 std::optional<IncorrectMetricUri> error = 1241 getChassisSensorNode(metricArgs.uris, chassisSensors); 1242 1243 if (error) 1244 { 1245 messages::propertyValueIncorrect( 1246 asyncResp->res, error->uri, 1247 "MetricProperties/" + std::to_string(error->index)); 1248 return; 1249 } 1250 1251 updateMetricsReq->emplace(pathAndUri, metricArgs); 1252 index++; 1253 } 1254 1255 for (const auto& [chassis, sensorType] : chassisSensors) 1256 { 1257 retrieveUriToDbusMap( 1258 chassis, sensorType, 1259 [asyncResp, updateMetricsReq]( 1260 const boost::beast::http::status status, 1261 const std::map<std::string, std::string>& uriToDbus) { 1262 if (status != boost::beast::http::status::ok) 1263 { 1264 BMCWEB_LOG_ERROR( 1265 "Failed to retrieve URI to dbus sensors map with err {}", 1266 static_cast<unsigned>(status)); 1267 return; 1268 } 1269 updateMetricsReq->insert(uriToDbus); 1270 }); 1271 } 1272 }); 1273 } 1274 1275 inline void handleMetricReportDefinitionCollectionHead( 1276 App& app, const crow::Request& req, 1277 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1278 { 1279 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1280 { 1281 return; 1282 } 1283 asyncResp->res.addHeader( 1284 boost::beast::http::field::link, 1285 "</redfish/v1/JsonSchemas/MetricReportDefinitionCollection/MetricReportDefinitionCollection.json>; rel=describedby"); 1286 } 1287 1288 inline void handleMetricReportDefinitionCollectionGet( 1289 App& app, const crow::Request& req, 1290 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1291 { 1292 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1293 { 1294 return; 1295 } 1296 asyncResp->res.addHeader( 1297 boost::beast::http::field::link, 1298 "</redfish/v1/JsonSchemas/MetricReportDefinition/MetricReportDefinition.json>; rel=describedby"); 1299 1300 asyncResp->res.jsonValue["@odata.type"] = 1301 "#MetricReportDefinitionCollection." 1302 "MetricReportDefinitionCollection"; 1303 asyncResp->res.jsonValue["@odata.id"] = 1304 "/redfish/v1/TelemetryService/MetricReportDefinitions"; 1305 asyncResp->res.jsonValue["Name"] = "Metric Definition Collection"; 1306 constexpr std::array<std::string_view, 1> interfaces{ 1307 telemetry::reportInterface}; 1308 collection_util::getCollectionMembers( 1309 asyncResp, 1310 boost::urls::url( 1311 "/redfish/v1/TelemetryService/MetricReportDefinitions"), 1312 interfaces, "/xyz/openbmc_project/Telemetry/Reports/TelemetryService"); 1313 } 1314 1315 inline void handleReportPatch( 1316 App& app, const crow::Request& req, 1317 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id) 1318 { 1319 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1320 { 1321 return; 1322 } 1323 1324 std::optional<std::string> reportingTypeStr; 1325 std::optional<std::string> reportUpdatesStr; 1326 std::optional<bool> metricReportDefinitionEnabled; 1327 std::optional<std::vector<nlohmann::json::object_t>> metrics; 1328 std::optional<std::vector<std::string>> reportActionsStr; 1329 std::optional<std::string> scheduleDurationStr; 1330 1331 if (!json_util::readJsonPatch( 1332 req, asyncResp->res, "Metrics", metrics, 1333 "MetricReportDefinitionType", reportingTypeStr, "ReportUpdates", 1334 reportUpdatesStr, "ReportActions", reportActionsStr, 1335 "Schedule/RecurrenceInterval", scheduleDurationStr, 1336 "MetricReportDefinitionEnabled", metricReportDefinitionEnabled)) 1337 { 1338 return; 1339 } 1340 1341 if (metricReportDefinitionEnabled) 1342 { 1343 setReportEnabled(asyncResp, id, *metricReportDefinitionEnabled); 1344 } 1345 1346 if (reportUpdatesStr) 1347 { 1348 setReportUpdates(asyncResp, id, *reportUpdatesStr); 1349 } 1350 1351 if (reportActionsStr) 1352 { 1353 setReportActions(asyncResp, id, *reportActionsStr); 1354 } 1355 1356 if (reportingTypeStr || scheduleDurationStr) 1357 { 1358 setReportTypeAndInterval(asyncResp, id, reportingTypeStr, 1359 scheduleDurationStr); 1360 } 1361 1362 if (metrics) 1363 { 1364 setReportMetrics(asyncResp, id, std::move(*metrics)); 1365 } 1366 } 1367 1368 inline void handleReportDelete( 1369 App& app, const crow::Request& req, 1370 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, std::string_view id) 1371 { 1372 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1373 { 1374 return; 1375 } 1376 1377 const std::string reportPath = getDbusReportPath(id); 1378 1379 crow::connections::systemBus->async_method_call( 1380 [asyncResp, 1381 reportId = std::string(id)](const boost::system::error_code& ec) { 1382 if (!verifyCommonErrors(asyncResp->res, reportId, ec)) 1383 { 1384 return; 1385 } 1386 asyncResp->res.result(boost::beast::http::status::no_content); 1387 }, 1388 service, reportPath, "xyz.openbmc_project.Object.Delete", "Delete"); 1389 } 1390 } // namespace telemetry 1391 1392 inline void afterRetrieveUriToDbusMap( 1393 const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/, 1394 const std::shared_ptr<telemetry::AddReport>& addReportReq, 1395 const boost::beast::http::status status, 1396 const std::map<std::string, std::string>& uriToDbus) 1397 { 1398 if (status != boost::beast::http::status::ok) 1399 { 1400 BMCWEB_LOG_ERROR( 1401 "Failed to retrieve URI to dbus sensors map with err {}", 1402 static_cast<unsigned>(status)); 1403 return; 1404 } 1405 addReportReq->insert(uriToDbus); 1406 } 1407 1408 inline void handleMetricReportDefinitionsPost( 1409 App& app, const crow::Request& req, 1410 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) 1411 { 1412 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1413 { 1414 return; 1415 } 1416 1417 telemetry::AddReportArgs args; 1418 if (!telemetry::getUserParameters(asyncResp->res, req, args)) 1419 { 1420 return; 1421 } 1422 1423 boost::container::flat_set<std::pair<std::string, std::string>> 1424 chassisSensors; 1425 if (!telemetry::getChassisSensorNodeFromMetrics(asyncResp, args.metrics, 1426 chassisSensors)) 1427 { 1428 return; 1429 } 1430 1431 auto addReportReq = 1432 std::make_shared<telemetry::AddReport>(std::move(args), asyncResp); 1433 for (const auto& [chassis, sensorType] : chassisSensors) 1434 { 1435 retrieveUriToDbusMap(chassis, sensorType, 1436 std::bind_front(afterRetrieveUriToDbusMap, 1437 asyncResp, addReportReq)); 1438 } 1439 } 1440 1441 inline void 1442 handleMetricReportHead(App& app, const crow::Request& req, 1443 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 1444 const std::string& /*id*/) 1445 { 1446 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1447 { 1448 return; 1449 } 1450 asyncResp->res.addHeader( 1451 boost::beast::http::field::link, 1452 "</redfish/v1/JsonSchemas/MetricReport/MetricReport.json>; rel=describedby"); 1453 } 1454 1455 inline void handleMetricReportGet( 1456 App& app, const crow::Request& req, 1457 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 1458 { 1459 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1460 { 1461 return; 1462 } 1463 asyncResp->res.addHeader( 1464 boost::beast::http::field::link, 1465 "</redfish/v1/JsonSchemas/MetricReport/MetricReport.json>; rel=describedby"); 1466 1467 sdbusplus::asio::getAllProperties( 1468 *crow::connections::systemBus, telemetry::service, 1469 telemetry::getDbusReportPath(id), telemetry::reportInterface, 1470 [asyncResp, id](const boost::system::error_code& ec, 1471 const dbus::utility::DBusPropertiesMap& properties) { 1472 if (!redfish::telemetry::verifyCommonErrors(asyncResp->res, id, ec)) 1473 { 1474 return; 1475 } 1476 1477 telemetry::fillReportDefinition(asyncResp, id, properties); 1478 }); 1479 } 1480 1481 inline void handleMetricReportDelete( 1482 App& app, const crow::Request& req, 1483 const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, const std::string& id) 1484 1485 { 1486 if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 1487 { 1488 return; 1489 } 1490 1491 const std::string reportPath = telemetry::getDbusReportPath(id); 1492 1493 crow::connections::systemBus->async_method_call( 1494 [asyncResp, id](const boost::system::error_code& ec) { 1495 /* 1496 * boost::system::errc and std::errc are missing value 1497 * for EBADR error that is defined in Linux. 1498 */ 1499 if (ec.value() == EBADR) 1500 { 1501 messages::resourceNotFound(asyncResp->res, 1502 "MetricReportDefinition", id); 1503 return; 1504 } 1505 1506 if (ec) 1507 { 1508 BMCWEB_LOG_ERROR("respHandler DBus error {}", ec); 1509 messages::internalError(asyncResp->res); 1510 return; 1511 } 1512 1513 asyncResp->res.result(boost::beast::http::status::no_content); 1514 }, 1515 telemetry::service, reportPath, "xyz.openbmc_project.Object.Delete", 1516 "Delete"); 1517 } 1518 1519 inline void requestRoutesMetricReportDefinitionCollection(App& app) 1520 { 1521 BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/") 1522 .privileges(redfish::privileges::headMetricReportDefinitionCollection) 1523 .methods(boost::beast::http::verb::head)(std::bind_front( 1524 telemetry::handleMetricReportDefinitionCollectionHead, 1525 std::ref(app))); 1526 1527 BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/") 1528 .privileges(redfish::privileges::getMetricReportDefinitionCollection) 1529 .methods(boost::beast::http::verb::get)(std::bind_front( 1530 telemetry::handleMetricReportDefinitionCollectionGet, 1531 std::ref(app))); 1532 1533 BMCWEB_ROUTE(app, "/redfish/v1/TelemetryService/MetricReportDefinitions/") 1534 .privileges(redfish::privileges::postMetricReportDefinitionCollection) 1535 .methods(boost::beast::http::verb::post)( 1536 std::bind_front(handleMetricReportDefinitionsPost, std::ref(app))); 1537 } 1538 1539 inline void requestRoutesMetricReportDefinition(App& app) 1540 { 1541 BMCWEB_ROUTE(app, 1542 "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/") 1543 .privileges(redfish::privileges::getMetricReportDefinition) 1544 .methods(boost::beast::http::verb::head)( 1545 std::bind_front(handleMetricReportHead, std::ref(app))); 1546 1547 BMCWEB_ROUTE(app, 1548 "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/") 1549 .privileges(redfish::privileges::getMetricReportDefinition) 1550 .methods(boost::beast::http::verb::get)( 1551 std::bind_front(handleMetricReportGet, std::ref(app))); 1552 1553 BMCWEB_ROUTE(app, 1554 "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/") 1555 .privileges(redfish::privileges::deleteMetricReportDefinition) 1556 .methods(boost::beast::http::verb::delete_)( 1557 std::bind_front(handleMetricReportDelete, std::ref(app))); 1558 1559 BMCWEB_ROUTE(app, 1560 "/redfish/v1/TelemetryService/MetricReportDefinitions/<str>/") 1561 .privileges(redfish::privileges::patchMetricReportDefinition) 1562 .methods(boost::beast::http::verb::patch)( 1563 std::bind_front(telemetry::handleReportPatch, std::ref(app))); 1564 } 1565 } // namespace redfish 1566