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> 37*5064a25bSMyung 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}; 48e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = { 49b304bd79SP Dheeraj Srujan Kumar "Base", "OpenBMC", "TaskEvent"}; 50e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = { 51e5aaf047SAppaRao Puli "TerminateAfterRetries", "SuspendRetries", "RetryForever"}; 52e5aaf047SAppaRao Puli 53e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = { 54e56f254cSSunitha Harish "Task"}; 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; 303*5064a25bSMyung Bae std::optional<bool> sendHeartbeat; 304*5064a25bSMyung 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, // 318*5064a25bSMyung 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, // 326*5064a25bSMyung 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 } 411*5064a25bSMyung Bae if (sendHeartbeat) 412*5064a25bSMyung Bae { 413*5064a25bSMyung Bae messages::propertyValueConflict( 414*5064a25bSMyung Bae asyncResp->res, "SendHeartbeat", "Protocol"); 415*5064a25bSMyung Bae return; 416*5064a25bSMyung Bae } 417*5064a25bSMyung Bae if (hbIntervalMinutes) 418*5064a25bSMyung Bae { 419*5064a25bSMyung Bae messages::propertyValueConflict( 420*5064a25bSMyung Bae asyncResp->res, "HeartbeatIntervalMinutes", "Protocol"); 421*5064a25bSMyung Bae return; 422*5064a25bSMyung 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 } 666*5064a25bSMyung Bae if (sendHeartbeat) 667*5064a25bSMyung Bae { 668*5064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 669*5064a25bSMyung Bae } 670*5064a25bSMyung Bae if (hbIntervalMinutes) 671*5064a25bSMyung Bae { 672*5064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 673*5064a25bSMyung Bae { 674*5064a25bSMyung Bae messages::propertyValueOutOfRange( 675*5064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 676*5064a25bSMyung Bae "HeartbeatIntervalMinutes"); 677*5064a25bSMyung Bae return; 678*5064a25bSMyung Bae } 679*5064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 680*5064a25bSMyung 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); 7117e860f15SJohn Edward Broadbent }); 712e5aaf047SAppaRao Puli } 713e5aaf047SAppaRao Puli 7147e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app) 715e5aaf047SAppaRao Puli { 7169d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 717ed398213SEd Tanous .privileges(redfish::privileges::getEventDestination) 7187e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::get)( 71945ca1b86SEd Tanous [&app](const crow::Request& req, 7207e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7217e860f15SJohn Edward Broadbent const std::string& param) { 7223ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 72345ca1b86SEd Tanous { 72445ca1b86SEd Tanous return; 72545ca1b86SEd Tanous } 7263d30708fSChicago Duan 7273d30708fSChicago Duan if (param.starts_with("snmp")) 7283d30708fSChicago Duan { 7293d30708fSChicago Duan getSnmpTrapClient(asyncResp, param); 7303d30708fSChicago Duan return; 7313d30708fSChicago Duan } 7323d30708fSChicago Duan 733b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 7347e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 735b52664e2SAppaRao Puli if (subValue == nullptr) 736e5aaf047SAppaRao Puli { 737bd79bce8SPatrick Williams asyncResp->res.result( 738bd79bce8SPatrick Williams boost::beast::http::status::not_found); 739e5aaf047SAppaRao Puli return; 740e5aaf047SAppaRao Puli } 7417e860f15SJohn Edward Broadbent const std::string& id = param; 742e5aaf047SAppaRao Puli 7434b712a29SEd Tanous const persistent_data::UserSubscription& userSub = 7445fe4ef35SMyung Bae *subValue->userSub; 745e56f254cSSunitha Harish 7464b712a29SEd Tanous nlohmann::json& jVal = asyncResp->res.jsonValue; 7474b712a29SEd Tanous jVal["@odata.type"] = 7484b712a29SEd Tanous "#EventDestination.v1_14_1.EventDestination"; 7494b712a29SEd Tanous jVal["Protocol"] = 7504b712a29SEd Tanous event_destination::EventDestinationProtocol::Redfish; 7514b712a29SEd Tanous jVal["@odata.id"] = boost::urls::format( 7524b712a29SEd Tanous "/redfish/v1/EventService/Subscriptions/{}", id); 7534b712a29SEd Tanous jVal["Id"] = id; 7544b712a29SEd Tanous jVal["Name"] = "Event Destination " + id; 7554b712a29SEd Tanous jVal["Destination"] = userSub.destinationUrl; 7564b712a29SEd Tanous jVal["Context"] = userSub.customText; 7574b712a29SEd Tanous jVal["SubscriptionType"] = userSub.subscriptionType; 7584b712a29SEd Tanous jVal["HttpHeaders"] = nlohmann::json::array(); 7594b712a29SEd Tanous jVal["EventFormatType"] = userSub.eventFormatType; 7604b712a29SEd Tanous jVal["RegistryPrefixes"] = userSub.registryPrefixes; 7614b712a29SEd Tanous jVal["ResourceTypes"] = userSub.resourceTypes; 7624b712a29SEd Tanous 7634b712a29SEd Tanous jVal["MessageIds"] = userSub.registryMsgIds; 7644b712a29SEd Tanous jVal["DeliveryRetryPolicy"] = userSub.retryPolicy; 765*5064a25bSMyung Bae jVal["SendHeartbeat"] = userSub.sendHeartbeat; 766*5064a25bSMyung Bae jVal["HeartbeatIntervalMinutes"] = userSub.hbIntervalMinutes; 7674b712a29SEd Tanous jVal["VerifyCertificate"] = userSub.verifyCertificate; 768144b6318SAppaRao Puli 7691476687dSEd Tanous nlohmann::json::array_t mrdJsonArray; 7704b712a29SEd Tanous for (const auto& mdrUri : userSub.metricReportDefinitions) 771144b6318SAppaRao Puli { 7721476687dSEd Tanous nlohmann::json::object_t mdr; 7731476687dSEd Tanous mdr["@odata.id"] = mdrUri; 7741476687dSEd Tanous mrdJsonArray.emplace_back(std::move(mdr)); 775144b6318SAppaRao Puli } 7764b712a29SEd Tanous jVal["MetricReportDefinitions"] = mrdJsonArray; 7777e860f15SJohn Edward Broadbent }); 7789d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 779ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 780ed398213SEd Tanous // ConfigureSelf 7817eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 782ed398213SEd Tanous //.privileges(redfish::privileges::patchEventDestination) 783432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 7847e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::patch)( 78545ca1b86SEd Tanous [&app](const crow::Request& req, 7867e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 7877e860f15SJohn Edward Broadbent const std::string& param) { 7883ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 78945ca1b86SEd Tanous { 79045ca1b86SEd Tanous return; 79145ca1b86SEd Tanous } 792b52664e2SAppaRao Puli std::shared_ptr<Subscription> subValue = 7937e860f15SJohn Edward Broadbent EventServiceManager::getInstance().getSubscription(param); 794b52664e2SAppaRao Puli if (subValue == nullptr) 795e5aaf047SAppaRao Puli { 796bd79bce8SPatrick Williams asyncResp->res.result( 797bd79bce8SPatrick Williams boost::beast::http::status::not_found); 798e5aaf047SAppaRao Puli return; 799e5aaf047SAppaRao Puli } 800e5aaf047SAppaRao Puli 801e5aaf047SAppaRao Puli std::optional<std::string> context; 802e5aaf047SAppaRao Puli std::optional<std::string> retryPolicy; 803*5064a25bSMyung Bae std::optional<bool> sendHeartbeat; 804*5064a25bSMyung Bae std::optional<uint64_t> hbIntervalMinutes; 80519bb362bSEd Tanous std::optional<bool> verifyCertificate; 80678d4ec4fSEd Tanous std::optional<std::vector<nlohmann::json::object_t>> headers; 807e5aaf047SAppaRao Puli 808afc474aeSMyung Bae if (!json_util::readJsonPatch( // 809afc474aeSMyung Bae req, asyncResp->res, // 810afc474aeSMyung Bae "Context", context, // 811afc474aeSMyung Bae "DeliveryRetryPolicy", retryPolicy, // 812*5064a25bSMyung Bae "HeartbeatIntervalMinutes", hbIntervalMinutes, // 813afc474aeSMyung Bae "HttpHeaders", headers, // 814*5064a25bSMyung Bae "SendHeartbeat", sendHeartbeat, // 815afc474aeSMyung Bae "VerifyCertificate", verifyCertificate // 816afc474aeSMyung Bae )) 817e5aaf047SAppaRao Puli { 818e5aaf047SAppaRao Puli return; 819e5aaf047SAppaRao Puli } 820e5aaf047SAppaRao Puli 821e5aaf047SAppaRao Puli if (context) 822e5aaf047SAppaRao Puli { 8235fe4ef35SMyung Bae subValue->userSub->customText = *context; 824e5aaf047SAppaRao Puli } 825e5aaf047SAppaRao Puli 826e5aaf047SAppaRao Puli if (headers) 827e5aaf047SAppaRao Puli { 828601c71aeSEd Tanous boost::beast::http::fields fields; 82978d4ec4fSEd Tanous for (const nlohmann::json::object_t& headerChunk : *headers) 830601c71aeSEd Tanous { 83178d4ec4fSEd Tanous for (const auto& it : headerChunk) 832601c71aeSEd Tanous { 833601c71aeSEd Tanous const std::string* value = 83478d4ec4fSEd Tanous it.second.get_ptr<const std::string*>(); 835601c71aeSEd Tanous if (value == nullptr) 836601c71aeSEd Tanous { 837601c71aeSEd Tanous messages::propertyValueFormatError( 83878d4ec4fSEd Tanous asyncResp->res, it.second, 83978d4ec4fSEd Tanous "HttpHeaders/" + it.first); 840601c71aeSEd Tanous return; 841601c71aeSEd Tanous } 84278d4ec4fSEd Tanous fields.set(it.first, *value); 843601c71aeSEd Tanous } 844601c71aeSEd Tanous } 8455fe4ef35SMyung Bae subValue->userSub->httpHeaders = std::move(fields); 846e5aaf047SAppaRao Puli } 847e5aaf047SAppaRao Puli 848e5aaf047SAppaRao Puli if (retryPolicy) 849e5aaf047SAppaRao Puli { 850bd79bce8SPatrick Williams if (std::ranges::find(supportedRetryPolicies, 851bd79bce8SPatrick Williams *retryPolicy) == 8523544d2a7SEd Tanous supportedRetryPolicies.end()) 853e5aaf047SAppaRao Puli { 854bd79bce8SPatrick Williams messages::propertyValueNotInList(asyncResp->res, 855bd79bce8SPatrick Williams *retryPolicy, 856e5aaf047SAppaRao Puli "DeliveryRetryPolicy"); 857e5aaf047SAppaRao Puli return; 858e5aaf047SAppaRao Puli } 8595fe4ef35SMyung Bae subValue->userSub->retryPolicy = *retryPolicy; 860e5aaf047SAppaRao Puli } 861e5aaf047SAppaRao Puli 862*5064a25bSMyung Bae if (sendHeartbeat) 863*5064a25bSMyung Bae { 864*5064a25bSMyung Bae subValue->userSub->sendHeartbeat = *sendHeartbeat; 865*5064a25bSMyung Bae } 866*5064a25bSMyung Bae if (hbIntervalMinutes) 867*5064a25bSMyung Bae { 868*5064a25bSMyung Bae if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535) 869*5064a25bSMyung Bae { 870*5064a25bSMyung Bae messages::propertyValueOutOfRange( 871*5064a25bSMyung Bae asyncResp->res, *hbIntervalMinutes, 872*5064a25bSMyung Bae "HeartbeatIntervalMinutes"); 873*5064a25bSMyung Bae return; 874*5064a25bSMyung Bae } 875*5064a25bSMyung Bae subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes; 876*5064a25bSMyung Bae } 877*5064a25bSMyung Bae 87819bb362bSEd Tanous if (verifyCertificate) 87919bb362bSEd Tanous { 8805fe4ef35SMyung Bae subValue->userSub->verifyCertificate = *verifyCertificate; 88119bb362bSEd Tanous } 88219bb362bSEd Tanous 883b52664e2SAppaRao Puli EventServiceManager::getInstance().updateSubscriptionData(); 8847e860f15SJohn Edward Broadbent }); 8859d41aec6SRavi Teja BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/") 886ed398213SEd Tanous // The below privilege is wrong, it should be ConfigureManager OR 887ed398213SEd Tanous // ConfigureSelf 8887eeafa76SAbhishek Patel // https://github.com/openbmc/bmcweb/issues/220 889ed398213SEd Tanous //.privileges(redfish::privileges::deleteEventDestination) 890432a890cSEd Tanous .privileges({{"ConfigureManager"}}) 8917e860f15SJohn Edward Broadbent .methods(boost::beast::http::verb::delete_)( 89245ca1b86SEd Tanous [&app](const crow::Request& req, 8937e860f15SJohn Edward Broadbent const std::shared_ptr<bmcweb::AsyncResp>& asyncResp, 8947e860f15SJohn Edward Broadbent const std::string& param) { 8953ba00073SCarson Labrado if (!redfish::setUpRedfishRoute(app, req, asyncResp)) 89645ca1b86SEd Tanous { 89745ca1b86SEd Tanous return; 89845ca1b86SEd Tanous } 8994b712a29SEd Tanous EventServiceManager& event = EventServiceManager::getInstance(); 9003d30708fSChicago Duan if (param.starts_with("snmp")) 9013d30708fSChicago Duan { 9023d30708fSChicago Duan deleteSnmpTrapClient(asyncResp, param); 9034b712a29SEd Tanous event.deleteSubscription(param); 9043d30708fSChicago Duan return; 9053d30708fSChicago Duan } 9063d30708fSChicago Duan 9074b712a29SEd Tanous if (!event.deleteSubscription(param)) 908e5aaf047SAppaRao Puli { 9094b712a29SEd Tanous messages::resourceNotFound(asyncResp->res, 9104b712a29SEd Tanous "EventDestination", param); 911e5aaf047SAppaRao Puli return; 912e5aaf047SAppaRao Puli } 9134b712a29SEd Tanous messages::success(asyncResp->res); 9147e860f15SJohn Edward Broadbent }); 915e5aaf047SAppaRao Puli } 916e5aaf047SAppaRao Puli 917e5aaf047SAppaRao Puli } // namespace redfish 918