140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0 240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors 340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2020 Intel Corporation 4e5aaf047SAppaRao Puli #pragma once 53ccb3adbSEd Tanous #include "app.hpp" 6d7857201SEd Tanous #include "async_resp.hpp" 7d7857201SEd Tanous #include "dbus_utility.hpp" 8d7857201SEd Tanous #include "error_messages.hpp" 9b52664e2SAppaRao Puli #include "event_service_manager.hpp" 10d7857201SEd Tanous #include "event_service_store.hpp" 11d7857201SEd Tanous #include "generated/enums/event_destination.hpp" 123ccb3adbSEd Tanous #include "http/utility.hpp" 13d7857201SEd Tanous #include "http_request.hpp" 149838eb20SEd Tanous #include "io_context_singleton.hpp" 153ccb3adbSEd Tanous #include "logging.hpp" 163ccb3adbSEd Tanous #include "query.hpp" 17d109e2b6SAlexander Hansen #include "registries.hpp" 183ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 19d109e2b6SAlexander Hansen #include "registries_selector.hpp" 203d30708fSChicago Duan #include "snmp_trap_event_clients.hpp" 21d7857201SEd Tanous #include "subscription.hpp" 22d109e2b6SAlexander Hansen #include "utils/json_utils.hpp" 23e5aaf047SAppaRao Puli 24d7857201SEd Tanous #include <asm-generic/errno.h> 25ed398213SEd Tanous 26d7857201SEd Tanous #include <boost/beast/http/fields.hpp> 27d7857201SEd Tanous #include <boost/beast/http/status.hpp> 28d7857201SEd Tanous #include <boost/beast/http/verb.hpp> 29d7857201SEd Tanous #include <boost/system/error_code.hpp> 30d7857201SEd Tanous #include <boost/system/result.hpp> 31d7857201SEd Tanous #include <boost/url/format.hpp> 32d7857201SEd Tanous #include <boost/url/parse.hpp> 33d7857201SEd Tanous #include <boost/url/url.hpp> 34d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp> 35d7857201SEd Tanous 36d7857201SEd Tanous #include <algorithm> 37d7857201SEd Tanous #include <array> 38d7857201SEd Tanous #include <cerrno> 39d7857201SEd Tanous #include <cstddef> 40d7857201SEd Tanous #include <cstdint> 413d30708fSChicago Duan #include <memory> 425064a25bSMyung Bae #include <optional> 433544d2a7SEd Tanous #include <ranges> 441e270c5fSPatrick Williams #include <span> 453d30708fSChicago Duan #include <string> 46d7857201SEd Tanous #include <utility> 47a14c9113SEd Tanous #include <vector> 481e270c5fSPatrick Williams 49e5aaf047SAppaRao Puli namespace redfish 50e5aaf047SAppaRao Puli { 51e5aaf047SAppaRao Puli 52156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 53156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 54fb546105SMyung Bae static constexpr const std::array<const char*, 4> supportedRegPrefixes = { 55fb546105SMyung Bae "Base", "OpenBMC", "TaskEvent", "HeartbeatEvent"}; 56e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 57e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 58e5aaf047SAppaRao Puli 59fb546105SMyung Bae static constexpr const std::array<const char*, 2> supportedResourceTypes = { 60fb546105SMyung Bae "Task", "Heartbeat"}; 61e56f254cSSunitha Harish 627e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app) 63e5aaf047SAppaRao Puli { 647e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 65ed398213SEd Tanous .privileges(redfish::privileges::getEventService) 66bd79bce8SPatrick Williams .methods( 67bd79bce8SPatrick Williams boost::beast::http::verb:: 68bd79bce8SPatrick Williams get)([&app]( 69bd79bce8SPatrick Williams const crow::Request& req, 70002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 713ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 7245ca1b86SEd Tanous { 7345ca1b86SEd Tanous return; 7445ca1b86SEd Tanous } 751476687dSEd Tanous 761476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService"; 771476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 781476687dSEd Tanous "#EventService.v1_5_0.EventService"; 791476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "EventService"; 801476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Event Service"; 815e44e3d8SAppaRao Puli asyncResp->res.jsonValue["ServerSentEventUri"] = 825e44e3d8SAppaRao Puli "/redfish/v1/EventService/SSE"; 835e44e3d8SAppaRao Puli 841476687dSEd Tanous asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] = 851476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 86bd79bce8SPatrick Williams asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"] 87bd79bce8SPatrick Williams ["target"] = 881476687dSEd Tanous "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"; 89e5aaf047SAppaRao Puli 9028afb49cSJunLin Chen const persistent_data::EventServiceConfig eventServiceConfig = 9128afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 9228afb49cSJunLin Chen .getEventServiceConfig(); 937d1cc387SAppaRao Puli 947d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 9528afb49cSJunLin Chen (eventServiceConfig.enabled ? "Enabled" : "Disabled"); 96bd79bce8SPatrick Williams asyncResp->res.jsonValue["ServiceEnabled"] = 97bd79bce8SPatrick Williams eventServiceConfig.enabled; 987e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 9928afb49cSJunLin Chen eventServiceConfig.retryAttempts; 100e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 10128afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval; 102bd79bce8SPatrick Williams asyncResp->res.jsonValue["EventFormatTypes"] = 103bd79bce8SPatrick Williams supportedEvtFormatTypes; 1040fda0f12SGeorge Liu asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 1050fda0f12SGeorge Liu asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 10607941a88SAyushi Smriti 107613dabeaSEd Tanous nlohmann::json::object_t supportedSSEFilters; 108613dabeaSEd Tanous supportedSSEFilters["EventFormatType"] = true; 109613dabeaSEd Tanous supportedSSEFilters["MessageId"] = true; 110613dabeaSEd Tanous supportedSSEFilters["MetricReportDefinition"] = true; 111613dabeaSEd Tanous supportedSSEFilters["RegistryPrefix"] = true; 112613dabeaSEd Tanous supportedSSEFilters["OriginResource"] = false; 113613dabeaSEd Tanous supportedSSEFilters["ResourceType"] = false; 11407941a88SAyushi Smriti 11507941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 116613dabeaSEd Tanous std::move(supportedSSEFilters); 1177e860f15SJohn Edward Broadbent }); 118e5aaf047SAppaRao Puli 1197e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 120ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 1217e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 12245ca1b86SEd Tanous [&app](const crow::Request& req, 12345ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1243ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 125e5aaf047SAppaRao Puli { 12645ca1b86SEd Tanous return; 12745ca1b86SEd Tanous } 128e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 129e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 130e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 131afc474aeSMyung Bae if (!json_util::readJsonPatch( // 132afc474aeSMyung Bae req, asyncResp->res, // 133afc474aeSMyung Bae "DeliveryRetryAttempts", retryAttemps, // 134afc474aeSMyung Bae "DeliveryRetryIntervalSeconds", retryInterval, // 135afc474aeSMyung Bae "ServiceEnabled", serviceEnabled // 136afc474aeSMyung Bae )) 137e5aaf047SAppaRao Puli { 138e5aaf047SAppaRao Puli return; 139e5aaf047SAppaRao Puli } 140e5aaf047SAppaRao Puli 14128afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 14228afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 14328afb49cSJunLin Chen .getEventServiceConfig(); 1447d1cc387SAppaRao Puli 145e5aaf047SAppaRao Puli if (serviceEnabled) 146e5aaf047SAppaRao Puli { 14728afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 148e5aaf047SAppaRao Puli } 149e5aaf047SAppaRao Puli 150e5aaf047SAppaRao Puli if (retryAttemps) 151e5aaf047SAppaRao Puli { 152e5aaf047SAppaRao Puli // Supported range [1-3] 153e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 154e5aaf047SAppaRao Puli { 155e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 156e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 157e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 158e5aaf047SAppaRao Puli } 159e5aaf047SAppaRao Puli else 160e5aaf047SAppaRao Puli { 16128afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 162e5aaf047SAppaRao Puli } 163e5aaf047SAppaRao Puli } 164e5aaf047SAppaRao Puli 165e5aaf047SAppaRao Puli if (retryInterval) 166e5aaf047SAppaRao Puli { 16733a32b34SGunnar Mills // Supported range [5 - 180] 16833a32b34SGunnar Mills if ((*retryInterval < 5) || (*retryInterval > 180)) 169e5aaf047SAppaRao Puli { 170e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 171e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 17233a32b34SGunnar Mills "DeliveryRetryIntervalSeconds", "[5-180]"); 173e5aaf047SAppaRao Puli } 174e5aaf047SAppaRao Puli else 175e5aaf047SAppaRao Puli { 176bd79bce8SPatrick Williams eventServiceConfig.retryTimeoutInterval = 177bd79bce8SPatrick Williams *retryInterval; 178e5aaf047SAppaRao Puli } 179e5aaf047SAppaRao Puli } 180e5aaf047SAppaRao Puli 1817d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 18228afb49cSJunLin Chen eventServiceConfig); 1837e860f15SJohn Edward Broadbent }); 1840b4bdd93SAppaRao Puli } 1850b4bdd93SAppaRao Puli 1867e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1870b4bdd93SAppaRao Puli { 1887e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1897e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 190ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1917e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 19245ca1b86SEd Tanous [&app](const crow::Request& req, 1937e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1943ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 19545ca1b86SEd Tanous { 19645ca1b86SEd Tanous return; 19745ca1b86SEd Tanous } 19881ee0e74SChandramohan Harkude 1994a19a7b5SEd Tanous // From the Redfish spec on EventId 2004a19a7b5SEd Tanous // A service can ignore this value and replace it with its own. 2014a19a7b5SEd Tanous // note that this parameter is intentionally ignored 2024a19a7b5SEd Tanous 2034a19a7b5SEd Tanous std::optional<std::string> eventId; 20481ee0e74SChandramohan Harkude TestEvent testEvent; 20581ee0e74SChandramohan Harkude // clang-format off 20681ee0e74SChandramohan Harkude if (!json_util::readJsonAction( 20781ee0e74SChandramohan Harkude req, asyncResp->res, 20881ee0e74SChandramohan Harkude "EventGroupId", testEvent.eventGroupId, 2094a19a7b5SEd Tanous "EventId", eventId, 21081ee0e74SChandramohan Harkude "EventTimestamp", testEvent.eventTimestamp, 21181ee0e74SChandramohan Harkude "Message", testEvent.message, 21281ee0e74SChandramohan Harkude "MessageArgs", testEvent.messageArgs, 21381ee0e74SChandramohan Harkude "MessageId", testEvent.messageId, 21481ee0e74SChandramohan Harkude "OriginOfCondition", testEvent.originOfCondition, 21581ee0e74SChandramohan Harkude "Resolution", testEvent.resolution, 21681ee0e74SChandramohan Harkude "Severity", testEvent.severity)) 21781ee0e74SChandramohan Harkude { 21881ee0e74SChandramohan Harkude return; 21981ee0e74SChandramohan Harkude } 22081ee0e74SChandramohan Harkude // clang-format on 22181ee0e74SChandramohan Harkude 22281ee0e74SChandramohan Harkude if (!EventServiceManager::getInstance().sendTestEventLog( 22381ee0e74SChandramohan Harkude testEvent)) 2246ba8c82eSsunharis_in { 2256ba8c82eSsunharis_in messages::serviceDisabled(asyncResp->res, 2266ba8c82eSsunharis_in "/redfish/v1/EventService/"); 2276ba8c82eSsunharis_in return; 2286ba8c82eSsunharis_in } 2298d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 2307e860f15SJohn Edward Broadbent }); 231e5aaf047SAppaRao Puli } 232e5aaf047SAppaRao Puli 2333d30708fSChicago Duan inline void doSubscriptionCollection( 234e81de512SEd Tanous const boost::system::error_code& ec, 2353d30708fSChicago Duan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2363d30708fSChicago Duan const dbus::utility::ManagedObjectType& resp) 2373d30708fSChicago Duan { 2383d30708fSChicago Duan if (ec) 2393d30708fSChicago Duan { 2401306101eSEd Tanous if (ec.value() == EBADR || ec.value() == EHOSTUNREACH) 2413d30708fSChicago Duan { 2423d30708fSChicago Duan // This is an optional process so just return if it isn't there 2433d30708fSChicago Duan return; 2443d30708fSChicago Duan } 2453d30708fSChicago Duan 24662598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec); 2473d30708fSChicago Duan messages::internalError(asyncResp->res); 2483d30708fSChicago Duan return; 2493d30708fSChicago Duan } 2503d30708fSChicago Duan nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 2513d30708fSChicago Duan for (const auto& objpath : resp) 2523d30708fSChicago Duan { 2533d30708fSChicago Duan sdbusplus::message::object_path path(objpath.first); 2543d30708fSChicago Duan const std::string snmpId = path.filename(); 2553d30708fSChicago Duan if (snmpId.empty()) 2563d30708fSChicago Duan { 25762598e31SEd Tanous BMCWEB_LOG_ERROR("The SNMP client ID is wrong"); 2583d30708fSChicago Duan messages::internalError(asyncResp->res); 2593d30708fSChicago Duan return; 2603d30708fSChicago Duan } 2613d30708fSChicago Duan 2623d30708fSChicago Duan getSnmpSubscriptionList(asyncResp, snmpId, memberArray); 2633d30708fSChicago Duan } 2643d30708fSChicago Duan } 2653d30708fSChicago Duan 2667e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 267e5aaf047SAppaRao Puli { 2681ebe3e41SGayathri Leburu BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 269ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 2707e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 27145ca1b86SEd Tanous [&app](const crow::Request& req, 2727e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2733ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 27445ca1b86SEd Tanous { 27545ca1b86SEd Tanous return; 27645ca1b86SEd Tanous } 2771476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 2781476687dSEd Tanous "#EventDestinationCollection.EventDestinationCollection"; 2791476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2801476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 281bd79bce8SPatrick Williams asyncResp->res.jsonValue["Name"] = 282bd79bce8SPatrick Williams "Event Destination Collections"; 283e5aaf047SAppaRao Puli 284bd79bce8SPatrick Williams nlohmann::json& memberArray = 285bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members"]; 286e5aaf047SAppaRao Puli 287b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 288b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 289b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 290bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members@odata.count"] = 291bd79bce8SPatrick Williams subscripIds.size(); 292b52664e2SAppaRao Puli 293b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 294e5aaf047SAppaRao Puli { 2951476687dSEd Tanous nlohmann::json::object_t member; 2963d30708fSChicago Duan member["@odata.id"] = boost::urls::format( 2973d30708fSChicago Duan "/redfish/v1/EventService/Subscriptions/{}" + id); 298b2ba3072SPatrick Williams memberArray.emplace_back(std::move(member)); 299e5aaf047SAppaRao Puli } 300*177612aaSEd Tanous dbus::utility::async_method_call( 301*177612aaSEd Tanous asyncResp, 302e81de512SEd Tanous [asyncResp](const boost::system::error_code& ec, 3033d30708fSChicago Duan const dbus::utility::ManagedObjectType& resp) { 3043d30708fSChicago Duan doSubscriptionCollection(ec, asyncResp, resp); 3053d30708fSChicago Duan }, 3063d30708fSChicago Duan "xyz.openbmc_project.Network.SNMP", 3073d30708fSChicago Duan "/xyz/openbmc_project/network/snmp/manager", 3083d30708fSChicago Duan "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 3097e860f15SJohn Edward Broadbent }); 3103d30708fSChicago Duan 3117e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 3127eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 313bd79bce8SPatrick Williams .methods( 314bd79bce8SPatrick Williams boost::beast::http::verb:: 315bd79bce8SPatrick Williams post)([&app]( 316bd79bce8SPatrick Williams const crow::Request& req, 3177e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 3183ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 31945ca1b86SEd Tanous { 32045ca1b86SEd Tanous return; 32145ca1b86SEd Tanous } 322fffb8c1fSEd Tanous if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 323fffb8c1fSEd Tanous maxNoOfSubscriptions) 324e5aaf047SAppaRao Puli { 325e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 326e5aaf047SAppaRao Puli return; 327e5aaf047SAppaRao Puli } 328e5aaf047SAppaRao Puli std::string destUrl; 329e5aaf047SAppaRao Puli std::string protocol; 33019bb362bSEd Tanous std::optional<bool> verifyCertificate; 331e5aaf047SAppaRao Puli std::optional<std::string> context; 332e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 33323a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 334e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 3355064a25bSMyung Bae std::optional<bool> sendHeartbeat; 3365064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 337e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 338e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 339a14c9113SEd Tanous std::optional<std::vector<std::string>> originResources; 340e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 34178d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 34278d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray; 343e5aaf047SAppaRao Puli 344afc474aeSMyung Bae if (!json_util::readJsonPatch( // 345afc474aeSMyung Bae req, asyncResp->res, // 346afc474aeSMyung Bae "Context", context, // 347afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 348afc474aeSMyung Bae "Destination", destUrl, // 349afc474aeSMyung Bae "EventFormatType", eventFormatType2, // 3505064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 351afc474aeSMyung Bae "HttpHeaders", headers, // 352afc474aeSMyung Bae "MessageIds", msgIds, // 353afc474aeSMyung Bae "MetricReportDefinitions", mrdJsonArray, // 354afc474aeSMyung Bae "OriginResources", originResources, // 355afc474aeSMyung Bae "Protocol", protocol, // 356afc474aeSMyung Bae "RegistryPrefixes", regPrefixes, // 357afc474aeSMyung Bae "ResourceTypes", resTypes, // 3585064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 359afc474aeSMyung Bae "SubscriptionType", subscriptionType, // 360afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 3614b712a29SEd Tanous )) 362e5aaf047SAppaRao Puli { 363e5aaf047SAppaRao Puli return; 364e5aaf047SAppaRao Puli } 3654b712a29SEd Tanous // clang-format on 366e5aaf047SAppaRao Puli 367600af5f1SAppaRao Puli // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers 368600af5f1SAppaRao Puli static constexpr const uint16_t maxDestinationSize = 2000; 369600af5f1SAppaRao Puli if (destUrl.size() > maxDestinationSize) 370600af5f1SAppaRao Puli { 371600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Destination", 372600af5f1SAppaRao Puli maxDestinationSize); 373600af5f1SAppaRao Puli return; 374600af5f1SAppaRao Puli } 375600af5f1SAppaRao Puli 376dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 377dd28ba82SAppaRao Puli { 37826f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 379dd28ba82SAppaRao Puli { 380bd79bce8SPatrick Williams messages::propertyValueConflict( 381bd79bce8SPatrick Williams asyncResp->res, "MessageIds", "RegistryPrefixes"); 382dd28ba82SAppaRao Puli return; 383dd28ba82SAppaRao Puli } 384dd28ba82SAppaRao Puli } 385dd28ba82SAppaRao Puli 3866fd29553SEd Tanous boost::system::result<boost::urls::url> url = 387a716aa74SEd Tanous boost::urls::parse_absolute_uri(destUrl); 388a716aa74SEd Tanous if (!url) 389e5aaf047SAppaRao Puli { 390bd79bce8SPatrick Williams BMCWEB_LOG_WARNING( 391bd79bce8SPatrick Williams "Failed to validate and split destination url"); 392e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 393e5aaf047SAppaRao Puli "Destination"); 394e5aaf047SAppaRao Puli return; 395e5aaf047SAppaRao Puli } 396a716aa74SEd Tanous url->normalize(); 397b07942e3SGeorge Liu 398b07942e3SGeorge Liu // port_number returns zero if it is not a valid representable port 399b07942e3SGeorge Liu if (url->has_port() && url->port_number() == 0) 400b07942e3SGeorge Liu { 401b07942e3SGeorge Liu BMCWEB_LOG_WARNING("{} is an invalid port in destination url", 402b07942e3SGeorge Liu url->port()); 403b07942e3SGeorge Liu messages::propertyValueFormatError(asyncResp->res, destUrl, 404b07942e3SGeorge Liu "Destination"); 405b07942e3SGeorge Liu return; 406b07942e3SGeorge Liu } 407b07942e3SGeorge Liu 408a716aa74SEd Tanous crow::utility::setProtocolDefaults(*url, protocol); 409a716aa74SEd Tanous crow::utility::setPortDefaults(*url); 410a716aa74SEd Tanous 411a716aa74SEd Tanous if (url->path().empty()) 412a716aa74SEd Tanous { 413a716aa74SEd Tanous url->set_path("/"); 414a716aa74SEd Tanous } 415a716aa74SEd Tanous 416a716aa74SEd Tanous if (url->has_userinfo()) 417a716aa74SEd Tanous { 418a716aa74SEd Tanous messages::propertyValueFormatError(asyncResp->res, destUrl, 419a716aa74SEd Tanous "Destination"); 420a716aa74SEd Tanous return; 421a716aa74SEd Tanous } 422b52664e2SAppaRao Puli 4233d30708fSChicago Duan if (protocol == "SNMPv2c") 4243d30708fSChicago Duan { 4253d30708fSChicago Duan if (context) 4263d30708fSChicago Duan { 4273d30708fSChicago Duan messages::propertyValueConflict(asyncResp->res, "Context", 4283d30708fSChicago Duan "Protocol"); 4293d30708fSChicago Duan return; 4303d30708fSChicago Duan } 4313d30708fSChicago Duan if (eventFormatType2) 4323d30708fSChicago Duan { 433bd79bce8SPatrick Williams messages::propertyValueConflict( 434bd79bce8SPatrick Williams asyncResp->res, "EventFormatType", "Protocol"); 4353d30708fSChicago Duan return; 4363d30708fSChicago Duan } 4373d30708fSChicago Duan if (retryPolicy) 4383d30708fSChicago Duan { 439bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 440bd79bce8SPatrick Williams "RetryPolicy", "Protocol"); 4413d30708fSChicago Duan return; 4423d30708fSChicago Duan } 4435064a25bSMyung Bae if (sendHeartbeat) 4445064a25bSMyung Bae { 4455064a25bSMyung Bae messages::propertyValueConflict( 4465064a25bSMyung Bae asyncResp->res, "SendHeartbeat", "Protocol"); 4475064a25bSMyung Bae return; 4485064a25bSMyung Bae } 4495064a25bSMyung Bae if (hbIntervalMinutes) 4505064a25bSMyung Bae { 4515064a25bSMyung Bae messages::propertyValueConflict( 4525064a25bSMyung Bae asyncResp->res, "HeartbeatIntervalMinutes", "Protocol"); 4535064a25bSMyung Bae return; 4545064a25bSMyung Bae } 4553d30708fSChicago Duan if (msgIds) 4563d30708fSChicago Duan { 457bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 458bd79bce8SPatrick Williams "MessageIds", "Protocol"); 4593d30708fSChicago Duan return; 4603d30708fSChicago Duan } 4613d30708fSChicago Duan if (regPrefixes) 4623d30708fSChicago Duan { 463bd79bce8SPatrick Williams messages::propertyValueConflict( 464bd79bce8SPatrick Williams asyncResp->res, "RegistryPrefixes", "Protocol"); 4653d30708fSChicago Duan return; 4663d30708fSChicago Duan } 4673d30708fSChicago Duan if (resTypes) 4683d30708fSChicago Duan { 469bd79bce8SPatrick Williams messages::propertyValueConflict( 470bd79bce8SPatrick Williams asyncResp->res, "ResourceTypes", "Protocol"); 4713d30708fSChicago Duan return; 4723d30708fSChicago Duan } 4733d30708fSChicago Duan if (headers) 4743d30708fSChicago Duan { 475bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 476bd79bce8SPatrick Williams "HttpHeaders", "Protocol"); 4773d30708fSChicago Duan return; 4783d30708fSChicago Duan } 4793d30708fSChicago Duan if (mrdJsonArray) 4803d30708fSChicago Duan { 4813d30708fSChicago Duan messages::propertyValueConflict( 4823d30708fSChicago Duan asyncResp->res, "MetricReportDefinitions", "Protocol"); 4833d30708fSChicago Duan return; 4843d30708fSChicago Duan } 485a716aa74SEd Tanous if (url->scheme() != "snmp") 486a716aa74SEd Tanous { 487bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 488bd79bce8SPatrick Williams "Destination", "Protocol"); 4893d30708fSChicago Duan return; 4903d30708fSChicago Duan } 4913d30708fSChicago Duan 492a716aa74SEd Tanous addSnmpTrapClient(asyncResp, url->host_address(), 493a716aa74SEd Tanous url->port_number()); 494a716aa74SEd Tanous return; 495b52664e2SAppaRao Puli } 4963d30708fSChicago Duan 497a716aa74SEd Tanous std::shared_ptr<Subscription> subValue = 49821a94d5cSMyung Bae std::make_shared<Subscription>( 4995fe4ef35SMyung Bae std::make_shared<persistent_data::UserSubscription>(), *url, 5009838eb20SEd Tanous getIoContext()); 501e5aaf047SAppaRao Puli 502e5aaf047SAppaRao Puli if (subscriptionType) 503e5aaf047SAppaRao Puli { 504e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 505e5aaf047SAppaRao Puli { 506fffb8c1fSEd Tanous messages::propertyValueNotInList( 507fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 508e5aaf047SAppaRao Puli return; 509e5aaf047SAppaRao Puli } 5105fe4ef35SMyung Bae subValue->userSub->subscriptionType = *subscriptionType; 511e5aaf047SAppaRao Puli } 512e5aaf047SAppaRao Puli else 513e5aaf047SAppaRao Puli { 5144b712a29SEd Tanous // Default 5155fe4ef35SMyung Bae subValue->userSub->subscriptionType = "RedfishEvent"; 516e5aaf047SAppaRao Puli } 517e5aaf047SAppaRao Puli 518e5aaf047SAppaRao Puli if (protocol != "Redfish") 519e5aaf047SAppaRao Puli { 520e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 521e5aaf047SAppaRao Puli "Protocol"); 522e5aaf047SAppaRao Puli return; 523e5aaf047SAppaRao Puli } 5245fe4ef35SMyung Bae subValue->userSub->protocol = protocol; 525e5aaf047SAppaRao Puli 52619bb362bSEd Tanous if (verifyCertificate) 52719bb362bSEd Tanous { 5285fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 52919bb362bSEd Tanous } 53019bb362bSEd Tanous 53123a21a1cSEd Tanous if (eventFormatType2) 532e5aaf047SAppaRao Puli { 533bd79bce8SPatrick Williams if (std::ranges::find(supportedEvtFormatTypes, 534bd79bce8SPatrick Williams *eventFormatType2) == 5353544d2a7SEd Tanous supportedEvtFormatTypes.end()) 536e5aaf047SAppaRao Puli { 537fffb8c1fSEd Tanous messages::propertyValueNotInList( 538fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 539e5aaf047SAppaRao Puli return; 540e5aaf047SAppaRao Puli } 5415fe4ef35SMyung Bae subValue->userSub->eventFormatType = *eventFormatType2; 542e5aaf047SAppaRao Puli } 543e5aaf047SAppaRao Puli else 544e5aaf047SAppaRao Puli { 545e5aaf047SAppaRao Puli // If not specified, use default "Event" 5465fe4ef35SMyung Bae subValue->userSub->eventFormatType = "Event"; 547e5aaf047SAppaRao Puli } 548e5aaf047SAppaRao Puli 549e5aaf047SAppaRao Puli if (context) 550e5aaf047SAppaRao Puli { 5518ece0e45SEd Tanous // This value is selected arbitrarily. 552600af5f1SAppaRao Puli constexpr const size_t maxContextSize = 256; 553600af5f1SAppaRao Puli if (context->size() > maxContextSize) 554600af5f1SAppaRao Puli { 555600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Context", 556600af5f1SAppaRao Puli maxContextSize); 557600af5f1SAppaRao Puli return; 558600af5f1SAppaRao Puli } 5595fe4ef35SMyung Bae subValue->userSub->customText = *context; 560e5aaf047SAppaRao Puli } 561e5aaf047SAppaRao Puli 562e5aaf047SAppaRao Puli if (headers) 563e5aaf047SAppaRao Puli { 564600af5f1SAppaRao Puli size_t cumulativeLen = 0; 565600af5f1SAppaRao Puli 56678d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 567601c71aeSEd Tanous { 56878d4ec4fSEd Tanous for (const auto& item : headerChunk) 56978d4ec4fSEd Tanous { 57078d4ec4fSEd Tanous const std::string* value = 57178d4ec4fSEd Tanous item.second.get_ptr<const std::string*>(); 57278d4ec4fSEd Tanous if (value == nullptr) 57378d4ec4fSEd Tanous { 57478d4ec4fSEd Tanous messages::propertyValueFormatError( 57578d4ec4fSEd Tanous asyncResp->res, item.second, 57678d4ec4fSEd Tanous "HttpHeaders/" + item.first); 57778d4ec4fSEd Tanous return; 57878d4ec4fSEd Tanous } 57978d4ec4fSEd Tanous // Adding a new json value is the size of the key, + 58078d4ec4fSEd Tanous // the size of the value + 2 * 2 quotes for each, + 58178d4ec4fSEd Tanous // the colon and space between. example: 58278d4ec4fSEd Tanous // "key": "value" 58378d4ec4fSEd Tanous cumulativeLen += item.first.size() + value->size() + 6; 584600af5f1SAppaRao Puli // This value is selected to mirror http_connection.hpp 585600af5f1SAppaRao Puli constexpr const uint16_t maxHeaderSizeED = 8096; 586600af5f1SAppaRao Puli if (cumulativeLen > maxHeaderSizeED) 587600af5f1SAppaRao Puli { 58878d4ec4fSEd Tanous messages::arraySizeTooLong( 58978d4ec4fSEd Tanous asyncResp->res, "HttpHeaders", maxHeaderSizeED); 590600af5f1SAppaRao Puli return; 591600af5f1SAppaRao Puli } 5925fe4ef35SMyung Bae subValue->userSub->httpHeaders.set(item.first, *value); 593601c71aeSEd Tanous } 594601c71aeSEd Tanous } 595e5aaf047SAppaRao Puli } 596e5aaf047SAppaRao Puli 597e5aaf047SAppaRao Puli if (regPrefixes) 598e5aaf047SAppaRao Puli { 599e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 600e5aaf047SAppaRao Puli { 6013544d2a7SEd Tanous if (std::ranges::find(supportedRegPrefixes, it) == 6023544d2a7SEd Tanous supportedRegPrefixes.end()) 603e5aaf047SAppaRao Puli { 604fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 605fffb8c1fSEd Tanous "RegistryPrefixes"); 606e5aaf047SAppaRao Puli return; 607e5aaf047SAppaRao Puli } 608e5aaf047SAppaRao Puli } 6095fe4ef35SMyung Bae subValue->userSub->registryPrefixes = *regPrefixes; 610e5aaf047SAppaRao Puli } 611e5aaf047SAppaRao Puli 612a14c9113SEd Tanous if (originResources) 613a14c9113SEd Tanous { 6145fe4ef35SMyung Bae subValue->userSub->originResources = *originResources; 615a14c9113SEd Tanous } 616a14c9113SEd Tanous 617e56f254cSSunitha Harish if (resTypes) 618e56f254cSSunitha Harish { 619e56f254cSSunitha Harish for (const std::string& it : *resTypes) 620e56f254cSSunitha Harish { 6213544d2a7SEd Tanous if (std::ranges::find(supportedResourceTypes, it) == 6223544d2a7SEd Tanous supportedResourceTypes.end()) 623e56f254cSSunitha Harish { 624e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 625e56f254cSSunitha Harish "ResourceTypes"); 626e56f254cSSunitha Harish return; 627e56f254cSSunitha Harish } 628e56f254cSSunitha Harish } 6295fe4ef35SMyung Bae subValue->userSub->resourceTypes = *resTypes; 630e56f254cSSunitha Harish } 631e56f254cSSunitha Harish 632e5aaf047SAppaRao Puli if (msgIds) 633e5aaf047SAppaRao Puli { 634b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 635b304bd79SP Dheeraj Srujan Kumar 6367e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 6377e860f15SJohn Edward Broadbent // supported prefixes 6385fe4ef35SMyung Bae if (subValue->userSub->registryPrefixes.empty()) 639b304bd79SP Dheeraj Srujan Kumar { 640b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 641b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 642b304bd79SP Dheeraj Srujan Kumar } 643b304bd79SP Dheeraj Srujan Kumar else 644b304bd79SP Dheeraj Srujan Kumar { 6455fe4ef35SMyung Bae registryPrefix = subValue->userSub->registryPrefixes; 646b304bd79SP Dheeraj Srujan Kumar } 647b304bd79SP Dheeraj Srujan Kumar 648b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 649b304bd79SP Dheeraj Srujan Kumar { 650b304bd79SP Dheeraj Srujan Kumar bool validId = false; 651b304bd79SP Dheeraj Srujan Kumar 652b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 653b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 654b304bd79SP Dheeraj Srujan Kumar { 655fffb8c1fSEd Tanous const std::span<const redfish::registries::MessageEntry> 656fffb8c1fSEd Tanous registry = 657fffb8c1fSEd Tanous redfish::registries::getRegistryFromPrefix(it); 658b304bd79SP Dheeraj Srujan Kumar 6593544d2a7SEd Tanous if (std::ranges::any_of( 6603544d2a7SEd Tanous registry, 661fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 662fffb8c1fSEd Tanous messageEntry) { 66355f79e6fSEd Tanous return id == messageEntry.first; 664b304bd79SP Dheeraj Srujan Kumar })) 665b304bd79SP Dheeraj Srujan Kumar { 666b304bd79SP Dheeraj Srujan Kumar validId = true; 667b304bd79SP Dheeraj Srujan Kumar break; 668b304bd79SP Dheeraj Srujan Kumar } 669b304bd79SP Dheeraj Srujan Kumar } 670b304bd79SP Dheeraj Srujan Kumar 671b304bd79SP Dheeraj Srujan Kumar if (!validId) 672b304bd79SP Dheeraj Srujan Kumar { 673b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 674b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 675b304bd79SP Dheeraj Srujan Kumar return; 676b304bd79SP Dheeraj Srujan Kumar } 677b304bd79SP Dheeraj Srujan Kumar } 678b304bd79SP Dheeraj Srujan Kumar 6795fe4ef35SMyung Bae subValue->userSub->registryMsgIds = *msgIds; 680e5aaf047SAppaRao Puli } 681e5aaf047SAppaRao Puli 682e5aaf047SAppaRao Puli if (retryPolicy) 683e5aaf047SAppaRao Puli { 6843544d2a7SEd Tanous if (std::ranges::find(supportedRetryPolicies, *retryPolicy) == 6853544d2a7SEd Tanous supportedRetryPolicies.end()) 686e5aaf047SAppaRao Puli { 687bd79bce8SPatrick Williams messages::propertyValueNotInList( 688bd79bce8SPatrick Williams asyncResp->res, *retryPolicy, "DeliveryRetryPolicy"); 689e5aaf047SAppaRao Puli return; 690e5aaf047SAppaRao Puli } 6915fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 692e5aaf047SAppaRao Puli } 693e5aaf047SAppaRao Puli else 694e5aaf047SAppaRao Puli { 695e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 6965fe4ef35SMyung Bae subValue->userSub->retryPolicy = "TerminateAfterRetries"; 697e5aaf047SAppaRao Puli } 6985064a25bSMyung Bae if (sendHeartbeat) 6995064a25bSMyung Bae { 7005064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 7015064a25bSMyung Bae } 7025064a25bSMyung Bae if (hbIntervalMinutes) 7035064a25bSMyung Bae { 7045064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 7055064a25bSMyung Bae { 7065064a25bSMyung Bae messages::propertyValueOutOfRange( 7075064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 7085064a25bSMyung Bae "HeartbeatIntervalMinutes"); 7095064a25bSMyung Bae return; 7105064a25bSMyung Bae } 7115064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 7125064a25bSMyung Bae } 713e5aaf047SAppaRao Puli 714144b6318SAppaRao Puli if (mrdJsonArray) 715156d6b00SAppaRao Puli { 71678d4ec4fSEd Tanous for (nlohmann::json::object_t& mrdObj : *mrdJsonArray) 717144b6318SAppaRao Puli { 718144b6318SAppaRao Puli std::string mrdUri; 719ea2e6eecSWilly Tu 72078d4ec4fSEd Tanous if (!json_util::readJsonObject(mrdObj, asyncResp->res, 72178d4ec4fSEd Tanous "@odata.id", mrdUri)) 722ea2e6eecSWilly Tu 723144b6318SAppaRao Puli { 724144b6318SAppaRao Puli return; 725144b6318SAppaRao Puli } 7265fe4ef35SMyung Bae subValue->userSub->metricReportDefinitions.emplace_back( 7274b712a29SEd Tanous mrdUri); 728144b6318SAppaRao Puli } 729156d6b00SAppaRao Puli } 730156d6b00SAppaRao Puli 731b52664e2SAppaRao Puli std::string id = 732bd79bce8SPatrick Williams EventServiceManager::getInstance().addPushSubscription( 733bd79bce8SPatrick Williams subValue); 734b52664e2SAppaRao Puli if (id.empty()) 735e5aaf047SAppaRao Puli { 736e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 737e5aaf047SAppaRao Puli return; 738e5aaf047SAppaRao Puli } 739e5aaf047SAppaRao Puli 740e5aaf047SAppaRao Puli messages::created(asyncResp->res); 741e5aaf047SAppaRao Puli asyncResp->res.addHeader( 742e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 743fb546105SMyung Bae 744fb546105SMyung Bae // schedule a heartbeat 745fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 746fb546105SMyung Bae { 747fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 748fb546105SMyung Bae } 7497e860f15SJohn Edward Broadbent }); 750e5aaf047SAppaRao Puli } 751e5aaf047SAppaRao Puli 7527e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 753e5aaf047SAppaRao Puli { 7549d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 755ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 7567e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 75745ca1b86SEd Tanous [&app](const crow::Request& req, 7587e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7597e860f15SJohn Edward Broadbent const std::string& param) { 7603ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 76145ca1b86SEd Tanous { 76245ca1b86SEd Tanous return; 76345ca1b86SEd Tanous } 7643d30708fSChicago Duan 7653d30708fSChicago Duan if (param.starts_with("snmp")) 7663d30708fSChicago Duan { 7673d30708fSChicago Duan getSnmpTrapClient(asyncResp, param); 7683d30708fSChicago Duan return; 7693d30708fSChicago Duan } 7703d30708fSChicago Duan 771b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 7727e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 773b52664e2SAppaRao Puli if (subValue == nullptr) 774e5aaf047SAppaRao Puli { 775bd79bce8SPatrick Williams asyncResp->res.result( 776bd79bce8SPatrick Williams boost::beast::http::status::not_found); 777e5aaf047SAppaRao Puli return; 778e5aaf047SAppaRao Puli } 7797e860f15SJohn Edward Broadbent const std::string& id = param; 780e5aaf047SAppaRao Puli 7814b712a29SEd Tanous const persistent_data::UserSubscription& userSub = 7825fe4ef35SMyung Bae *subValue->userSub; 783e56f254cSSunitha Harish 7844b712a29SEd Tanous nlohmann::json& jVal = asyncResp->res.jsonValue; 7854b712a29SEd Tanous jVal["@odata.type"] = 7864b712a29SEd Tanous "#EventDestination.v1_14_1.EventDestination"; 7874b712a29SEd Tanous jVal["Protocol"] = 7884b712a29SEd Tanous event_destination::EventDestinationProtocol::Redfish; 7894b712a29SEd Tanous jVal["@odata.id"] = boost::urls::format( 7904b712a29SEd Tanous "/redfish/v1/EventService/Subscriptions/{}", id); 7914b712a29SEd Tanous jVal["Id"] = id; 7924b712a29SEd Tanous jVal["Name"] = "Event Destination " + id; 7934b712a29SEd Tanous jVal["Destination"] = userSub.destinationUrl; 7944b712a29SEd Tanous jVal["Context"] = userSub.customText; 7954b712a29SEd Tanous jVal["SubscriptionType"] = userSub.subscriptionType; 7964b712a29SEd Tanous jVal["HttpHeaders"] = nlohmann::json::array(); 7974b712a29SEd Tanous jVal["EventFormatType"] = userSub.eventFormatType; 7984b712a29SEd Tanous jVal["RegistryPrefixes"] = userSub.registryPrefixes; 7994b712a29SEd Tanous jVal["ResourceTypes"] = userSub.resourceTypes; 8004b712a29SEd Tanous 8014b712a29SEd Tanous jVal["MessageIds"] = userSub.registryMsgIds; 8024b712a29SEd Tanous jVal["DeliveryRetryPolicy"] = userSub.retryPolicy; 8035064a25bSMyung Bae jVal["SendHeartbeat"] = userSub.sendHeartbeat; 8045064a25bSMyung Bae jVal["HeartbeatIntervalMinutes"] = userSub.hbIntervalMinutes; 8054b712a29SEd Tanous jVal["VerifyCertificate"] = userSub.verifyCertificate; 806144b6318SAppaRao Puli 8071476687dSEd Tanous nlohmann::json::array_t mrdJsonArray; 8084b712a29SEd Tanous for (const auto& mdrUri : userSub.metricReportDefinitions) 809144b6318SAppaRao Puli { 8101476687dSEd Tanous nlohmann::json::object_t mdr; 8111476687dSEd Tanous mdr["@odata.id"] = mdrUri; 8121476687dSEd Tanous mrdJsonArray.emplace_back(std::move(mdr)); 813144b6318SAppaRao Puli } 8144b712a29SEd Tanous jVal["MetricReportDefinitions"] = mrdJsonArray; 8157e860f15SJohn Edward Broadbent }); 8169d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 817ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 818ed398213SEd Tanous // ConfigureSelf 8197eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 820ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 821432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 8227e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 82345ca1b86SEd Tanous [&app](const crow::Request& req, 8247e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8257e860f15SJohn Edward Broadbent const std::string& param) { 8263ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 82745ca1b86SEd Tanous { 82845ca1b86SEd Tanous return; 82945ca1b86SEd Tanous } 830b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 8317e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 832b52664e2SAppaRao Puli if (subValue == nullptr) 833e5aaf047SAppaRao Puli { 834bd79bce8SPatrick Williams asyncResp->res.result( 835bd79bce8SPatrick Williams boost::beast::http::status::not_found); 836e5aaf047SAppaRao Puli return; 837e5aaf047SAppaRao Puli } 838e5aaf047SAppaRao Puli 839e5aaf047SAppaRao Puli std::optional<std::string> context; 840e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 8415064a25bSMyung Bae std::optional<bool> sendHeartbeat; 8425064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 84319bb362bSEd Tanous std::optional<bool> verifyCertificate; 84478d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 845e5aaf047SAppaRao Puli 846afc474aeSMyung Bae if (!json_util::readJsonPatch( // 847afc474aeSMyung Bae req, asyncResp->res, // 848afc474aeSMyung Bae "Context", context, // 849afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 8505064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 851afc474aeSMyung Bae "HttpHeaders", headers, // 8525064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 853afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 854afc474aeSMyung Bae )) 855e5aaf047SAppaRao Puli { 856e5aaf047SAppaRao Puli return; 857e5aaf047SAppaRao Puli } 858e5aaf047SAppaRao Puli 859e5aaf047SAppaRao Puli if (context) 860e5aaf047SAppaRao Puli { 8615fe4ef35SMyung Bae subValue->userSub->customText = *context; 862e5aaf047SAppaRao Puli } 863e5aaf047SAppaRao Puli 864e5aaf047SAppaRao Puli if (headers) 865e5aaf047SAppaRao Puli { 866601c71aeSEd Tanous boost::beast::http::fields fields; 86778d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 868601c71aeSEd Tanous { 86978d4ec4fSEd Tanous for (const auto& it : headerChunk) 870601c71aeSEd Tanous { 871601c71aeSEd Tanous const std::string* value = 87278d4ec4fSEd Tanous it.second.get_ptr<const std::string*>(); 873601c71aeSEd Tanous if (value == nullptr) 874601c71aeSEd Tanous { 875601c71aeSEd Tanous messages::propertyValueFormatError( 87678d4ec4fSEd Tanous asyncResp->res, it.second, 87778d4ec4fSEd Tanous "HttpHeaders/" + it.first); 878601c71aeSEd Tanous return; 879601c71aeSEd Tanous } 88078d4ec4fSEd Tanous fields.set(it.first, *value); 881601c71aeSEd Tanous } 882601c71aeSEd Tanous } 8835fe4ef35SMyung Bae subValue->userSub->httpHeaders = std::move(fields); 884e5aaf047SAppaRao Puli } 885e5aaf047SAppaRao Puli 886e5aaf047SAppaRao Puli if (retryPolicy) 887e5aaf047SAppaRao Puli { 888bd79bce8SPatrick Williams if (std::ranges::find(supportedRetryPolicies, 889bd79bce8SPatrick Williams *retryPolicy) == 8903544d2a7SEd Tanous supportedRetryPolicies.end()) 891e5aaf047SAppaRao Puli { 892bd79bce8SPatrick Williams messages::propertyValueNotInList(asyncResp->res, 893bd79bce8SPatrick Williams *retryPolicy, 894e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 895e5aaf047SAppaRao Puli return; 896e5aaf047SAppaRao Puli } 8975fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 898e5aaf047SAppaRao Puli } 899e5aaf047SAppaRao Puli 9005064a25bSMyung Bae if (sendHeartbeat) 9015064a25bSMyung Bae { 9025064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 9035064a25bSMyung Bae } 9045064a25bSMyung Bae if (hbIntervalMinutes) 9055064a25bSMyung Bae { 9065064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 9075064a25bSMyung Bae { 9085064a25bSMyung Bae messages::propertyValueOutOfRange( 9095064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 9105064a25bSMyung Bae "HeartbeatIntervalMinutes"); 9115064a25bSMyung Bae return; 9125064a25bSMyung Bae } 9135064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 9145064a25bSMyung Bae } 9155064a25bSMyung Bae 916fb546105SMyung Bae if (hbIntervalMinutes || sendHeartbeat) 917fb546105SMyung Bae { 918fb546105SMyung Bae // if Heartbeat interval or send heart were changed, cancel 919fb546105SMyung Bae // the heartbeat timer if running and start a new heartbeat 920fb546105SMyung Bae // if needed 921fb546105SMyung Bae subValue->heartbeatParametersChanged(); 922fb546105SMyung Bae } 923fb546105SMyung Bae 92419bb362bSEd Tanous if (verifyCertificate) 92519bb362bSEd Tanous { 9265fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 92719bb362bSEd Tanous } 92819bb362bSEd Tanous 929b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 9307e860f15SJohn Edward Broadbent }); 9319d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 932ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 933ed398213SEd Tanous // ConfigureSelf 9347eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 935ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 936432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 9377e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 93845ca1b86SEd Tanous [&app](const crow::Request& req, 9397e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9407e860f15SJohn Edward Broadbent const std::string& param) { 9413ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 94245ca1b86SEd Tanous { 94345ca1b86SEd Tanous return; 94445ca1b86SEd Tanous } 9454b712a29SEd Tanous EventServiceManager& event = EventServiceManager::getInstance(); 9463d30708fSChicago Duan if (param.starts_with("snmp")) 9473d30708fSChicago Duan { 9483d30708fSChicago Duan deleteSnmpTrapClient(asyncResp, param); 9494b712a29SEd Tanous event.deleteSubscription(param); 9503d30708fSChicago Duan return; 9513d30708fSChicago Duan } 9523d30708fSChicago Duan 9534b712a29SEd Tanous if (!event.deleteSubscription(param)) 954e5aaf047SAppaRao Puli { 9554b712a29SEd Tanous messages::resourceNotFound(asyncResp->res, 9564b712a29SEd Tanous "EventDestination", param); 957e5aaf047SAppaRao Puli return; 958e5aaf047SAppaRao Puli } 9594b712a29SEd Tanous messages::success(asyncResp->res); 9607e860f15SJohn Edward Broadbent }); 961e5aaf047SAppaRao Puli } 962e5aaf047SAppaRao Puli 963e5aaf047SAppaRao Puli } // namespace redfish 964