1e5aaf047SAppaRao Puli /* 26be832e2SEd Tanous Copyright (c) 2020 Intel Corporation 36be832e2SEd Tanous 46be832e2SEd Tanous Licensed under the Apache License, Version 2.0 (the "License"); 56be832e2SEd Tanous you may not use this file except in compliance with the License. 66be832e2SEd Tanous You may obtain a copy of the License at 76be832e2SEd Tanous 86be832e2SEd Tanous http://www.apache.org/licenses/LICENSE-2.0 96be832e2SEd Tanous 106be832e2SEd Tanous Unless required by applicable law or agreed to in writing, software 116be832e2SEd Tanous distributed under the License is distributed on an "AS IS" BASIS, 126be832e2SEd Tanous WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 136be832e2SEd Tanous See the License for the specific language governing permissions and 146be832e2SEd Tanous limitations under the License. 15e5aaf047SAppaRao Puli */ 16e5aaf047SAppaRao Puli #pragma once 173ccb3adbSEd Tanous #include "app.hpp" 18b52664e2SAppaRao Puli #include "event_service_manager.hpp" 19539d8c6bSEd Tanous #include "generated/enums/event_service.hpp" 203ccb3adbSEd Tanous #include "http/utility.hpp" 213ccb3adbSEd Tanous #include "logging.hpp" 223ccb3adbSEd Tanous #include "query.hpp" 23d109e2b6SAlexander Hansen #include "registries.hpp" 243ccb3adbSEd Tanous #include "registries/privilege_registry.hpp" 25d109e2b6SAlexander Hansen #include "registries_selector.hpp" 263d30708fSChicago Duan #include "snmp_trap_event_clients.hpp" 27d109e2b6SAlexander Hansen #include "utils/json_utils.hpp" 28e5aaf047SAppaRao Puli 29601c71aeSEd Tanous #include <boost/beast/http/fields.hpp> 303d30708fSChicago Duan #include <boost/system/error_code.hpp> 31a716aa74SEd Tanous #include <boost/url/parse.hpp> 323d30708fSChicago Duan #include <sdbusplus/unpack_properties.hpp> 333d30708fSChicago Duan #include <utils/dbus_utils.hpp> 34ed398213SEd Tanous 353d30708fSChicago Duan #include <charconv> 363d30708fSChicago Duan #include <memory> 375064a25bSMyung Bae #include <optional> 383544d2a7SEd Tanous #include <ranges> 391e270c5fSPatrick Williams #include <span> 403d30708fSChicago Duan #include <string> 41a14c9113SEd Tanous #include <vector> 421e270c5fSPatrick Williams 43e5aaf047SAppaRao Puli namespace redfish 44e5aaf047SAppaRao Puli { 45e5aaf047SAppaRao Puli 46156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = { 47156d6b00SAppaRao Puli eventFormatType, metricReportFormatType}; 48*fb546105SMyung Bae static constexpr const std::array<const char*, 4> supportedRegPrefixes = { 49*fb546105SMyung Bae "Base", "OpenBMC", "TaskEvent", "HeartbeatEvent"}; 50e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 51e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 52e5aaf047SAppaRao Puli 53*fb546105SMyung Bae static constexpr const std::array<const char*, 2> supportedResourceTypes = { 54*fb546105SMyung Bae "Task", "Heartbeat"}; 55e56f254cSSunitha Harish 567e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app) 57e5aaf047SAppaRao Puli { 587e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 59ed398213SEd Tanous .privileges(redfish::privileges::getEventService) 60bd79bce8SPatrick Williams .methods( 61bd79bce8SPatrick Williams boost::beast::http::verb:: 62bd79bce8SPatrick Williams get)([&app]( 63bd79bce8SPatrick Williams const crow::Request& req, 64002d39b4SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 653ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 6645ca1b86SEd Tanous { 6745ca1b86SEd Tanous return; 6845ca1b86SEd Tanous } 691476687dSEd Tanous 701476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService"; 711476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 721476687dSEd Tanous "#EventService.v1_5_0.EventService"; 731476687dSEd Tanous asyncResp->res.jsonValue["Id"] = "EventService"; 741476687dSEd Tanous asyncResp->res.jsonValue["Name"] = "Event Service"; 755e44e3d8SAppaRao Puli asyncResp->res.jsonValue["ServerSentEventUri"] = 765e44e3d8SAppaRao Puli "/redfish/v1/EventService/SSE"; 775e44e3d8SAppaRao Puli 781476687dSEd Tanous asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] = 791476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 80bd79bce8SPatrick Williams asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"] 81bd79bce8SPatrick Williams ["target"] = 821476687dSEd Tanous "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"; 83e5aaf047SAppaRao Puli 8428afb49cSJunLin Chen const persistent_data::EventServiceConfig eventServiceConfig = 8528afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 8628afb49cSJunLin Chen .getEventServiceConfig(); 877d1cc387SAppaRao Puli 887d1cc387SAppaRao Puli asyncResp->res.jsonValue["Status"]["State"] = 8928afb49cSJunLin Chen (eventServiceConfig.enabled ? "Enabled" : "Disabled"); 90bd79bce8SPatrick Williams asyncResp->res.jsonValue["ServiceEnabled"] = 91bd79bce8SPatrick Williams eventServiceConfig.enabled; 927e860f15SJohn Edward Broadbent asyncResp->res.jsonValue["DeliveryRetryAttempts"] = 9328afb49cSJunLin Chen eventServiceConfig.retryAttempts; 94e5aaf047SAppaRao Puli asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] = 9528afb49cSJunLin Chen eventServiceConfig.retryTimeoutInterval; 96bd79bce8SPatrick Williams asyncResp->res.jsonValue["EventFormatTypes"] = 97bd79bce8SPatrick Williams supportedEvtFormatTypes; 980fda0f12SGeorge Liu asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes; 990fda0f12SGeorge Liu asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes; 10007941a88SAyushi Smriti 101613dabeaSEd Tanous nlohmann::json::object_t supportedSSEFilters; 102613dabeaSEd Tanous supportedSSEFilters["EventFormatType"] = true; 103613dabeaSEd Tanous supportedSSEFilters["MessageId"] = true; 104613dabeaSEd Tanous supportedSSEFilters["MetricReportDefinition"] = true; 105613dabeaSEd Tanous supportedSSEFilters["RegistryPrefix"] = true; 106613dabeaSEd Tanous supportedSSEFilters["OriginResource"] = false; 107613dabeaSEd Tanous supportedSSEFilters["ResourceType"] = false; 10807941a88SAyushi Smriti 10907941a88SAyushi Smriti asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] = 110613dabeaSEd Tanous std::move(supportedSSEFilters); 1117e860f15SJohn Edward Broadbent }); 112e5aaf047SAppaRao Puli 1137e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/") 114ed398213SEd Tanous .privileges(redfish::privileges::patchEventService) 1157e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 11645ca1b86SEd Tanous [&app](const crow::Request& req, 11745ca1b86SEd Tanous const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1183ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 119e5aaf047SAppaRao Puli { 12045ca1b86SEd Tanous return; 12145ca1b86SEd Tanous } 122e5aaf047SAppaRao Puli std::optional<bool> serviceEnabled; 123e5aaf047SAppaRao Puli std::optional<uint32_t> retryAttemps; 124e5aaf047SAppaRao Puli std::optional<uint32_t> retryInterval; 125afc474aeSMyung Bae if (!json_util::readJsonPatch( // 126afc474aeSMyung Bae req, asyncResp->res, // 127afc474aeSMyung Bae "DeliveryRetryAttempts", retryAttemps, // 128afc474aeSMyung Bae "DeliveryRetryIntervalSeconds", retryInterval, // 129afc474aeSMyung Bae "ServiceEnabled", serviceEnabled // 130afc474aeSMyung Bae )) 131e5aaf047SAppaRao Puli { 132e5aaf047SAppaRao Puli return; 133e5aaf047SAppaRao Puli } 134e5aaf047SAppaRao Puli 13528afb49cSJunLin Chen persistent_data::EventServiceConfig eventServiceConfig = 13628afb49cSJunLin Chen persistent_data::EventServiceStore::getInstance() 13728afb49cSJunLin Chen .getEventServiceConfig(); 1387d1cc387SAppaRao Puli 139e5aaf047SAppaRao Puli if (serviceEnabled) 140e5aaf047SAppaRao Puli { 14128afb49cSJunLin Chen eventServiceConfig.enabled = *serviceEnabled; 142e5aaf047SAppaRao Puli } 143e5aaf047SAppaRao Puli 144e5aaf047SAppaRao Puli if (retryAttemps) 145e5aaf047SAppaRao Puli { 146e5aaf047SAppaRao Puli // Supported range [1-3] 147e5aaf047SAppaRao Puli if ((*retryAttemps < 1) || (*retryAttemps > 3)) 148e5aaf047SAppaRao Puli { 149e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 150e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryAttemps), 151e5aaf047SAppaRao Puli "DeliveryRetryAttempts", "[1-3]"); 152e5aaf047SAppaRao Puli } 153e5aaf047SAppaRao Puli else 154e5aaf047SAppaRao Puli { 15528afb49cSJunLin Chen eventServiceConfig.retryAttempts = *retryAttemps; 156e5aaf047SAppaRao Puli } 157e5aaf047SAppaRao Puli } 158e5aaf047SAppaRao Puli 159e5aaf047SAppaRao Puli if (retryInterval) 160e5aaf047SAppaRao Puli { 16133a32b34SGunnar Mills // Supported range [5 - 180] 16233a32b34SGunnar Mills if ((*retryInterval < 5) || (*retryInterval > 180)) 163e5aaf047SAppaRao Puli { 164e5aaf047SAppaRao Puli messages::queryParameterOutOfRange( 165e5aaf047SAppaRao Puli asyncResp->res, std::to_string(*retryInterval), 16633a32b34SGunnar Mills "DeliveryRetryIntervalSeconds", "[5-180]"); 167e5aaf047SAppaRao Puli } 168e5aaf047SAppaRao Puli else 169e5aaf047SAppaRao Puli { 170bd79bce8SPatrick Williams eventServiceConfig.retryTimeoutInterval = 171bd79bce8SPatrick Williams *retryInterval; 172e5aaf047SAppaRao Puli } 173e5aaf047SAppaRao Puli } 174e5aaf047SAppaRao Puli 1757d1cc387SAppaRao Puli EventServiceManager::getInstance().setEventServiceConfig( 17628afb49cSJunLin Chen eventServiceConfig); 1777e860f15SJohn Edward Broadbent }); 1780b4bdd93SAppaRao Puli } 1790b4bdd93SAppaRao Puli 1807e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app) 1810b4bdd93SAppaRao Puli { 1827e860f15SJohn Edward Broadbent BMCWEB_ROUTE( 1837e860f15SJohn Edward Broadbent app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/") 184ed398213SEd Tanous .privileges(redfish::privileges::postEventService) 1857e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::post)( 18645ca1b86SEd Tanous [&app](const crow::Request& req, 1877e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 1883ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 18945ca1b86SEd Tanous { 19045ca1b86SEd Tanous return; 19145ca1b86SEd Tanous } 1926ba8c82eSsunharis_in if (!EventServiceManager::getInstance().sendTestEventLog()) 1936ba8c82eSsunharis_in { 1946ba8c82eSsunharis_in messages::serviceDisabled(asyncResp->res, 1956ba8c82eSsunharis_in "/redfish/v1/EventService/"); 1966ba8c82eSsunharis_in return; 1976ba8c82eSsunharis_in } 1988d1b46d7Szhanghch05 asyncResp->res.result(boost::beast::http::status::no_content); 1997e860f15SJohn Edward Broadbent }); 200e5aaf047SAppaRao Puli } 201e5aaf047SAppaRao Puli 2023d30708fSChicago Duan inline void doSubscriptionCollection( 203e81de512SEd Tanous const boost::system::error_code& ec, 2043d30708fSChicago Duan const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 2053d30708fSChicago Duan const dbus::utility::ManagedObjectType& resp) 2063d30708fSChicago Duan { 2073d30708fSChicago Duan if (ec) 2083d30708fSChicago Duan { 2091306101eSEd Tanous if (ec.value() == EBADR || ec.value() == EHOSTUNREACH) 2103d30708fSChicago Duan { 2113d30708fSChicago Duan // This is an optional process so just return if it isn't there 2123d30708fSChicago Duan return; 2133d30708fSChicago Duan } 2143d30708fSChicago Duan 21562598e31SEd Tanous BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec); 2163d30708fSChicago Duan messages::internalError(asyncResp->res); 2173d30708fSChicago Duan return; 2183d30708fSChicago Duan } 2193d30708fSChicago Duan nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"]; 2203d30708fSChicago Duan for (const auto& objpath : resp) 2213d30708fSChicago Duan { 2223d30708fSChicago Duan sdbusplus::message::object_path path(objpath.first); 2233d30708fSChicago Duan const std::string snmpId = path.filename(); 2243d30708fSChicago Duan if (snmpId.empty()) 2253d30708fSChicago Duan { 22662598e31SEd Tanous BMCWEB_LOG_ERROR("The SNMP client ID is wrong"); 2273d30708fSChicago Duan messages::internalError(asyncResp->res); 2283d30708fSChicago Duan return; 2293d30708fSChicago Duan } 2303d30708fSChicago Duan 2313d30708fSChicago Duan getSnmpSubscriptionList(asyncResp, snmpId, memberArray); 2323d30708fSChicago Duan } 2333d30708fSChicago Duan } 2343d30708fSChicago Duan 2357e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app) 236e5aaf047SAppaRao Puli { 2371ebe3e41SGayathri Leburu BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 238ed398213SEd Tanous .privileges(redfish::privileges::getEventDestinationCollection) 2397e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 24045ca1b86SEd Tanous [&app](const crow::Request& req, 2417e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2423ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 24345ca1b86SEd Tanous { 24445ca1b86SEd Tanous return; 24545ca1b86SEd Tanous } 2461476687dSEd Tanous asyncResp->res.jsonValue["@odata.type"] = 2471476687dSEd Tanous "#EventDestinationCollection.EventDestinationCollection"; 2481476687dSEd Tanous asyncResp->res.jsonValue["@odata.id"] = 2491476687dSEd Tanous "/redfish/v1/EventService/Subscriptions"; 250bd79bce8SPatrick Williams asyncResp->res.jsonValue["Name"] = 251bd79bce8SPatrick Williams "Event Destination Collections"; 252e5aaf047SAppaRao Puli 253bd79bce8SPatrick Williams nlohmann::json& memberArray = 254bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members"]; 255e5aaf047SAppaRao Puli 256b52664e2SAppaRao Puli std::vector<std::string> subscripIds = 257b52664e2SAppaRao Puli EventServiceManager::getInstance().getAllIDs(); 258b52664e2SAppaRao Puli memberArray = nlohmann::json::array(); 259bd79bce8SPatrick Williams asyncResp->res.jsonValue["Members@odata.count"] = 260bd79bce8SPatrick Williams subscripIds.size(); 261b52664e2SAppaRao Puli 262b52664e2SAppaRao Puli for (const std::string& id : subscripIds) 263e5aaf047SAppaRao Puli { 2641476687dSEd Tanous nlohmann::json::object_t member; 2653d30708fSChicago Duan member["@odata.id"] = boost::urls::format( 2663d30708fSChicago Duan "/redfish/v1/EventService/Subscriptions/{}" + id); 267b2ba3072SPatrick Williams memberArray.emplace_back(std::move(member)); 268e5aaf047SAppaRao Puli } 2693d30708fSChicago Duan crow::connections::systemBus->async_method_call( 270e81de512SEd Tanous [asyncResp](const boost::system::error_code& ec, 2713d30708fSChicago Duan const dbus::utility::ManagedObjectType& resp) { 2723d30708fSChicago Duan doSubscriptionCollection(ec, asyncResp, resp); 2733d30708fSChicago Duan }, 2743d30708fSChicago Duan "xyz.openbmc_project.Network.SNMP", 2753d30708fSChicago Duan "/xyz/openbmc_project/network/snmp/manager", 2763d30708fSChicago Duan "org.freedesktop.DBus.ObjectManager", "GetManagedObjects"); 2777e860f15SJohn Edward Broadbent }); 2783d30708fSChicago Duan 2797e860f15SJohn Edward Broadbent BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/") 2807eeafa76SAbhishek Patel .privileges(redfish::privileges::postEventDestinationCollection) 281bd79bce8SPatrick Williams .methods( 282bd79bce8SPatrick Williams boost::beast::http::verb:: 283bd79bce8SPatrick Williams post)([&app]( 284bd79bce8SPatrick Williams const crow::Request& req, 2857e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) { 2863ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 28745ca1b86SEd Tanous { 28845ca1b86SEd Tanous return; 28945ca1b86SEd Tanous } 290fffb8c1fSEd Tanous if (EventServiceManager::getInstance().getNumberOfSubscriptions() >= 291fffb8c1fSEd Tanous maxNoOfSubscriptions) 292e5aaf047SAppaRao Puli { 293e5aaf047SAppaRao Puli messages::eventSubscriptionLimitExceeded(asyncResp->res); 294e5aaf047SAppaRao Puli return; 295e5aaf047SAppaRao Puli } 296e5aaf047SAppaRao Puli std::string destUrl; 297e5aaf047SAppaRao Puli std::string protocol; 29819bb362bSEd Tanous std::optional<bool> verifyCertificate; 299e5aaf047SAppaRao Puli std::optional<std::string> context; 300e5aaf047SAppaRao Puli std::optional<std::string> subscriptionType; 30123a21a1cSEd Tanous std::optional<std::string> eventFormatType2; 302e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 3035064a25bSMyung Bae std::optional<bool> sendHeartbeat; 3045064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 305e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> msgIds; 306e5aaf047SAppaRao Puli std::optional<std::vector<std::string>> regPrefixes; 307a14c9113SEd Tanous std::optional<std::vector<std::string>> originResources; 308e56f254cSSunitha Harish std::optional<std::vector<std::string>> resTypes; 30978d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 31078d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray; 311e5aaf047SAppaRao Puli 312afc474aeSMyung Bae if (!json_util::readJsonPatch( // 313afc474aeSMyung Bae req, asyncResp->res, // 314afc474aeSMyung Bae "Context", context, // 315afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 316afc474aeSMyung Bae "Destination", destUrl, // 317afc474aeSMyung Bae "EventFormatType", eventFormatType2, // 3185064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 319afc474aeSMyung Bae "HttpHeaders", headers, // 320afc474aeSMyung Bae "MessageIds", msgIds, // 321afc474aeSMyung Bae "MetricReportDefinitions", mrdJsonArray, // 322afc474aeSMyung Bae "OriginResources", originResources, // 323afc474aeSMyung Bae "Protocol", protocol, // 324afc474aeSMyung Bae "RegistryPrefixes", regPrefixes, // 325afc474aeSMyung Bae "ResourceTypes", resTypes, // 3265064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 327afc474aeSMyung Bae "SubscriptionType", subscriptionType, // 328afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 3294b712a29SEd Tanous )) 330e5aaf047SAppaRao Puli { 331e5aaf047SAppaRao Puli return; 332e5aaf047SAppaRao Puli } 3334b712a29SEd Tanous // clang-format on 334e5aaf047SAppaRao Puli 335600af5f1SAppaRao Puli // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers 336600af5f1SAppaRao Puli static constexpr const uint16_t maxDestinationSize = 2000; 337600af5f1SAppaRao Puli if (destUrl.size() > maxDestinationSize) 338600af5f1SAppaRao Puli { 339600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Destination", 340600af5f1SAppaRao Puli maxDestinationSize); 341600af5f1SAppaRao Puli return; 342600af5f1SAppaRao Puli } 343600af5f1SAppaRao Puli 344dd28ba82SAppaRao Puli if (regPrefixes && msgIds) 345dd28ba82SAppaRao Puli { 34626f6976fSEd Tanous if (!regPrefixes->empty() && !msgIds->empty()) 347dd28ba82SAppaRao Puli { 348bd79bce8SPatrick Williams messages::propertyValueConflict( 349bd79bce8SPatrick Williams asyncResp->res, "MessageIds", "RegistryPrefixes"); 350dd28ba82SAppaRao Puli return; 351dd28ba82SAppaRao Puli } 352dd28ba82SAppaRao Puli } 353dd28ba82SAppaRao Puli 3546fd29553SEd Tanous boost::system::result<boost::urls::url> url = 355a716aa74SEd Tanous boost::urls::parse_absolute_uri(destUrl); 356a716aa74SEd Tanous if (!url) 357e5aaf047SAppaRao Puli { 358bd79bce8SPatrick Williams BMCWEB_LOG_WARNING( 359bd79bce8SPatrick Williams "Failed to validate and split destination url"); 360e5aaf047SAppaRao Puli messages::propertyValueFormatError(asyncResp->res, destUrl, 361e5aaf047SAppaRao Puli "Destination"); 362e5aaf047SAppaRao Puli return; 363e5aaf047SAppaRao Puli } 364a716aa74SEd Tanous url->normalize(); 365b07942e3SGeorge Liu 366b07942e3SGeorge Liu // port_number returns zero if it is not a valid representable port 367b07942e3SGeorge Liu if (url->has_port() && url->port_number() == 0) 368b07942e3SGeorge Liu { 369b07942e3SGeorge Liu BMCWEB_LOG_WARNING("{} is an invalid port in destination url", 370b07942e3SGeorge Liu url->port()); 371b07942e3SGeorge Liu messages::propertyValueFormatError(asyncResp->res, destUrl, 372b07942e3SGeorge Liu "Destination"); 373b07942e3SGeorge Liu return; 374b07942e3SGeorge Liu } 375b07942e3SGeorge Liu 376a716aa74SEd Tanous crow::utility::setProtocolDefaults(*url, protocol); 377a716aa74SEd Tanous crow::utility::setPortDefaults(*url); 378a716aa74SEd Tanous 379a716aa74SEd Tanous if (url->path().empty()) 380a716aa74SEd Tanous { 381a716aa74SEd Tanous url->set_path("/"); 382a716aa74SEd Tanous } 383a716aa74SEd Tanous 384a716aa74SEd Tanous if (url->has_userinfo()) 385a716aa74SEd Tanous { 386a716aa74SEd Tanous messages::propertyValueFormatError(asyncResp->res, destUrl, 387a716aa74SEd Tanous "Destination"); 388a716aa74SEd Tanous return; 389a716aa74SEd Tanous } 390b52664e2SAppaRao Puli 3913d30708fSChicago Duan if (protocol == "SNMPv2c") 3923d30708fSChicago Duan { 3933d30708fSChicago Duan if (context) 3943d30708fSChicago Duan { 3953d30708fSChicago Duan messages::propertyValueConflict(asyncResp->res, "Context", 3963d30708fSChicago Duan "Protocol"); 3973d30708fSChicago Duan return; 3983d30708fSChicago Duan } 3993d30708fSChicago Duan if (eventFormatType2) 4003d30708fSChicago Duan { 401bd79bce8SPatrick Williams messages::propertyValueConflict( 402bd79bce8SPatrick Williams asyncResp->res, "EventFormatType", "Protocol"); 4033d30708fSChicago Duan return; 4043d30708fSChicago Duan } 4053d30708fSChicago Duan if (retryPolicy) 4063d30708fSChicago Duan { 407bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 408bd79bce8SPatrick Williams "RetryPolicy", "Protocol"); 4093d30708fSChicago Duan return; 4103d30708fSChicago Duan } 4115064a25bSMyung Bae if (sendHeartbeat) 4125064a25bSMyung Bae { 4135064a25bSMyung Bae messages::propertyValueConflict( 4145064a25bSMyung Bae asyncResp->res, "SendHeartbeat", "Protocol"); 4155064a25bSMyung Bae return; 4165064a25bSMyung Bae } 4175064a25bSMyung Bae if (hbIntervalMinutes) 4185064a25bSMyung Bae { 4195064a25bSMyung Bae messages::propertyValueConflict( 4205064a25bSMyung Bae asyncResp->res, "HeartbeatIntervalMinutes", "Protocol"); 4215064a25bSMyung Bae return; 4225064a25bSMyung Bae } 4233d30708fSChicago Duan if (msgIds) 4243d30708fSChicago Duan { 425bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 426bd79bce8SPatrick Williams "MessageIds", "Protocol"); 4273d30708fSChicago Duan return; 4283d30708fSChicago Duan } 4293d30708fSChicago Duan if (regPrefixes) 4303d30708fSChicago Duan { 431bd79bce8SPatrick Williams messages::propertyValueConflict( 432bd79bce8SPatrick Williams asyncResp->res, "RegistryPrefixes", "Protocol"); 4333d30708fSChicago Duan return; 4343d30708fSChicago Duan } 4353d30708fSChicago Duan if (resTypes) 4363d30708fSChicago Duan { 437bd79bce8SPatrick Williams messages::propertyValueConflict( 438bd79bce8SPatrick Williams asyncResp->res, "ResourceTypes", "Protocol"); 4393d30708fSChicago Duan return; 4403d30708fSChicago Duan } 4413d30708fSChicago Duan if (headers) 4423d30708fSChicago Duan { 443bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 444bd79bce8SPatrick Williams "HttpHeaders", "Protocol"); 4453d30708fSChicago Duan return; 4463d30708fSChicago Duan } 4473d30708fSChicago Duan if (mrdJsonArray) 4483d30708fSChicago Duan { 4493d30708fSChicago Duan messages::propertyValueConflict( 4503d30708fSChicago Duan asyncResp->res, "MetricReportDefinitions", "Protocol"); 4513d30708fSChicago Duan return; 4523d30708fSChicago Duan } 453a716aa74SEd Tanous if (url->scheme() != "snmp") 454a716aa74SEd Tanous { 455bd79bce8SPatrick Williams messages::propertyValueConflict(asyncResp->res, 456bd79bce8SPatrick Williams "Destination", "Protocol"); 4573d30708fSChicago Duan return; 4583d30708fSChicago Duan } 4593d30708fSChicago Duan 460a716aa74SEd Tanous addSnmpTrapClient(asyncResp, url->host_address(), 461a716aa74SEd Tanous url->port_number()); 462a716aa74SEd Tanous return; 463b52664e2SAppaRao Puli } 4643d30708fSChicago Duan 465a716aa74SEd Tanous std::shared_ptr<Subscription> subValue = 46621a94d5cSMyung Bae std::make_shared<Subscription>( 4675fe4ef35SMyung Bae std::make_shared<persistent_data::UserSubscription>(), *url, 4685fe4ef35SMyung Bae app.ioContext()); 469e5aaf047SAppaRao Puli 470e5aaf047SAppaRao Puli if (subscriptionType) 471e5aaf047SAppaRao Puli { 472e5aaf047SAppaRao Puli if (*subscriptionType != "RedfishEvent") 473e5aaf047SAppaRao Puli { 474fffb8c1fSEd Tanous messages::propertyValueNotInList( 475fffb8c1fSEd Tanous asyncResp->res, *subscriptionType, "SubscriptionType"); 476e5aaf047SAppaRao Puli return; 477e5aaf047SAppaRao Puli } 4785fe4ef35SMyung Bae subValue->userSub->subscriptionType = *subscriptionType; 479e5aaf047SAppaRao Puli } 480e5aaf047SAppaRao Puli else 481e5aaf047SAppaRao Puli { 4824b712a29SEd Tanous // Default 4835fe4ef35SMyung Bae subValue->userSub->subscriptionType = "RedfishEvent"; 484e5aaf047SAppaRao Puli } 485e5aaf047SAppaRao Puli 486e5aaf047SAppaRao Puli if (protocol != "Redfish") 487e5aaf047SAppaRao Puli { 488e5aaf047SAppaRao Puli messages::propertyValueNotInList(asyncResp->res, protocol, 489e5aaf047SAppaRao Puli "Protocol"); 490e5aaf047SAppaRao Puli return; 491e5aaf047SAppaRao Puli } 4925fe4ef35SMyung Bae subValue->userSub->protocol = protocol; 493e5aaf047SAppaRao Puli 49419bb362bSEd Tanous if (verifyCertificate) 49519bb362bSEd Tanous { 4965fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 49719bb362bSEd Tanous } 49819bb362bSEd Tanous 49923a21a1cSEd Tanous if (eventFormatType2) 500e5aaf047SAppaRao Puli { 501bd79bce8SPatrick Williams if (std::ranges::find(supportedEvtFormatTypes, 502bd79bce8SPatrick Williams *eventFormatType2) == 5033544d2a7SEd Tanous supportedEvtFormatTypes.end()) 504e5aaf047SAppaRao Puli { 505fffb8c1fSEd Tanous messages::propertyValueNotInList( 506fffb8c1fSEd Tanous asyncResp->res, *eventFormatType2, "EventFormatType"); 507e5aaf047SAppaRao Puli return; 508e5aaf047SAppaRao Puli } 5095fe4ef35SMyung Bae subValue->userSub->eventFormatType = *eventFormatType2; 510e5aaf047SAppaRao Puli } 511e5aaf047SAppaRao Puli else 512e5aaf047SAppaRao Puli { 513e5aaf047SAppaRao Puli // If not specified, use default "Event" 5145fe4ef35SMyung Bae subValue->userSub->eventFormatType = "Event"; 515e5aaf047SAppaRao Puli } 516e5aaf047SAppaRao Puli 517e5aaf047SAppaRao Puli if (context) 518e5aaf047SAppaRao Puli { 5198ece0e45SEd Tanous // This value is selected arbitrarily. 520600af5f1SAppaRao Puli constexpr const size_t maxContextSize = 256; 521600af5f1SAppaRao Puli if (context->size() > maxContextSize) 522600af5f1SAppaRao Puli { 523600af5f1SAppaRao Puli messages::stringValueTooLong(asyncResp->res, "Context", 524600af5f1SAppaRao Puli maxContextSize); 525600af5f1SAppaRao Puli return; 526600af5f1SAppaRao Puli } 5275fe4ef35SMyung Bae subValue->userSub->customText = *context; 528e5aaf047SAppaRao Puli } 529e5aaf047SAppaRao Puli 530e5aaf047SAppaRao Puli if (headers) 531e5aaf047SAppaRao Puli { 532600af5f1SAppaRao Puli size_t cumulativeLen = 0; 533600af5f1SAppaRao Puli 53478d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 535601c71aeSEd Tanous { 53678d4ec4fSEd Tanous for (const auto& item : headerChunk) 53778d4ec4fSEd Tanous { 53878d4ec4fSEd Tanous const std::string* value = 53978d4ec4fSEd Tanous item.second.get_ptr<const std::string*>(); 54078d4ec4fSEd Tanous if (value == nullptr) 54178d4ec4fSEd Tanous { 54278d4ec4fSEd Tanous messages::propertyValueFormatError( 54378d4ec4fSEd Tanous asyncResp->res, item.second, 54478d4ec4fSEd Tanous "HttpHeaders/" + item.first); 54578d4ec4fSEd Tanous return; 54678d4ec4fSEd Tanous } 54778d4ec4fSEd Tanous // Adding a new json value is the size of the key, + 54878d4ec4fSEd Tanous // the size of the value + 2 * 2 quotes for each, + 54978d4ec4fSEd Tanous // the colon and space between. example: 55078d4ec4fSEd Tanous // "key": "value" 55178d4ec4fSEd Tanous cumulativeLen += item.first.size() + value->size() + 6; 552600af5f1SAppaRao Puli // This value is selected to mirror http_connection.hpp 553600af5f1SAppaRao Puli constexpr const uint16_t maxHeaderSizeED = 8096; 554600af5f1SAppaRao Puli if (cumulativeLen > maxHeaderSizeED) 555600af5f1SAppaRao Puli { 55678d4ec4fSEd Tanous messages::arraySizeTooLong( 55778d4ec4fSEd Tanous asyncResp->res, "HttpHeaders", maxHeaderSizeED); 558600af5f1SAppaRao Puli return; 559600af5f1SAppaRao Puli } 5605fe4ef35SMyung Bae subValue->userSub->httpHeaders.set(item.first, *value); 561601c71aeSEd Tanous } 562601c71aeSEd Tanous } 563e5aaf047SAppaRao Puli } 564e5aaf047SAppaRao Puli 565e5aaf047SAppaRao Puli if (regPrefixes) 566e5aaf047SAppaRao Puli { 567e5aaf047SAppaRao Puli for (const std::string& it : *regPrefixes) 568e5aaf047SAppaRao Puli { 5693544d2a7SEd Tanous if (std::ranges::find(supportedRegPrefixes, it) == 5703544d2a7SEd Tanous supportedRegPrefixes.end()) 571e5aaf047SAppaRao Puli { 572fffb8c1fSEd Tanous messages::propertyValueNotInList(asyncResp->res, it, 573fffb8c1fSEd Tanous "RegistryPrefixes"); 574e5aaf047SAppaRao Puli return; 575e5aaf047SAppaRao Puli } 576e5aaf047SAppaRao Puli } 5775fe4ef35SMyung Bae subValue->userSub->registryPrefixes = *regPrefixes; 578e5aaf047SAppaRao Puli } 579e5aaf047SAppaRao Puli 580a14c9113SEd Tanous if (originResources) 581a14c9113SEd Tanous { 5825fe4ef35SMyung Bae subValue->userSub->originResources = *originResources; 583a14c9113SEd Tanous } 584a14c9113SEd Tanous 585e56f254cSSunitha Harish if (resTypes) 586e56f254cSSunitha Harish { 587e56f254cSSunitha Harish for (const std::string& it : *resTypes) 588e56f254cSSunitha Harish { 5893544d2a7SEd Tanous if (std::ranges::find(supportedResourceTypes, it) == 5903544d2a7SEd Tanous supportedResourceTypes.end()) 591e56f254cSSunitha Harish { 592e56f254cSSunitha Harish messages::propertyValueNotInList(asyncResp->res, it, 593e56f254cSSunitha Harish "ResourceTypes"); 594e56f254cSSunitha Harish return; 595e56f254cSSunitha Harish } 596e56f254cSSunitha Harish } 5975fe4ef35SMyung Bae subValue->userSub->resourceTypes = *resTypes; 598e56f254cSSunitha Harish } 599e56f254cSSunitha Harish 600e5aaf047SAppaRao Puli if (msgIds) 601e5aaf047SAppaRao Puli { 602b304bd79SP Dheeraj Srujan Kumar std::vector<std::string> registryPrefix; 603b304bd79SP Dheeraj Srujan Kumar 6047e860f15SJohn Edward Broadbent // If no registry prefixes are mentioned, consider all 6057e860f15SJohn Edward Broadbent // supported prefixes 6065fe4ef35SMyung Bae if (subValue->userSub->registryPrefixes.empty()) 607b304bd79SP Dheeraj Srujan Kumar { 608b304bd79SP Dheeraj Srujan Kumar registryPrefix.assign(supportedRegPrefixes.begin(), 609b304bd79SP Dheeraj Srujan Kumar supportedRegPrefixes.end()); 610b304bd79SP Dheeraj Srujan Kumar } 611b304bd79SP Dheeraj Srujan Kumar else 612b304bd79SP Dheeraj Srujan Kumar { 6135fe4ef35SMyung Bae registryPrefix = subValue->userSub->registryPrefixes; 614b304bd79SP Dheeraj Srujan Kumar } 615b304bd79SP Dheeraj Srujan Kumar 616b304bd79SP Dheeraj Srujan Kumar for (const std::string& id : *msgIds) 617b304bd79SP Dheeraj Srujan Kumar { 618b304bd79SP Dheeraj Srujan Kumar bool validId = false; 619b304bd79SP Dheeraj Srujan Kumar 620b304bd79SP Dheeraj Srujan Kumar // Check for Message ID in each of the selected Registry 621b304bd79SP Dheeraj Srujan Kumar for (const std::string& it : registryPrefix) 622b304bd79SP Dheeraj Srujan Kumar { 623fffb8c1fSEd Tanous const std::span<const redfish::registries::MessageEntry> 624fffb8c1fSEd Tanous registry = 625fffb8c1fSEd Tanous redfish::registries::getRegistryFromPrefix(it); 626b304bd79SP Dheeraj Srujan Kumar 6273544d2a7SEd Tanous if (std::ranges::any_of( 6283544d2a7SEd Tanous registry, 629fffb8c1fSEd Tanous [&id](const redfish::registries::MessageEntry& 630fffb8c1fSEd Tanous messageEntry) { 63155f79e6fSEd Tanous return id == messageEntry.first; 632b304bd79SP Dheeraj Srujan Kumar })) 633b304bd79SP Dheeraj Srujan Kumar { 634b304bd79SP Dheeraj Srujan Kumar validId = true; 635b304bd79SP Dheeraj Srujan Kumar break; 636b304bd79SP Dheeraj Srujan Kumar } 637b304bd79SP Dheeraj Srujan Kumar } 638b304bd79SP Dheeraj Srujan Kumar 639b304bd79SP Dheeraj Srujan Kumar if (!validId) 640b304bd79SP Dheeraj Srujan Kumar { 641b304bd79SP Dheeraj Srujan Kumar messages::propertyValueNotInList(asyncResp->res, id, 642b304bd79SP Dheeraj Srujan Kumar "MessageIds"); 643b304bd79SP Dheeraj Srujan Kumar return; 644b304bd79SP Dheeraj Srujan Kumar } 645b304bd79SP Dheeraj Srujan Kumar } 646b304bd79SP Dheeraj Srujan Kumar 6475fe4ef35SMyung Bae subValue->userSub->registryMsgIds = *msgIds; 648e5aaf047SAppaRao Puli } 649e5aaf047SAppaRao Puli 650e5aaf047SAppaRao Puli if (retryPolicy) 651e5aaf047SAppaRao Puli { 6523544d2a7SEd Tanous if (std::ranges::find(supportedRetryPolicies, *retryPolicy) == 6533544d2a7SEd Tanous supportedRetryPolicies.end()) 654e5aaf047SAppaRao Puli { 655bd79bce8SPatrick Williams messages::propertyValueNotInList( 656bd79bce8SPatrick Williams asyncResp->res, *retryPolicy, "DeliveryRetryPolicy"); 657e5aaf047SAppaRao Puli return; 658e5aaf047SAppaRao Puli } 6595fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 660e5aaf047SAppaRao Puli } 661e5aaf047SAppaRao Puli else 662e5aaf047SAppaRao Puli { 663e5aaf047SAppaRao Puli // Default "TerminateAfterRetries" 6645fe4ef35SMyung Bae subValue->userSub->retryPolicy = "TerminateAfterRetries"; 665e5aaf047SAppaRao Puli } 6665064a25bSMyung Bae if (sendHeartbeat) 6675064a25bSMyung Bae { 6685064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 6695064a25bSMyung Bae } 6705064a25bSMyung Bae if (hbIntervalMinutes) 6715064a25bSMyung Bae { 6725064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 6735064a25bSMyung Bae { 6745064a25bSMyung Bae messages::propertyValueOutOfRange( 6755064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 6765064a25bSMyung Bae "HeartbeatIntervalMinutes"); 6775064a25bSMyung Bae return; 6785064a25bSMyung Bae } 6795064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 6805064a25bSMyung Bae } 681e5aaf047SAppaRao Puli 682144b6318SAppaRao Puli if (mrdJsonArray) 683156d6b00SAppaRao Puli { 68478d4ec4fSEd Tanous for (nlohmann::json::object_t& mrdObj : *mrdJsonArray) 685144b6318SAppaRao Puli { 686144b6318SAppaRao Puli std::string mrdUri; 687ea2e6eecSWilly Tu 68878d4ec4fSEd Tanous if (!json_util::readJsonObject(mrdObj, asyncResp->res, 68978d4ec4fSEd Tanous "@odata.id", mrdUri)) 690ea2e6eecSWilly Tu 691144b6318SAppaRao Puli { 692144b6318SAppaRao Puli return; 693144b6318SAppaRao Puli } 6945fe4ef35SMyung Bae subValue->userSub->metricReportDefinitions.emplace_back( 6954b712a29SEd Tanous mrdUri); 696144b6318SAppaRao Puli } 697156d6b00SAppaRao Puli } 698156d6b00SAppaRao Puli 699b52664e2SAppaRao Puli std::string id = 700bd79bce8SPatrick Williams EventServiceManager::getInstance().addPushSubscription( 701bd79bce8SPatrick Williams subValue); 702b52664e2SAppaRao Puli if (id.empty()) 703e5aaf047SAppaRao Puli { 704e5aaf047SAppaRao Puli messages::internalError(asyncResp->res); 705e5aaf047SAppaRao Puli return; 706e5aaf047SAppaRao Puli } 707e5aaf047SAppaRao Puli 708e5aaf047SAppaRao Puli messages::created(asyncResp->res); 709e5aaf047SAppaRao Puli asyncResp->res.addHeader( 710e5aaf047SAppaRao Puli "Location", "/redfish/v1/EventService/Subscriptions/" + id); 711*fb546105SMyung Bae 712*fb546105SMyung Bae // schedule a heartbeat 713*fb546105SMyung Bae if (subValue->userSub->sendHeartbeat) 714*fb546105SMyung Bae { 715*fb546105SMyung Bae subValue->scheduleNextHeartbeatEvent(); 716*fb546105SMyung Bae } 7177e860f15SJohn Edward Broadbent }); 718e5aaf047SAppaRao Puli } 719e5aaf047SAppaRao Puli 7207e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 721e5aaf047SAppaRao Puli { 7229d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 723ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 7247e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 72545ca1b86SEd Tanous [&app](const crow::Request& req, 7267e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7277e860f15SJohn Edward Broadbent const std::string& param) { 7283ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 72945ca1b86SEd Tanous { 73045ca1b86SEd Tanous return; 73145ca1b86SEd Tanous } 7323d30708fSChicago Duan 7333d30708fSChicago Duan if (param.starts_with("snmp")) 7343d30708fSChicago Duan { 7353d30708fSChicago Duan getSnmpTrapClient(asyncResp, param); 7363d30708fSChicago Duan return; 7373d30708fSChicago Duan } 7383d30708fSChicago Duan 739b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 7407e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 741b52664e2SAppaRao Puli if (subValue == nullptr) 742e5aaf047SAppaRao Puli { 743bd79bce8SPatrick Williams asyncResp->res.result( 744bd79bce8SPatrick Williams boost::beast::http::status::not_found); 745e5aaf047SAppaRao Puli return; 746e5aaf047SAppaRao Puli } 7477e860f15SJohn Edward Broadbent const std::string& id = param; 748e5aaf047SAppaRao Puli 7494b712a29SEd Tanous const persistent_data::UserSubscription& userSub = 7505fe4ef35SMyung Bae *subValue->userSub; 751e56f254cSSunitha Harish 7524b712a29SEd Tanous nlohmann::json& jVal = asyncResp->res.jsonValue; 7534b712a29SEd Tanous jVal["@odata.type"] = 7544b712a29SEd Tanous "#EventDestination.v1_14_1.EventDestination"; 7554b712a29SEd Tanous jVal["Protocol"] = 7564b712a29SEd Tanous event_destination::EventDestinationProtocol::Redfish; 7574b712a29SEd Tanous jVal["@odata.id"] = boost::urls::format( 7584b712a29SEd Tanous "/redfish/v1/EventService/Subscriptions/{}", id); 7594b712a29SEd Tanous jVal["Id"] = id; 7604b712a29SEd Tanous jVal["Name"] = "Event Destination " + id; 7614b712a29SEd Tanous jVal["Destination"] = userSub.destinationUrl; 7624b712a29SEd Tanous jVal["Context"] = userSub.customText; 7634b712a29SEd Tanous jVal["SubscriptionType"] = userSub.subscriptionType; 7644b712a29SEd Tanous jVal["HttpHeaders"] = nlohmann::json::array(); 7654b712a29SEd Tanous jVal["EventFormatType"] = userSub.eventFormatType; 7664b712a29SEd Tanous jVal["RegistryPrefixes"] = userSub.registryPrefixes; 7674b712a29SEd Tanous jVal["ResourceTypes"] = userSub.resourceTypes; 7684b712a29SEd Tanous 7694b712a29SEd Tanous jVal["MessageIds"] = userSub.registryMsgIds; 7704b712a29SEd Tanous jVal["DeliveryRetryPolicy"] = userSub.retryPolicy; 7715064a25bSMyung Bae jVal["SendHeartbeat"] = userSub.sendHeartbeat; 7725064a25bSMyung Bae jVal["HeartbeatIntervalMinutes"] = userSub.hbIntervalMinutes; 7734b712a29SEd Tanous jVal["VerifyCertificate"] = userSub.verifyCertificate; 774144b6318SAppaRao Puli 7751476687dSEd Tanous nlohmann::json::array_t mrdJsonArray; 7764b712a29SEd Tanous for (const auto& mdrUri : userSub.metricReportDefinitions) 777144b6318SAppaRao Puli { 7781476687dSEd Tanous nlohmann::json::object_t mdr; 7791476687dSEd Tanous mdr["@odata.id"] = mdrUri; 7801476687dSEd Tanous mrdJsonArray.emplace_back(std::move(mdr)); 781144b6318SAppaRao Puli } 7824b712a29SEd Tanous jVal["MetricReportDefinitions"] = mrdJsonArray; 7837e860f15SJohn Edward Broadbent }); 7849d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 785ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 786ed398213SEd Tanous // ConfigureSelf 7877eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 788ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 789432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 7907e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 79145ca1b86SEd Tanous [&app](const crow::Request& req, 7927e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7937e860f15SJohn Edward Broadbent const std::string& param) { 7943ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 79545ca1b86SEd Tanous { 79645ca1b86SEd Tanous return; 79745ca1b86SEd Tanous } 798b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 7997e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 800b52664e2SAppaRao Puli if (subValue == nullptr) 801e5aaf047SAppaRao Puli { 802bd79bce8SPatrick Williams asyncResp->res.result( 803bd79bce8SPatrick Williams boost::beast::http::status::not_found); 804e5aaf047SAppaRao Puli return; 805e5aaf047SAppaRao Puli } 806e5aaf047SAppaRao Puli 807e5aaf047SAppaRao Puli std::optional<std::string> context; 808e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 8095064a25bSMyung Bae std::optional<bool> sendHeartbeat; 8105064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 81119bb362bSEd Tanous std::optional<bool> verifyCertificate; 81278d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 813e5aaf047SAppaRao Puli 814afc474aeSMyung Bae if (!json_util::readJsonPatch( // 815afc474aeSMyung Bae req, asyncResp->res, // 816afc474aeSMyung Bae "Context", context, // 817afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 8185064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 819afc474aeSMyung Bae "HttpHeaders", headers, // 8205064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 821afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 822afc474aeSMyung Bae )) 823e5aaf047SAppaRao Puli { 824e5aaf047SAppaRao Puli return; 825e5aaf047SAppaRao Puli } 826e5aaf047SAppaRao Puli 827e5aaf047SAppaRao Puli if (context) 828e5aaf047SAppaRao Puli { 8295fe4ef35SMyung Bae subValue->userSub->customText = *context; 830e5aaf047SAppaRao Puli } 831e5aaf047SAppaRao Puli 832e5aaf047SAppaRao Puli if (headers) 833e5aaf047SAppaRao Puli { 834601c71aeSEd Tanous boost::beast::http::fields fields; 83578d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 836601c71aeSEd Tanous { 83778d4ec4fSEd Tanous for (const auto& it : headerChunk) 838601c71aeSEd Tanous { 839601c71aeSEd Tanous const std::string* value = 84078d4ec4fSEd Tanous it.second.get_ptr<const std::string*>(); 841601c71aeSEd Tanous if (value == nullptr) 842601c71aeSEd Tanous { 843601c71aeSEd Tanous messages::propertyValueFormatError( 84478d4ec4fSEd Tanous asyncResp->res, it.second, 84578d4ec4fSEd Tanous "HttpHeaders/" + it.first); 846601c71aeSEd Tanous return; 847601c71aeSEd Tanous } 84878d4ec4fSEd Tanous fields.set(it.first, *value); 849601c71aeSEd Tanous } 850601c71aeSEd Tanous } 8515fe4ef35SMyung Bae subValue->userSub->httpHeaders = std::move(fields); 852e5aaf047SAppaRao Puli } 853e5aaf047SAppaRao Puli 854e5aaf047SAppaRao Puli if (retryPolicy) 855e5aaf047SAppaRao Puli { 856bd79bce8SPatrick Williams if (std::ranges::find(supportedRetryPolicies, 857bd79bce8SPatrick Williams *retryPolicy) == 8583544d2a7SEd Tanous supportedRetryPolicies.end()) 859e5aaf047SAppaRao Puli { 860bd79bce8SPatrick Williams messages::propertyValueNotInList(asyncResp->res, 861bd79bce8SPatrick Williams *retryPolicy, 862e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 863e5aaf047SAppaRao Puli return; 864e5aaf047SAppaRao Puli } 8655fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 866e5aaf047SAppaRao Puli } 867e5aaf047SAppaRao Puli 8685064a25bSMyung Bae if (sendHeartbeat) 8695064a25bSMyung Bae { 8705064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 8715064a25bSMyung Bae } 8725064a25bSMyung Bae if (hbIntervalMinutes) 8735064a25bSMyung Bae { 8745064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 8755064a25bSMyung Bae { 8765064a25bSMyung Bae messages::propertyValueOutOfRange( 8775064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 8785064a25bSMyung Bae "HeartbeatIntervalMinutes"); 8795064a25bSMyung Bae return; 8805064a25bSMyung Bae } 8815064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 8825064a25bSMyung Bae } 8835064a25bSMyung Bae 884*fb546105SMyung Bae if (hbIntervalMinutes || sendHeartbeat) 885*fb546105SMyung Bae { 886*fb546105SMyung Bae // if Heartbeat interval or send heart were changed, cancel 887*fb546105SMyung Bae // the heartbeat timer if running and start a new heartbeat 888*fb546105SMyung Bae // if needed 889*fb546105SMyung Bae subValue->heartbeatParametersChanged(); 890*fb546105SMyung Bae } 891*fb546105SMyung Bae 89219bb362bSEd Tanous if (verifyCertificate) 89319bb362bSEd Tanous { 8945fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 89519bb362bSEd Tanous } 89619bb362bSEd Tanous 897b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 8987e860f15SJohn Edward Broadbent }); 8999d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 900ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 901ed398213SEd Tanous // ConfigureSelf 9027eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 903ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 904432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 9057e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 90645ca1b86SEd Tanous [&app](const crow::Request& req, 9077e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 9087e860f15SJohn Edward Broadbent const std::string& param) { 9093ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 91045ca1b86SEd Tanous { 91145ca1b86SEd Tanous return; 91245ca1b86SEd Tanous } 9134b712a29SEd Tanous EventServiceManager& event = EventServiceManager::getInstance(); 9143d30708fSChicago Duan if (param.starts_with("snmp")) 9153d30708fSChicago Duan { 9163d30708fSChicago Duan deleteSnmpTrapClient(asyncResp, param); 9174b712a29SEd Tanous event.deleteSubscription(param); 9183d30708fSChicago Duan return; 9193d30708fSChicago Duan } 9203d30708fSChicago Duan 9214b712a29SEd Tanous if (!event.deleteSubscription(param)) 922e5aaf047SAppaRao Puli { 9234b712a29SEd Tanous messages::resourceNotFound(asyncResp->res, 9244b712a29SEd Tanous "EventDestination", param); 925e5aaf047SAppaRao Puli return; 926e5aaf047SAppaRao Puli } 9274b712a29SEd Tanous messages::success(asyncResp->res); 9287e860f15SJohn Edward Broadbent }); 929e5aaf047SAppaRao Puli } 930e5aaf047SAppaRao Puli 931e5aaf047SAppaRao Puli } // namespace redfish 932