xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision a14c9113226dcae33a36eb4e50abbcc28be998ae)
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"
233ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
243d30708fSChicago Duan #include "snmp_trap_event_clients.hpp"
25e5aaf047SAppaRao Puli 
26601c71aeSEd Tanous #include <boost/beast/http/fields.hpp>
273d30708fSChicago Duan #include <boost/system/error_code.hpp>
28a716aa74SEd Tanous #include <boost/url/parse.hpp>
293d30708fSChicago Duan #include <sdbusplus/unpack_properties.hpp>
303d30708fSChicago Duan #include <utils/dbus_utils.hpp>
31ed398213SEd Tanous 
323d30708fSChicago Duan #include <charconv>
333d30708fSChicago Duan #include <memory>
343544d2a7SEd Tanous #include <ranges>
351e270c5fSPatrick Williams #include <span>
363d30708fSChicago Duan #include <string>
37*a14c9113SEd Tanous #include <vector>
381e270c5fSPatrick Williams 
39e5aaf047SAppaRao Puli namespace redfish
40e5aaf047SAppaRao Puli {
41e5aaf047SAppaRao Puli 
42156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
43156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
44e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
45b304bd79SP Dheeraj Srujan Kumar     "Base", "OpenBMC", "TaskEvent"};
46e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
47e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
48e5aaf047SAppaRao Puli 
49e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = {
50e56f254cSSunitha Harish     "Task"};
51e56f254cSSunitha Harish 
527e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app)
53e5aaf047SAppaRao Puli {
547e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
55ed398213SEd Tanous         .privileges(redfish::privileges::getEventService)
56bd79bce8SPatrick Williams         .methods(
57bd79bce8SPatrick Williams             boost::beast::http::verb::
58bd79bce8SPatrick Williams                 get)([&app](
59bd79bce8SPatrick Williams                          const crow::Request& req,
60002d39b4SEd Tanous                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
613ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
6245ca1b86SEd Tanous             {
6345ca1b86SEd Tanous                 return;
6445ca1b86SEd Tanous             }
651476687dSEd Tanous 
661476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
671476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
681476687dSEd Tanous                 "#EventService.v1_5_0.EventService";
691476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = "EventService";
701476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "Event Service";
715e44e3d8SAppaRao Puli             asyncResp->res.jsonValue["ServerSentEventUri"] =
725e44e3d8SAppaRao Puli                 "/redfish/v1/EventService/SSE";
735e44e3d8SAppaRao Puli 
741476687dSEd Tanous             asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
751476687dSEd Tanous                 "/redfish/v1/EventService/Subscriptions";
76bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"]
77bd79bce8SPatrick Williams                                     ["target"] =
781476687dSEd Tanous                 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
79e5aaf047SAppaRao Puli 
8028afb49cSJunLin Chen             const persistent_data::EventServiceConfig eventServiceConfig =
8128afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
8228afb49cSJunLin Chen                     .getEventServiceConfig();
837d1cc387SAppaRao Puli 
847d1cc387SAppaRao Puli             asyncResp->res.jsonValue["Status"]["State"] =
8528afb49cSJunLin Chen                 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
86bd79bce8SPatrick Williams             asyncResp->res.jsonValue["ServiceEnabled"] =
87bd79bce8SPatrick Williams                 eventServiceConfig.enabled;
887e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
8928afb49cSJunLin Chen                 eventServiceConfig.retryAttempts;
90e5aaf047SAppaRao Puli             asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
9128afb49cSJunLin Chen                 eventServiceConfig.retryTimeoutInterval;
92bd79bce8SPatrick Williams             asyncResp->res.jsonValue["EventFormatTypes"] =
93bd79bce8SPatrick Williams                 supportedEvtFormatTypes;
940fda0f12SGeorge Liu             asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
950fda0f12SGeorge Liu             asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
9607941a88SAyushi Smriti 
97613dabeaSEd Tanous             nlohmann::json::object_t supportedSSEFilters;
98613dabeaSEd Tanous             supportedSSEFilters["EventFormatType"] = true;
99613dabeaSEd Tanous             supportedSSEFilters["MessageId"] = true;
100613dabeaSEd Tanous             supportedSSEFilters["MetricReportDefinition"] = true;
101613dabeaSEd Tanous             supportedSSEFilters["RegistryPrefix"] = true;
102613dabeaSEd Tanous             supportedSSEFilters["OriginResource"] = false;
103613dabeaSEd Tanous             supportedSSEFilters["ResourceType"] = false;
10407941a88SAyushi Smriti 
10507941a88SAyushi Smriti             asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
106613dabeaSEd Tanous                 std::move(supportedSSEFilters);
1077e860f15SJohn Edward Broadbent         });
108e5aaf047SAppaRao Puli 
1097e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
110ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
1117e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
11245ca1b86SEd Tanous             [&app](const crow::Request& req,
11345ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1143ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
115e5aaf047SAppaRao Puli                 {
11645ca1b86SEd Tanous                     return;
11745ca1b86SEd Tanous                 }
118e5aaf047SAppaRao Puli                 std::optional<bool> serviceEnabled;
119e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryAttemps;
120e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryInterval;
121e5aaf047SAppaRao Puli 
12215ed6780SWilly Tu                 if (!json_util::readJsonPatch(
1237e860f15SJohn Edward Broadbent                         req, asyncResp->res, "ServiceEnabled", serviceEnabled,
1247e860f15SJohn Edward Broadbent                         "DeliveryRetryAttempts", retryAttemps,
1257e860f15SJohn Edward Broadbent                         "DeliveryRetryIntervalSeconds", retryInterval))
126e5aaf047SAppaRao Puli                 {
127e5aaf047SAppaRao Puli                     return;
128e5aaf047SAppaRao Puli                 }
129e5aaf047SAppaRao Puli 
13028afb49cSJunLin Chen                 persistent_data::EventServiceConfig eventServiceConfig =
13128afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
13228afb49cSJunLin Chen                         .getEventServiceConfig();
1337d1cc387SAppaRao Puli 
134e5aaf047SAppaRao Puli                 if (serviceEnabled)
135e5aaf047SAppaRao Puli                 {
13628afb49cSJunLin Chen                     eventServiceConfig.enabled = *serviceEnabled;
137e5aaf047SAppaRao Puli                 }
138e5aaf047SAppaRao Puli 
139e5aaf047SAppaRao Puli                 if (retryAttemps)
140e5aaf047SAppaRao Puli                 {
141e5aaf047SAppaRao Puli                     // Supported range [1-3]
142e5aaf047SAppaRao Puli                     if ((*retryAttemps < 1) || (*retryAttemps > 3))
143e5aaf047SAppaRao Puli                     {
144e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
145e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryAttemps),
146e5aaf047SAppaRao Puli                             "DeliveryRetryAttempts", "[1-3]");
147e5aaf047SAppaRao Puli                     }
148e5aaf047SAppaRao Puli                     else
149e5aaf047SAppaRao Puli                     {
15028afb49cSJunLin Chen                         eventServiceConfig.retryAttempts = *retryAttemps;
151e5aaf047SAppaRao Puli                     }
152e5aaf047SAppaRao Puli                 }
153e5aaf047SAppaRao Puli 
154e5aaf047SAppaRao Puli                 if (retryInterval)
155e5aaf047SAppaRao Puli                 {
15633a32b34SGunnar Mills                     // Supported range [5 - 180]
15733a32b34SGunnar Mills                     if ((*retryInterval < 5) || (*retryInterval > 180))
158e5aaf047SAppaRao Puli                     {
159e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
160e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryInterval),
16133a32b34SGunnar Mills                             "DeliveryRetryIntervalSeconds", "[5-180]");
162e5aaf047SAppaRao Puli                     }
163e5aaf047SAppaRao Puli                     else
164e5aaf047SAppaRao Puli                     {
165bd79bce8SPatrick Williams                         eventServiceConfig.retryTimeoutInterval =
166bd79bce8SPatrick Williams                             *retryInterval;
167e5aaf047SAppaRao Puli                     }
168e5aaf047SAppaRao Puli                 }
169e5aaf047SAppaRao Puli 
1707d1cc387SAppaRao Puli                 EventServiceManager::getInstance().setEventServiceConfig(
17128afb49cSJunLin Chen                     eventServiceConfig);
1727e860f15SJohn Edward Broadbent             });
1730b4bdd93SAppaRao Puli }
1740b4bdd93SAppaRao Puli 
1757e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1760b4bdd93SAppaRao Puli {
1777e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1787e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
179ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1807e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
18145ca1b86SEd Tanous             [&app](const crow::Request& req,
1827e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1833ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
18445ca1b86SEd Tanous                 {
18545ca1b86SEd Tanous                     return;
18645ca1b86SEd Tanous                 }
1876ba8c82eSsunharis_in                 if (!EventServiceManager::getInstance().sendTestEventLog())
1886ba8c82eSsunharis_in                 {
1896ba8c82eSsunharis_in                     messages::serviceDisabled(asyncResp->res,
1906ba8c82eSsunharis_in                                               "/redfish/v1/EventService/");
1916ba8c82eSsunharis_in                     return;
1926ba8c82eSsunharis_in                 }
1938d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
1947e860f15SJohn Edward Broadbent             });
195e5aaf047SAppaRao Puli }
196e5aaf047SAppaRao Puli 
1973d30708fSChicago Duan inline void doSubscriptionCollection(
198e81de512SEd Tanous     const boost::system::error_code& ec,
1993d30708fSChicago Duan     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2003d30708fSChicago Duan     const dbus::utility::ManagedObjectType& resp)
2013d30708fSChicago Duan {
2023d30708fSChicago Duan     if (ec)
2033d30708fSChicago Duan     {
2041306101eSEd Tanous         if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
2053d30708fSChicago Duan         {
2063d30708fSChicago Duan             // This is an optional process so just return if it isn't there
2073d30708fSChicago Duan             return;
2083d30708fSChicago Duan         }
2093d30708fSChicago Duan 
21062598e31SEd Tanous         BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
2113d30708fSChicago Duan         messages::internalError(asyncResp->res);
2123d30708fSChicago Duan         return;
2133d30708fSChicago Duan     }
2143d30708fSChicago Duan     nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
2153d30708fSChicago Duan     for (const auto& objpath : resp)
2163d30708fSChicago Duan     {
2173d30708fSChicago Duan         sdbusplus::message::object_path path(objpath.first);
2183d30708fSChicago Duan         const std::string snmpId = path.filename();
2193d30708fSChicago Duan         if (snmpId.empty())
2203d30708fSChicago Duan         {
22162598e31SEd Tanous             BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
2223d30708fSChicago Duan             messages::internalError(asyncResp->res);
2233d30708fSChicago Duan             return;
2243d30708fSChicago Duan         }
2253d30708fSChicago Duan 
2263d30708fSChicago Duan         getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
2273d30708fSChicago Duan     }
2283d30708fSChicago Duan }
2293d30708fSChicago Duan 
2307e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
231e5aaf047SAppaRao Puli {
2321ebe3e41SGayathri Leburu     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
233ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
2347e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
23545ca1b86SEd Tanous             [&app](const crow::Request& req,
2367e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2373ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
23845ca1b86SEd Tanous                 {
23945ca1b86SEd Tanous                     return;
24045ca1b86SEd Tanous                 }
2411476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
2421476687dSEd Tanous                     "#EventDestinationCollection.EventDestinationCollection";
2431476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
2441476687dSEd Tanous                     "/redfish/v1/EventService/Subscriptions";
245bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Name"] =
246bd79bce8SPatrick Williams                     "Event Destination Collections";
247e5aaf047SAppaRao Puli 
248bd79bce8SPatrick Williams                 nlohmann::json& memberArray =
249bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["Members"];
250e5aaf047SAppaRao Puli 
251b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
252b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
253b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
254bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Members@odata.count"] =
255bd79bce8SPatrick Williams                     subscripIds.size();
256b52664e2SAppaRao Puli 
257b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
258e5aaf047SAppaRao Puli                 {
2591476687dSEd Tanous                     nlohmann::json::object_t member;
2603d30708fSChicago Duan                     member["@odata.id"] = boost::urls::format(
2613d30708fSChicago Duan                         "/redfish/v1/EventService/Subscriptions/{}" + id);
262b2ba3072SPatrick Williams                     memberArray.emplace_back(std::move(member));
263e5aaf047SAppaRao Puli                 }
2643d30708fSChicago Duan                 crow::connections::systemBus->async_method_call(
265e81de512SEd Tanous                     [asyncResp](const boost::system::error_code& ec,
2663d30708fSChicago Duan                                 const dbus::utility::ManagedObjectType& resp) {
2673d30708fSChicago Duan                         doSubscriptionCollection(ec, asyncResp, resp);
2683d30708fSChicago Duan                     },
2693d30708fSChicago Duan                     "xyz.openbmc_project.Network.SNMP",
2703d30708fSChicago Duan                     "/xyz/openbmc_project/network/snmp/manager",
2713d30708fSChicago Duan                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
2727e860f15SJohn Edward Broadbent             });
2733d30708fSChicago Duan 
2747e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
2757eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
276bd79bce8SPatrick Williams         .methods(
277bd79bce8SPatrick Williams             boost::beast::http::verb::
278bd79bce8SPatrick Williams                 post)([&app](
279bd79bce8SPatrick Williams                           const crow::Request& req,
2807e860f15SJohn Edward Broadbent                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2813ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
28245ca1b86SEd Tanous             {
28345ca1b86SEd Tanous                 return;
28445ca1b86SEd Tanous             }
285fffb8c1fSEd Tanous             if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
286fffb8c1fSEd Tanous                 maxNoOfSubscriptions)
287e5aaf047SAppaRao Puli             {
288e5aaf047SAppaRao Puli                 messages::eventSubscriptionLimitExceeded(asyncResp->res);
289e5aaf047SAppaRao Puli                 return;
290e5aaf047SAppaRao Puli             }
291e5aaf047SAppaRao Puli             std::string destUrl;
292e5aaf047SAppaRao Puli             std::string protocol;
29319bb362bSEd Tanous             std::optional<bool> verifyCertificate;
294e5aaf047SAppaRao Puli             std::optional<std::string> context;
295e5aaf047SAppaRao Puli             std::optional<std::string> subscriptionType;
29623a21a1cSEd Tanous             std::optional<std::string> eventFormatType2;
297e5aaf047SAppaRao Puli             std::optional<std::string> retryPolicy;
298e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> msgIds;
299e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> regPrefixes;
300*a14c9113SEd Tanous             std::optional<std::vector<std::string>> originResources;
301e56f254cSSunitha Harish             std::optional<std::vector<std::string>> resTypes;
30278d4ec4fSEd Tanous             std::optional<std::vector<nlohmann::json::object_t>> headers;
30378d4ec4fSEd Tanous             std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
304e5aaf047SAppaRao Puli 
30515ed6780SWilly Tu             if (!json_util::readJsonPatch(
306bd79bce8SPatrick Williams                     req, asyncResp->res, "Destination", destUrl, "Context",
307bd79bce8SPatrick Williams                     context, "Protocol", protocol, "SubscriptionType",
308bd79bce8SPatrick Williams                     subscriptionType, "EventFormatType", eventFormatType2,
309bd79bce8SPatrick Williams                     "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
310*a14c9113SEd Tanous                     "OriginResources", originResources, "MessageIds", msgIds,
311*a14c9113SEd Tanous                     "DeliveryRetryPolicy", retryPolicy,
312bd79bce8SPatrick Williams                     "MetricReportDefinitions", mrdJsonArray, "ResourceTypes",
313bd79bce8SPatrick Williams                     resTypes, "VerifyCertificate", verifyCertificate))
314e5aaf047SAppaRao Puli             {
315e5aaf047SAppaRao Puli                 return;
316e5aaf047SAppaRao Puli             }
317e5aaf047SAppaRao Puli 
318600af5f1SAppaRao Puli             // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
319600af5f1SAppaRao Puli             static constexpr const uint16_t maxDestinationSize = 2000;
320600af5f1SAppaRao Puli             if (destUrl.size() > maxDestinationSize)
321600af5f1SAppaRao Puli             {
322600af5f1SAppaRao Puli                 messages::stringValueTooLong(asyncResp->res, "Destination",
323600af5f1SAppaRao Puli                                              maxDestinationSize);
324600af5f1SAppaRao Puli                 return;
325600af5f1SAppaRao Puli             }
326600af5f1SAppaRao Puli 
327dd28ba82SAppaRao Puli             if (regPrefixes && msgIds)
328dd28ba82SAppaRao Puli             {
32926f6976fSEd Tanous                 if (!regPrefixes->empty() && !msgIds->empty())
330dd28ba82SAppaRao Puli                 {
331bd79bce8SPatrick Williams                     messages::propertyValueConflict(
332bd79bce8SPatrick Williams                         asyncResp->res, "MessageIds", "RegistryPrefixes");
333dd28ba82SAppaRao Puli                     return;
334dd28ba82SAppaRao Puli                 }
335dd28ba82SAppaRao Puli             }
336dd28ba82SAppaRao Puli 
3376fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
338a716aa74SEd Tanous                 boost::urls::parse_absolute_uri(destUrl);
339a716aa74SEd Tanous             if (!url)
340e5aaf047SAppaRao Puli             {
341bd79bce8SPatrick Williams                 BMCWEB_LOG_WARNING(
342bd79bce8SPatrick Williams                     "Failed to validate and split destination url");
343e5aaf047SAppaRao Puli                 messages::propertyValueFormatError(asyncResp->res, destUrl,
344e5aaf047SAppaRao Puli                                                    "Destination");
345e5aaf047SAppaRao Puli                 return;
346e5aaf047SAppaRao Puli             }
347a716aa74SEd Tanous             url->normalize();
348a716aa74SEd Tanous             crow::utility::setProtocolDefaults(*url, protocol);
349a716aa74SEd Tanous             crow::utility::setPortDefaults(*url);
350a716aa74SEd Tanous 
351a716aa74SEd Tanous             if (url->path().empty())
352a716aa74SEd Tanous             {
353a716aa74SEd Tanous                 url->set_path("/");
354a716aa74SEd Tanous             }
355a716aa74SEd Tanous 
356a716aa74SEd Tanous             if (url->has_userinfo())
357a716aa74SEd Tanous             {
358a716aa74SEd Tanous                 messages::propertyValueFormatError(asyncResp->res, destUrl,
359a716aa74SEd Tanous                                                    "Destination");
360a716aa74SEd Tanous                 return;
361a716aa74SEd Tanous             }
362b52664e2SAppaRao Puli 
3633d30708fSChicago Duan             if (protocol == "SNMPv2c")
3643d30708fSChicago Duan             {
3653d30708fSChicago Duan                 if (context)
3663d30708fSChicago Duan                 {
3673d30708fSChicago Duan                     messages::propertyValueConflict(asyncResp->res, "Context",
3683d30708fSChicago Duan                                                     "Protocol");
3693d30708fSChicago Duan                     return;
3703d30708fSChicago Duan                 }
3713d30708fSChicago Duan                 if (eventFormatType2)
3723d30708fSChicago Duan                 {
373bd79bce8SPatrick Williams                     messages::propertyValueConflict(
374bd79bce8SPatrick Williams                         asyncResp->res, "EventFormatType", "Protocol");
3753d30708fSChicago Duan                     return;
3763d30708fSChicago Duan                 }
3773d30708fSChicago Duan                 if (retryPolicy)
3783d30708fSChicago Duan                 {
379bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
380bd79bce8SPatrick Williams                                                     "RetryPolicy", "Protocol");
3813d30708fSChicago Duan                     return;
3823d30708fSChicago Duan                 }
3833d30708fSChicago Duan                 if (msgIds)
3843d30708fSChicago Duan                 {
385bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
386bd79bce8SPatrick Williams                                                     "MessageIds", "Protocol");
3873d30708fSChicago Duan                     return;
3883d30708fSChicago Duan                 }
3893d30708fSChicago Duan                 if (regPrefixes)
3903d30708fSChicago Duan                 {
391bd79bce8SPatrick Williams                     messages::propertyValueConflict(
392bd79bce8SPatrick Williams                         asyncResp->res, "RegistryPrefixes", "Protocol");
3933d30708fSChicago Duan                     return;
3943d30708fSChicago Duan                 }
3953d30708fSChicago Duan                 if (resTypes)
3963d30708fSChicago Duan                 {
397bd79bce8SPatrick Williams                     messages::propertyValueConflict(
398bd79bce8SPatrick Williams                         asyncResp->res, "ResourceTypes", "Protocol");
3993d30708fSChicago Duan                     return;
4003d30708fSChicago Duan                 }
4013d30708fSChicago Duan                 if (headers)
4023d30708fSChicago Duan                 {
403bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
404bd79bce8SPatrick Williams                                                     "HttpHeaders", "Protocol");
4053d30708fSChicago Duan                     return;
4063d30708fSChicago Duan                 }
4073d30708fSChicago Duan                 if (mrdJsonArray)
4083d30708fSChicago Duan                 {
4093d30708fSChicago Duan                     messages::propertyValueConflict(
4103d30708fSChicago Duan                         asyncResp->res, "MetricReportDefinitions", "Protocol");
4113d30708fSChicago Duan                     return;
4123d30708fSChicago Duan                 }
413a716aa74SEd Tanous                 if (url->scheme() != "snmp")
414a716aa74SEd Tanous                 {
415bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
416bd79bce8SPatrick Williams                                                     "Destination", "Protocol");
4173d30708fSChicago Duan                     return;
4183d30708fSChicago Duan                 }
4193d30708fSChicago Duan 
420a716aa74SEd Tanous                 addSnmpTrapClient(asyncResp, url->host_address(),
421a716aa74SEd Tanous                                   url->port_number());
422a716aa74SEd Tanous                 return;
423b52664e2SAppaRao Puli             }
4243d30708fSChicago Duan 
425a716aa74SEd Tanous             std::shared_ptr<Subscription> subValue =
426a716aa74SEd Tanous                 std::make_shared<Subscription>(*url, app.ioContext());
427b52664e2SAppaRao Puli 
428a716aa74SEd Tanous             subValue->destinationUrl = std::move(*url);
429e5aaf047SAppaRao Puli 
430e5aaf047SAppaRao Puli             if (subscriptionType)
431e5aaf047SAppaRao Puli             {
432e5aaf047SAppaRao Puli                 if (*subscriptionType != "RedfishEvent")
433e5aaf047SAppaRao Puli                 {
434fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
435fffb8c1fSEd Tanous                         asyncResp->res, *subscriptionType, "SubscriptionType");
436e5aaf047SAppaRao Puli                     return;
437e5aaf047SAppaRao Puli                 }
438b52664e2SAppaRao Puli                 subValue->subscriptionType = *subscriptionType;
439e5aaf047SAppaRao Puli             }
440e5aaf047SAppaRao Puli             else
441e5aaf047SAppaRao Puli             {
442b52664e2SAppaRao Puli                 subValue->subscriptionType = "RedfishEvent"; // Default
443e5aaf047SAppaRao Puli             }
444e5aaf047SAppaRao Puli 
445e5aaf047SAppaRao Puli             if (protocol != "Redfish")
446e5aaf047SAppaRao Puli             {
447e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, protocol,
448e5aaf047SAppaRao Puli                                                  "Protocol");
449e5aaf047SAppaRao Puli                 return;
450e5aaf047SAppaRao Puli             }
451b52664e2SAppaRao Puli             subValue->protocol = protocol;
452e5aaf047SAppaRao Puli 
45319bb362bSEd Tanous             if (verifyCertificate)
45419bb362bSEd Tanous             {
45519bb362bSEd Tanous                 subValue->verifyCertificate = *verifyCertificate;
45619bb362bSEd Tanous             }
45719bb362bSEd Tanous 
45823a21a1cSEd Tanous             if (eventFormatType2)
459e5aaf047SAppaRao Puli             {
460bd79bce8SPatrick Williams                 if (std::ranges::find(supportedEvtFormatTypes,
461bd79bce8SPatrick Williams                                       *eventFormatType2) ==
4623544d2a7SEd Tanous                     supportedEvtFormatTypes.end())
463e5aaf047SAppaRao Puli                 {
464fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
465fffb8c1fSEd Tanous                         asyncResp->res, *eventFormatType2, "EventFormatType");
466e5aaf047SAppaRao Puli                     return;
467e5aaf047SAppaRao Puli                 }
46823a21a1cSEd Tanous                 subValue->eventFormatType = *eventFormatType2;
469e5aaf047SAppaRao Puli             }
470e5aaf047SAppaRao Puli             else
471e5aaf047SAppaRao Puli             {
472e5aaf047SAppaRao Puli                 // If not specified, use default "Event"
47323a21a1cSEd Tanous                 subValue->eventFormatType = "Event";
474e5aaf047SAppaRao Puli             }
475e5aaf047SAppaRao Puli 
476e5aaf047SAppaRao Puli             if (context)
477e5aaf047SAppaRao Puli             {
4788ece0e45SEd Tanous                 // This value is selected arbitrarily.
479600af5f1SAppaRao Puli                 constexpr const size_t maxContextSize = 256;
480600af5f1SAppaRao Puli                 if (context->size() > maxContextSize)
481600af5f1SAppaRao Puli                 {
482600af5f1SAppaRao Puli                     messages::stringValueTooLong(asyncResp->res, "Context",
483600af5f1SAppaRao Puli                                                  maxContextSize);
484600af5f1SAppaRao Puli                     return;
485600af5f1SAppaRao Puli                 }
486b52664e2SAppaRao Puli                 subValue->customText = *context;
487e5aaf047SAppaRao Puli             }
488e5aaf047SAppaRao Puli 
489e5aaf047SAppaRao Puli             if (headers)
490e5aaf047SAppaRao Puli             {
491600af5f1SAppaRao Puli                 size_t cumulativeLen = 0;
492600af5f1SAppaRao Puli 
49378d4ec4fSEd Tanous                 for (const nlohmann::json::object_t& headerChunk : *headers)
494601c71aeSEd Tanous                 {
49578d4ec4fSEd Tanous                     for (const auto& item : headerChunk)
49678d4ec4fSEd Tanous                     {
49778d4ec4fSEd Tanous                         const std::string* value =
49878d4ec4fSEd Tanous                             item.second.get_ptr<const std::string*>();
49978d4ec4fSEd Tanous                         if (value == nullptr)
50078d4ec4fSEd Tanous                         {
50178d4ec4fSEd Tanous                             messages::propertyValueFormatError(
50278d4ec4fSEd Tanous                                 asyncResp->res, item.second,
50378d4ec4fSEd Tanous                                 "HttpHeaders/" + item.first);
50478d4ec4fSEd Tanous                             return;
50578d4ec4fSEd Tanous                         }
50678d4ec4fSEd Tanous                         // Adding a new json value is the size of the key, +
50778d4ec4fSEd Tanous                         // the size of the value + 2 * 2 quotes for each, +
50878d4ec4fSEd Tanous                         // the colon and space between. example:
50978d4ec4fSEd Tanous                         // "key": "value"
51078d4ec4fSEd Tanous                         cumulativeLen += item.first.size() + value->size() + 6;
511600af5f1SAppaRao Puli                         // This value is selected to mirror http_connection.hpp
512600af5f1SAppaRao Puli                         constexpr const uint16_t maxHeaderSizeED = 8096;
513600af5f1SAppaRao Puli                         if (cumulativeLen > maxHeaderSizeED)
514600af5f1SAppaRao Puli                         {
51578d4ec4fSEd Tanous                             messages::arraySizeTooLong(
51678d4ec4fSEd Tanous                                 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
517600af5f1SAppaRao Puli                             return;
518600af5f1SAppaRao Puli                         }
51978d4ec4fSEd Tanous                         subValue->httpHeaders.set(item.first, *value);
520601c71aeSEd Tanous                     }
521601c71aeSEd Tanous                 }
522e5aaf047SAppaRao Puli             }
523e5aaf047SAppaRao Puli 
524e5aaf047SAppaRao Puli             if (regPrefixes)
525e5aaf047SAppaRao Puli             {
526e5aaf047SAppaRao Puli                 for (const std::string& it : *regPrefixes)
527e5aaf047SAppaRao Puli                 {
5283544d2a7SEd Tanous                     if (std::ranges::find(supportedRegPrefixes, it) ==
5293544d2a7SEd Tanous                         supportedRegPrefixes.end())
530e5aaf047SAppaRao Puli                     {
531fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
532fffb8c1fSEd Tanous                                                          "RegistryPrefixes");
533e5aaf047SAppaRao Puli                         return;
534e5aaf047SAppaRao Puli                     }
535e5aaf047SAppaRao Puli                 }
536b52664e2SAppaRao Puli                 subValue->registryPrefixes = *regPrefixes;
537e5aaf047SAppaRao Puli             }
538e5aaf047SAppaRao Puli 
539*a14c9113SEd Tanous             if (originResources)
540*a14c9113SEd Tanous             {
541*a14c9113SEd Tanous                 subValue->originResources = *originResources;
542*a14c9113SEd Tanous             }
543*a14c9113SEd Tanous 
544e56f254cSSunitha Harish             if (resTypes)
545e56f254cSSunitha Harish             {
546e56f254cSSunitha Harish                 for (const std::string& it : *resTypes)
547e56f254cSSunitha Harish                 {
5483544d2a7SEd Tanous                     if (std::ranges::find(supportedResourceTypes, it) ==
5493544d2a7SEd Tanous                         supportedResourceTypes.end())
550e56f254cSSunitha Harish                     {
551e56f254cSSunitha Harish                         messages::propertyValueNotInList(asyncResp->res, it,
552e56f254cSSunitha Harish                                                          "ResourceTypes");
553e56f254cSSunitha Harish                         return;
554e56f254cSSunitha Harish                     }
555e56f254cSSunitha Harish                 }
556e56f254cSSunitha Harish                 subValue->resourceTypes = *resTypes;
557e56f254cSSunitha Harish             }
558e56f254cSSunitha Harish 
559e5aaf047SAppaRao Puli             if (msgIds)
560e5aaf047SAppaRao Puli             {
561b304bd79SP Dheeraj Srujan Kumar                 std::vector<std::string> registryPrefix;
562b304bd79SP Dheeraj Srujan Kumar 
5637e860f15SJohn Edward Broadbent                 // If no registry prefixes are mentioned, consider all
5647e860f15SJohn Edward Broadbent                 // supported prefixes
565b304bd79SP Dheeraj Srujan Kumar                 if (subValue->registryPrefixes.empty())
566b304bd79SP Dheeraj Srujan Kumar                 {
567b304bd79SP Dheeraj Srujan Kumar                     registryPrefix.assign(supportedRegPrefixes.begin(),
568b304bd79SP Dheeraj Srujan Kumar                                           supportedRegPrefixes.end());
569b304bd79SP Dheeraj Srujan Kumar                 }
570b304bd79SP Dheeraj Srujan Kumar                 else
571b304bd79SP Dheeraj Srujan Kumar                 {
572b304bd79SP Dheeraj Srujan Kumar                     registryPrefix = subValue->registryPrefixes;
573b304bd79SP Dheeraj Srujan Kumar                 }
574b304bd79SP Dheeraj Srujan Kumar 
575b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& id : *msgIds)
576b304bd79SP Dheeraj Srujan Kumar                 {
577b304bd79SP Dheeraj Srujan Kumar                     bool validId = false;
578b304bd79SP Dheeraj Srujan Kumar 
579b304bd79SP Dheeraj Srujan Kumar                     // Check for Message ID in each of the selected Registry
580b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& it : registryPrefix)
581b304bd79SP Dheeraj Srujan Kumar                     {
582fffb8c1fSEd Tanous                         const std::span<const redfish::registries::MessageEntry>
583fffb8c1fSEd Tanous                             registry =
584fffb8c1fSEd Tanous                                 redfish::registries::getRegistryFromPrefix(it);
585b304bd79SP Dheeraj Srujan Kumar 
5863544d2a7SEd Tanous                         if (std::ranges::any_of(
5873544d2a7SEd Tanous                                 registry,
588fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
589fffb8c1fSEd Tanous                                           messageEntry) {
59055f79e6fSEd Tanous                                     return id == messageEntry.first;
591b304bd79SP Dheeraj Srujan Kumar                                 }))
592b304bd79SP Dheeraj Srujan Kumar                         {
593b304bd79SP Dheeraj Srujan Kumar                             validId = true;
594b304bd79SP Dheeraj Srujan Kumar                             break;
595b304bd79SP Dheeraj Srujan Kumar                         }
596b304bd79SP Dheeraj Srujan Kumar                     }
597b304bd79SP Dheeraj Srujan Kumar 
598b304bd79SP Dheeraj Srujan Kumar                     if (!validId)
599b304bd79SP Dheeraj Srujan Kumar                     {
600b304bd79SP Dheeraj Srujan Kumar                         messages::propertyValueNotInList(asyncResp->res, id,
601b304bd79SP Dheeraj Srujan Kumar                                                          "MessageIds");
602b304bd79SP Dheeraj Srujan Kumar                         return;
603b304bd79SP Dheeraj Srujan Kumar                     }
604b304bd79SP Dheeraj Srujan Kumar                 }
605b304bd79SP Dheeraj Srujan Kumar 
606b52664e2SAppaRao Puli                 subValue->registryMsgIds = *msgIds;
607e5aaf047SAppaRao Puli             }
608e5aaf047SAppaRao Puli 
609e5aaf047SAppaRao Puli             if (retryPolicy)
610e5aaf047SAppaRao Puli             {
6113544d2a7SEd Tanous                 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
6123544d2a7SEd Tanous                     supportedRetryPolicies.end())
613e5aaf047SAppaRao Puli                 {
614bd79bce8SPatrick Williams                     messages::propertyValueNotInList(
615bd79bce8SPatrick Williams                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
616e5aaf047SAppaRao Puli                     return;
617e5aaf047SAppaRao Puli                 }
618b52664e2SAppaRao Puli                 subValue->retryPolicy = *retryPolicy;
619e5aaf047SAppaRao Puli             }
620e5aaf047SAppaRao Puli             else
621e5aaf047SAppaRao Puli             {
622e5aaf047SAppaRao Puli                 // Default "TerminateAfterRetries"
623b52664e2SAppaRao Puli                 subValue->retryPolicy = "TerminateAfterRetries";
624e5aaf047SAppaRao Puli             }
625e5aaf047SAppaRao Puli 
626144b6318SAppaRao Puli             if (mrdJsonArray)
627156d6b00SAppaRao Puli             {
62878d4ec4fSEd Tanous                 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
629144b6318SAppaRao Puli                 {
630144b6318SAppaRao Puli                     std::string mrdUri;
631ea2e6eecSWilly Tu 
63278d4ec4fSEd Tanous                     if (!json_util::readJsonObject(mrdObj, asyncResp->res,
63378d4ec4fSEd Tanous                                                    "@odata.id", mrdUri))
634ea2e6eecSWilly Tu 
635144b6318SAppaRao Puli                     {
636144b6318SAppaRao Puli                         return;
637144b6318SAppaRao Puli                     }
638ea2e6eecSWilly Tu                     subValue->metricReportDefinitions.emplace_back(mrdUri);
639144b6318SAppaRao Puli                 }
640156d6b00SAppaRao Puli             }
641156d6b00SAppaRao Puli 
642b52664e2SAppaRao Puli             std::string id =
643bd79bce8SPatrick Williams                 EventServiceManager::getInstance().addPushSubscription(
644bd79bce8SPatrick Williams                     subValue);
645b52664e2SAppaRao Puli             if (id.empty())
646e5aaf047SAppaRao Puli             {
647e5aaf047SAppaRao Puli                 messages::internalError(asyncResp->res);
648e5aaf047SAppaRao Puli                 return;
649e5aaf047SAppaRao Puli             }
650e5aaf047SAppaRao Puli 
651e5aaf047SAppaRao Puli             messages::created(asyncResp->res);
652e5aaf047SAppaRao Puli             asyncResp->res.addHeader(
653e5aaf047SAppaRao Puli                 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
6547e860f15SJohn Edward Broadbent         });
655e5aaf047SAppaRao Puli }
656e5aaf047SAppaRao Puli 
6577e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
658e5aaf047SAppaRao Puli {
6599d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
660ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
6617e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
66245ca1b86SEd Tanous             [&app](const crow::Request& req,
6637e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6647e860f15SJohn Edward Broadbent                    const std::string& param) {
6653ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
66645ca1b86SEd Tanous                 {
66745ca1b86SEd Tanous                     return;
66845ca1b86SEd Tanous                 }
6693d30708fSChicago Duan 
6703d30708fSChicago Duan                 if (param.starts_with("snmp"))
6713d30708fSChicago Duan                 {
6723d30708fSChicago Duan                     getSnmpTrapClient(asyncResp, param);
6733d30708fSChicago Duan                     return;
6743d30708fSChicago Duan                 }
6753d30708fSChicago Duan 
676b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
6777e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
678b52664e2SAppaRao Puli                 if (subValue == nullptr)
679e5aaf047SAppaRao Puli                 {
680bd79bce8SPatrick Williams                     asyncResp->res.result(
681bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
682e5aaf047SAppaRao Puli                     return;
683e5aaf047SAppaRao Puli                 }
6847e860f15SJohn Edward Broadbent                 const std::string& id = param;
685e5aaf047SAppaRao Puli 
6861476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
6878759961cSMyung Bae                     "#EventDestination.v1_14_1.EventDestination";
688539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Protocol"] =
689539d8c6bSEd Tanous                     event_destination::EventDestinationProtocol::Redfish;
6903b32780dSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
6913b32780dSEd Tanous                     "/redfish/v1/EventService/Subscriptions/{}", id);
692e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Id"] = id;
693e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
694bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Destination"] =
695bd79bce8SPatrick Williams                     subValue->destinationUrl;
696b52664e2SAppaRao Puli                 asyncResp->res.jsonValue["Context"] = subValue->customText;
697e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["SubscriptionType"] =
698b52664e2SAppaRao Puli                     subValue->subscriptionType;
699bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["HttpHeaders"] =
700bd79bce8SPatrick Williams                     nlohmann::json::array();
701bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["EventFormatType"] =
702bd79bce8SPatrick Williams                     subValue->eventFormatType;
703e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["RegistryPrefixes"] =
704b52664e2SAppaRao Puli                     subValue->registryPrefixes;
705bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["ResourceTypes"] =
706bd79bce8SPatrick Williams                     subValue->resourceTypes;
707e56f254cSSunitha Harish 
708bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["MessageIds"] =
709bd79bce8SPatrick Williams                     subValue->registryMsgIds;
710bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
711bd79bce8SPatrick Williams                     subValue->retryPolicy;
71219bb362bSEd Tanous                 asyncResp->res.jsonValue["VerifyCertificate"] =
71319bb362bSEd Tanous                     subValue->verifyCertificate;
714144b6318SAppaRao Puli 
7151476687dSEd Tanous                 nlohmann::json::array_t mrdJsonArray;
716144b6318SAppaRao Puli                 for (const auto& mdrUri : subValue->metricReportDefinitions)
717144b6318SAppaRao Puli                 {
7181476687dSEd Tanous                     nlohmann::json::object_t mdr;
7191476687dSEd Tanous                     mdr["@odata.id"] = mdrUri;
7201476687dSEd Tanous                     mrdJsonArray.emplace_back(std::move(mdr));
721144b6318SAppaRao Puli                 }
722bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["MetricReportDefinitions"] =
723bd79bce8SPatrick Williams                     mrdJsonArray;
7247e860f15SJohn Edward Broadbent             });
7259d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
726ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
727ed398213SEd Tanous         // ConfigureSelf
7287eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
729ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
730432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
7317e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
73245ca1b86SEd Tanous             [&app](const crow::Request& req,
7337e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7347e860f15SJohn Edward Broadbent                    const std::string& param) {
7353ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
73645ca1b86SEd Tanous                 {
73745ca1b86SEd Tanous                     return;
73845ca1b86SEd Tanous                 }
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                 }
747e5aaf047SAppaRao Puli 
748e5aaf047SAppaRao Puli                 std::optional<std::string> context;
749e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
75019bb362bSEd Tanous                 std::optional<bool> verifyCertificate;
75178d4ec4fSEd Tanous                 std::optional<std::vector<nlohmann::json::object_t>> headers;
752e5aaf047SAppaRao Puli 
753bd79bce8SPatrick Williams                 if (!json_util::readJsonPatch(
754bd79bce8SPatrick Williams                         req, asyncResp->res, "Context", context,
75519bb362bSEd Tanous                         "VerifyCertificate", verifyCertificate,
756bd79bce8SPatrick Williams                         "DeliveryRetryPolicy", retryPolicy, "HttpHeaders",
757bd79bce8SPatrick Williams                         headers))
758e5aaf047SAppaRao Puli                 {
759e5aaf047SAppaRao Puli                     return;
760e5aaf047SAppaRao Puli                 }
761e5aaf047SAppaRao Puli 
762e5aaf047SAppaRao Puli                 if (context)
763e5aaf047SAppaRao Puli                 {
764b52664e2SAppaRao Puli                     subValue->customText = *context;
765e5aaf047SAppaRao Puli                 }
766e5aaf047SAppaRao Puli 
767e5aaf047SAppaRao Puli                 if (headers)
768e5aaf047SAppaRao Puli                 {
769601c71aeSEd Tanous                     boost::beast::http::fields fields;
77078d4ec4fSEd Tanous                     for (const nlohmann::json::object_t& headerChunk : *headers)
771601c71aeSEd Tanous                     {
77278d4ec4fSEd Tanous                         for (const auto& it : headerChunk)
773601c71aeSEd Tanous                         {
774601c71aeSEd Tanous                             const std::string* value =
77578d4ec4fSEd Tanous                                 it.second.get_ptr<const std::string*>();
776601c71aeSEd Tanous                             if (value == nullptr)
777601c71aeSEd Tanous                             {
778601c71aeSEd Tanous                                 messages::propertyValueFormatError(
77978d4ec4fSEd Tanous                                     asyncResp->res, it.second,
78078d4ec4fSEd Tanous                                     "HttpHeaders/" + it.first);
781601c71aeSEd Tanous                                 return;
782601c71aeSEd Tanous                             }
78378d4ec4fSEd Tanous                             fields.set(it.first, *value);
784601c71aeSEd Tanous                         }
785601c71aeSEd Tanous                     }
78678d4ec4fSEd Tanous                     subValue->httpHeaders = std::move(fields);
787e5aaf047SAppaRao Puli                 }
788e5aaf047SAppaRao Puli 
789e5aaf047SAppaRao Puli                 if (retryPolicy)
790e5aaf047SAppaRao Puli                 {
791bd79bce8SPatrick Williams                     if (std::ranges::find(supportedRetryPolicies,
792bd79bce8SPatrick Williams                                           *retryPolicy) ==
7933544d2a7SEd Tanous                         supportedRetryPolicies.end())
794e5aaf047SAppaRao Puli                     {
795bd79bce8SPatrick Williams                         messages::propertyValueNotInList(asyncResp->res,
796bd79bce8SPatrick Williams                                                          *retryPolicy,
797e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
798e5aaf047SAppaRao Puli                         return;
799e5aaf047SAppaRao Puli                     }
800b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
801e5aaf047SAppaRao Puli                 }
802e5aaf047SAppaRao Puli 
80319bb362bSEd Tanous                 if (verifyCertificate)
80419bb362bSEd Tanous                 {
80519bb362bSEd Tanous                     subValue->verifyCertificate = *verifyCertificate;
80619bb362bSEd Tanous                 }
80719bb362bSEd Tanous 
808b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
8097e860f15SJohn Edward Broadbent             });
8109d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
811ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
812ed398213SEd Tanous         // ConfigureSelf
8137eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
814ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
815432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
8167e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
81745ca1b86SEd Tanous             [&app](const crow::Request& req,
8187e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8197e860f15SJohn Edward Broadbent                    const std::string& param) {
8203ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
82145ca1b86SEd Tanous                 {
82245ca1b86SEd Tanous                     return;
82345ca1b86SEd Tanous                 }
8243d30708fSChicago Duan 
8253d30708fSChicago Duan                 if (param.starts_with("snmp"))
8263d30708fSChicago Duan                 {
8273d30708fSChicago Duan                     deleteSnmpTrapClient(asyncResp, param);
828bd79bce8SPatrick Williams                     EventServiceManager::getInstance().deleteSubscription(
829bd79bce8SPatrick Williams                         param);
8303d30708fSChicago Duan                     return;
8313d30708fSChicago Duan                 }
8323d30708fSChicago Duan 
833bd79bce8SPatrick Williams                 if (!EventServiceManager::getInstance().isSubscriptionExist(
834bd79bce8SPatrick Williams                         param))
835e5aaf047SAppaRao Puli                 {
836bd79bce8SPatrick Williams                     asyncResp->res.result(
837bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
838e5aaf047SAppaRao Puli                     return;
839e5aaf047SAppaRao Puli                 }
8407e860f15SJohn Edward Broadbent                 EventServiceManager::getInstance().deleteSubscription(param);
8417e860f15SJohn Edward Broadbent             });
842e5aaf047SAppaRao Puli }
843e5aaf047SAppaRao Puli 
844e5aaf047SAppaRao Puli } // namespace redfish
845