xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision 4b712a29debc1a0860cc04850b262203cad402a5)
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>
37a14c9113SEd 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;
300a14c9113SEd 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 
305*4b712a29SEd Tanous             // clang-format off
30615ed6780SWilly Tu             if (!json_util::readJsonPatch(
307*4b712a29SEd Tanous                     req, asyncResp->res,
308*4b712a29SEd Tanous                     "Context", context,
309a14c9113SEd Tanous                     "DeliveryRetryPolicy", retryPolicy,
310*4b712a29SEd Tanous                     "Destination", destUrl,
311*4b712a29SEd Tanous                     "EventFormatType", eventFormatType2,
312*4b712a29SEd Tanous                     "HttpHeaders", headers,
313*4b712a29SEd Tanous                     "MessageIds", msgIds,
314*4b712a29SEd Tanous                     "MetricReportDefinitions", mrdJsonArray,
315*4b712a29SEd Tanous                     "OriginResources", originResources,
316*4b712a29SEd Tanous                     "Protocol", protocol,
317*4b712a29SEd Tanous                     "RegistryPrefixes", regPrefixes,
318*4b712a29SEd Tanous                     "ResourceTypes", resTypes,
319*4b712a29SEd Tanous                     "SubscriptionType", subscriptionType,
320*4b712a29SEd Tanous                     "VerifyCertificate", verifyCertificate
321*4b712a29SEd Tanous             ))
322e5aaf047SAppaRao Puli             {
323e5aaf047SAppaRao Puli                 return;
324e5aaf047SAppaRao Puli             }
325*4b712a29SEd Tanous             // clang-format on
326e5aaf047SAppaRao Puli 
327600af5f1SAppaRao Puli             // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
328600af5f1SAppaRao Puli             static constexpr const uint16_t maxDestinationSize = 2000;
329600af5f1SAppaRao Puli             if (destUrl.size() > maxDestinationSize)
330600af5f1SAppaRao Puli             {
331600af5f1SAppaRao Puli                 messages::stringValueTooLong(asyncResp->res, "Destination",
332600af5f1SAppaRao Puli                                              maxDestinationSize);
333600af5f1SAppaRao Puli                 return;
334600af5f1SAppaRao Puli             }
335600af5f1SAppaRao Puli 
336dd28ba82SAppaRao Puli             if (regPrefixes && msgIds)
337dd28ba82SAppaRao Puli             {
33826f6976fSEd Tanous                 if (!regPrefixes->empty() && !msgIds->empty())
339dd28ba82SAppaRao Puli                 {
340bd79bce8SPatrick Williams                     messages::propertyValueConflict(
341bd79bce8SPatrick Williams                         asyncResp->res, "MessageIds", "RegistryPrefixes");
342dd28ba82SAppaRao Puli                     return;
343dd28ba82SAppaRao Puli                 }
344dd28ba82SAppaRao Puli             }
345dd28ba82SAppaRao Puli 
3466fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
347a716aa74SEd Tanous                 boost::urls::parse_absolute_uri(destUrl);
348a716aa74SEd Tanous             if (!url)
349e5aaf047SAppaRao Puli             {
350bd79bce8SPatrick Williams                 BMCWEB_LOG_WARNING(
351bd79bce8SPatrick Williams                     "Failed to validate and split destination url");
352e5aaf047SAppaRao Puli                 messages::propertyValueFormatError(asyncResp->res, destUrl,
353e5aaf047SAppaRao Puli                                                    "Destination");
354e5aaf047SAppaRao Puli                 return;
355e5aaf047SAppaRao Puli             }
356a716aa74SEd Tanous             url->normalize();
357a716aa74SEd Tanous             crow::utility::setProtocolDefaults(*url, protocol);
358a716aa74SEd Tanous             crow::utility::setPortDefaults(*url);
359a716aa74SEd Tanous 
360a716aa74SEd Tanous             if (url->path().empty())
361a716aa74SEd Tanous             {
362a716aa74SEd Tanous                 url->set_path("/");
363a716aa74SEd Tanous             }
364a716aa74SEd Tanous 
365a716aa74SEd Tanous             if (url->has_userinfo())
366a716aa74SEd Tanous             {
367a716aa74SEd Tanous                 messages::propertyValueFormatError(asyncResp->res, destUrl,
368a716aa74SEd Tanous                                                    "Destination");
369a716aa74SEd Tanous                 return;
370a716aa74SEd Tanous             }
371b52664e2SAppaRao Puli 
3723d30708fSChicago Duan             if (protocol == "SNMPv2c")
3733d30708fSChicago Duan             {
3743d30708fSChicago Duan                 if (context)
3753d30708fSChicago Duan                 {
3763d30708fSChicago Duan                     messages::propertyValueConflict(asyncResp->res, "Context",
3773d30708fSChicago Duan                                                     "Protocol");
3783d30708fSChicago Duan                     return;
3793d30708fSChicago Duan                 }
3803d30708fSChicago Duan                 if (eventFormatType2)
3813d30708fSChicago Duan                 {
382bd79bce8SPatrick Williams                     messages::propertyValueConflict(
383bd79bce8SPatrick Williams                         asyncResp->res, "EventFormatType", "Protocol");
3843d30708fSChicago Duan                     return;
3853d30708fSChicago Duan                 }
3863d30708fSChicago Duan                 if (retryPolicy)
3873d30708fSChicago Duan                 {
388bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
389bd79bce8SPatrick Williams                                                     "RetryPolicy", "Protocol");
3903d30708fSChicago Duan                     return;
3913d30708fSChicago Duan                 }
3923d30708fSChicago Duan                 if (msgIds)
3933d30708fSChicago Duan                 {
394bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
395bd79bce8SPatrick Williams                                                     "MessageIds", "Protocol");
3963d30708fSChicago Duan                     return;
3973d30708fSChicago Duan                 }
3983d30708fSChicago Duan                 if (regPrefixes)
3993d30708fSChicago Duan                 {
400bd79bce8SPatrick Williams                     messages::propertyValueConflict(
401bd79bce8SPatrick Williams                         asyncResp->res, "RegistryPrefixes", "Protocol");
4023d30708fSChicago Duan                     return;
4033d30708fSChicago Duan                 }
4043d30708fSChicago Duan                 if (resTypes)
4053d30708fSChicago Duan                 {
406bd79bce8SPatrick Williams                     messages::propertyValueConflict(
407bd79bce8SPatrick Williams                         asyncResp->res, "ResourceTypes", "Protocol");
4083d30708fSChicago Duan                     return;
4093d30708fSChicago Duan                 }
4103d30708fSChicago Duan                 if (headers)
4113d30708fSChicago Duan                 {
412bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
413bd79bce8SPatrick Williams                                                     "HttpHeaders", "Protocol");
4143d30708fSChicago Duan                     return;
4153d30708fSChicago Duan                 }
4163d30708fSChicago Duan                 if (mrdJsonArray)
4173d30708fSChicago Duan                 {
4183d30708fSChicago Duan                     messages::propertyValueConflict(
4193d30708fSChicago Duan                         asyncResp->res, "MetricReportDefinitions", "Protocol");
4203d30708fSChicago Duan                     return;
4213d30708fSChicago Duan                 }
422a716aa74SEd Tanous                 if (url->scheme() != "snmp")
423a716aa74SEd Tanous                 {
424bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
425bd79bce8SPatrick Williams                                                     "Destination", "Protocol");
4263d30708fSChicago Duan                     return;
4273d30708fSChicago Duan                 }
4283d30708fSChicago Duan 
429a716aa74SEd Tanous                 addSnmpTrapClient(asyncResp, url->host_address(),
430a716aa74SEd Tanous                                   url->port_number());
431a716aa74SEd Tanous                 return;
432b52664e2SAppaRao Puli             }
4333d30708fSChicago Duan 
434a716aa74SEd Tanous             std::shared_ptr<Subscription> subValue =
435a716aa74SEd Tanous                 std::make_shared<Subscription>(*url, app.ioContext());
436b52664e2SAppaRao Puli 
437*4b712a29SEd Tanous             subValue->userSub.destinationUrl = std::move(*url);
438e5aaf047SAppaRao Puli 
439e5aaf047SAppaRao Puli             if (subscriptionType)
440e5aaf047SAppaRao Puli             {
441e5aaf047SAppaRao Puli                 if (*subscriptionType != "RedfishEvent")
442e5aaf047SAppaRao Puli                 {
443fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
444fffb8c1fSEd Tanous                         asyncResp->res, *subscriptionType, "SubscriptionType");
445e5aaf047SAppaRao Puli                     return;
446e5aaf047SAppaRao Puli                 }
447*4b712a29SEd Tanous                 subValue->userSub.subscriptionType = *subscriptionType;
448e5aaf047SAppaRao Puli             }
449e5aaf047SAppaRao Puli             else
450e5aaf047SAppaRao Puli             {
451*4b712a29SEd Tanous                 // Default
452*4b712a29SEd Tanous                 subValue->userSub.subscriptionType = "RedfishEvent";
453e5aaf047SAppaRao Puli             }
454e5aaf047SAppaRao Puli 
455e5aaf047SAppaRao Puli             if (protocol != "Redfish")
456e5aaf047SAppaRao Puli             {
457e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, protocol,
458e5aaf047SAppaRao Puli                                                  "Protocol");
459e5aaf047SAppaRao Puli                 return;
460e5aaf047SAppaRao Puli             }
461*4b712a29SEd Tanous             subValue->userSub.protocol = protocol;
462e5aaf047SAppaRao Puli 
46319bb362bSEd Tanous             if (verifyCertificate)
46419bb362bSEd Tanous             {
465*4b712a29SEd Tanous                 subValue->userSub.verifyCertificate = *verifyCertificate;
46619bb362bSEd Tanous             }
46719bb362bSEd Tanous 
46823a21a1cSEd Tanous             if (eventFormatType2)
469e5aaf047SAppaRao Puli             {
470bd79bce8SPatrick Williams                 if (std::ranges::find(supportedEvtFormatTypes,
471bd79bce8SPatrick Williams                                       *eventFormatType2) ==
4723544d2a7SEd Tanous                     supportedEvtFormatTypes.end())
473e5aaf047SAppaRao Puli                 {
474fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
475fffb8c1fSEd Tanous                         asyncResp->res, *eventFormatType2, "EventFormatType");
476e5aaf047SAppaRao Puli                     return;
477e5aaf047SAppaRao Puli                 }
478*4b712a29SEd Tanous                 subValue->userSub.eventFormatType = *eventFormatType2;
479e5aaf047SAppaRao Puli             }
480e5aaf047SAppaRao Puli             else
481e5aaf047SAppaRao Puli             {
482e5aaf047SAppaRao Puli                 // If not specified, use default "Event"
483*4b712a29SEd Tanous                 subValue->userSub.eventFormatType = "Event";
484e5aaf047SAppaRao Puli             }
485e5aaf047SAppaRao Puli 
486e5aaf047SAppaRao Puli             if (context)
487e5aaf047SAppaRao Puli             {
4888ece0e45SEd Tanous                 // This value is selected arbitrarily.
489600af5f1SAppaRao Puli                 constexpr const size_t maxContextSize = 256;
490600af5f1SAppaRao Puli                 if (context->size() > maxContextSize)
491600af5f1SAppaRao Puli                 {
492600af5f1SAppaRao Puli                     messages::stringValueTooLong(asyncResp->res, "Context",
493600af5f1SAppaRao Puli                                                  maxContextSize);
494600af5f1SAppaRao Puli                     return;
495600af5f1SAppaRao Puli                 }
496*4b712a29SEd Tanous                 subValue->userSub.customText = *context;
497e5aaf047SAppaRao Puli             }
498e5aaf047SAppaRao Puli 
499e5aaf047SAppaRao Puli             if (headers)
500e5aaf047SAppaRao Puli             {
501600af5f1SAppaRao Puli                 size_t cumulativeLen = 0;
502600af5f1SAppaRao Puli 
50378d4ec4fSEd Tanous                 for (const nlohmann::json::object_t& headerChunk : *headers)
504601c71aeSEd Tanous                 {
50578d4ec4fSEd Tanous                     for (const auto& item : headerChunk)
50678d4ec4fSEd Tanous                     {
50778d4ec4fSEd Tanous                         const std::string* value =
50878d4ec4fSEd Tanous                             item.second.get_ptr<const std::string*>();
50978d4ec4fSEd Tanous                         if (value == nullptr)
51078d4ec4fSEd Tanous                         {
51178d4ec4fSEd Tanous                             messages::propertyValueFormatError(
51278d4ec4fSEd Tanous                                 asyncResp->res, item.second,
51378d4ec4fSEd Tanous                                 "HttpHeaders/" + item.first);
51478d4ec4fSEd Tanous                             return;
51578d4ec4fSEd Tanous                         }
51678d4ec4fSEd Tanous                         // Adding a new json value is the size of the key, +
51778d4ec4fSEd Tanous                         // the size of the value + 2 * 2 quotes for each, +
51878d4ec4fSEd Tanous                         // the colon and space between. example:
51978d4ec4fSEd Tanous                         // "key": "value"
52078d4ec4fSEd Tanous                         cumulativeLen += item.first.size() + value->size() + 6;
521600af5f1SAppaRao Puli                         // This value is selected to mirror http_connection.hpp
522600af5f1SAppaRao Puli                         constexpr const uint16_t maxHeaderSizeED = 8096;
523600af5f1SAppaRao Puli                         if (cumulativeLen > maxHeaderSizeED)
524600af5f1SAppaRao Puli                         {
52578d4ec4fSEd Tanous                             messages::arraySizeTooLong(
52678d4ec4fSEd Tanous                                 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
527600af5f1SAppaRao Puli                             return;
528600af5f1SAppaRao Puli                         }
529*4b712a29SEd Tanous                         subValue->userSub.httpHeaders.set(item.first, *value);
530601c71aeSEd Tanous                     }
531601c71aeSEd Tanous                 }
532e5aaf047SAppaRao Puli             }
533e5aaf047SAppaRao Puli 
534e5aaf047SAppaRao Puli             if (regPrefixes)
535e5aaf047SAppaRao Puli             {
536e5aaf047SAppaRao Puli                 for (const std::string& it : *regPrefixes)
537e5aaf047SAppaRao Puli                 {
5383544d2a7SEd Tanous                     if (std::ranges::find(supportedRegPrefixes, it) ==
5393544d2a7SEd Tanous                         supportedRegPrefixes.end())
540e5aaf047SAppaRao Puli                     {
541fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
542fffb8c1fSEd Tanous                                                          "RegistryPrefixes");
543e5aaf047SAppaRao Puli                         return;
544e5aaf047SAppaRao Puli                     }
545e5aaf047SAppaRao Puli                 }
546*4b712a29SEd Tanous                 subValue->userSub.registryPrefixes = *regPrefixes;
547e5aaf047SAppaRao Puli             }
548e5aaf047SAppaRao Puli 
549a14c9113SEd Tanous             if (originResources)
550a14c9113SEd Tanous             {
551*4b712a29SEd Tanous                 subValue->userSub.originResources = *originResources;
552a14c9113SEd Tanous             }
553a14c9113SEd Tanous 
554e56f254cSSunitha Harish             if (resTypes)
555e56f254cSSunitha Harish             {
556e56f254cSSunitha Harish                 for (const std::string& it : *resTypes)
557e56f254cSSunitha Harish                 {
5583544d2a7SEd Tanous                     if (std::ranges::find(supportedResourceTypes, it) ==
5593544d2a7SEd Tanous                         supportedResourceTypes.end())
560e56f254cSSunitha Harish                     {
561e56f254cSSunitha Harish                         messages::propertyValueNotInList(asyncResp->res, it,
562e56f254cSSunitha Harish                                                          "ResourceTypes");
563e56f254cSSunitha Harish                         return;
564e56f254cSSunitha Harish                     }
565e56f254cSSunitha Harish                 }
566*4b712a29SEd Tanous                 subValue->userSub.resourceTypes = *resTypes;
567e56f254cSSunitha Harish             }
568e56f254cSSunitha Harish 
569e5aaf047SAppaRao Puli             if (msgIds)
570e5aaf047SAppaRao Puli             {
571b304bd79SP Dheeraj Srujan Kumar                 std::vector<std::string> registryPrefix;
572b304bd79SP Dheeraj Srujan Kumar 
5737e860f15SJohn Edward Broadbent                 // If no registry prefixes are mentioned, consider all
5747e860f15SJohn Edward Broadbent                 // supported prefixes
575*4b712a29SEd Tanous                 if (subValue->userSub.registryPrefixes.empty())
576b304bd79SP Dheeraj Srujan Kumar                 {
577b304bd79SP Dheeraj Srujan Kumar                     registryPrefix.assign(supportedRegPrefixes.begin(),
578b304bd79SP Dheeraj Srujan Kumar                                           supportedRegPrefixes.end());
579b304bd79SP Dheeraj Srujan Kumar                 }
580b304bd79SP Dheeraj Srujan Kumar                 else
581b304bd79SP Dheeraj Srujan Kumar                 {
582*4b712a29SEd Tanous                     registryPrefix = subValue->userSub.registryPrefixes;
583b304bd79SP Dheeraj Srujan Kumar                 }
584b304bd79SP Dheeraj Srujan Kumar 
585b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& id : *msgIds)
586b304bd79SP Dheeraj Srujan Kumar                 {
587b304bd79SP Dheeraj Srujan Kumar                     bool validId = false;
588b304bd79SP Dheeraj Srujan Kumar 
589b304bd79SP Dheeraj Srujan Kumar                     // Check for Message ID in each of the selected Registry
590b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& it : registryPrefix)
591b304bd79SP Dheeraj Srujan Kumar                     {
592fffb8c1fSEd Tanous                         const std::span<const redfish::registries::MessageEntry>
593fffb8c1fSEd Tanous                             registry =
594fffb8c1fSEd Tanous                                 redfish::registries::getRegistryFromPrefix(it);
595b304bd79SP Dheeraj Srujan Kumar 
5963544d2a7SEd Tanous                         if (std::ranges::any_of(
5973544d2a7SEd Tanous                                 registry,
598fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
599fffb8c1fSEd Tanous                                           messageEntry) {
60055f79e6fSEd Tanous                                     return id == messageEntry.first;
601b304bd79SP Dheeraj Srujan Kumar                                 }))
602b304bd79SP Dheeraj Srujan Kumar                         {
603b304bd79SP Dheeraj Srujan Kumar                             validId = true;
604b304bd79SP Dheeraj Srujan Kumar                             break;
605b304bd79SP Dheeraj Srujan Kumar                         }
606b304bd79SP Dheeraj Srujan Kumar                     }
607b304bd79SP Dheeraj Srujan Kumar 
608b304bd79SP Dheeraj Srujan Kumar                     if (!validId)
609b304bd79SP Dheeraj Srujan Kumar                     {
610b304bd79SP Dheeraj Srujan Kumar                         messages::propertyValueNotInList(asyncResp->res, id,
611b304bd79SP Dheeraj Srujan Kumar                                                          "MessageIds");
612b304bd79SP Dheeraj Srujan Kumar                         return;
613b304bd79SP Dheeraj Srujan Kumar                     }
614b304bd79SP Dheeraj Srujan Kumar                 }
615b304bd79SP Dheeraj Srujan Kumar 
616*4b712a29SEd Tanous                 subValue->userSub.registryMsgIds = *msgIds;
617e5aaf047SAppaRao Puli             }
618e5aaf047SAppaRao Puli 
619e5aaf047SAppaRao Puli             if (retryPolicy)
620e5aaf047SAppaRao Puli             {
6213544d2a7SEd Tanous                 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
6223544d2a7SEd Tanous                     supportedRetryPolicies.end())
623e5aaf047SAppaRao Puli                 {
624bd79bce8SPatrick Williams                     messages::propertyValueNotInList(
625bd79bce8SPatrick Williams                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
626e5aaf047SAppaRao Puli                     return;
627e5aaf047SAppaRao Puli                 }
628*4b712a29SEd Tanous                 subValue->userSub.retryPolicy = *retryPolicy;
629e5aaf047SAppaRao Puli             }
630e5aaf047SAppaRao Puli             else
631e5aaf047SAppaRao Puli             {
632e5aaf047SAppaRao Puli                 // Default "TerminateAfterRetries"
633*4b712a29SEd Tanous                 subValue->userSub.retryPolicy = "TerminateAfterRetries";
634e5aaf047SAppaRao Puli             }
635e5aaf047SAppaRao Puli 
636144b6318SAppaRao Puli             if (mrdJsonArray)
637156d6b00SAppaRao Puli             {
63878d4ec4fSEd Tanous                 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
639144b6318SAppaRao Puli                 {
640144b6318SAppaRao Puli                     std::string mrdUri;
641ea2e6eecSWilly Tu 
64278d4ec4fSEd Tanous                     if (!json_util::readJsonObject(mrdObj, asyncResp->res,
64378d4ec4fSEd Tanous                                                    "@odata.id", mrdUri))
644ea2e6eecSWilly Tu 
645144b6318SAppaRao Puli                     {
646144b6318SAppaRao Puli                         return;
647144b6318SAppaRao Puli                     }
648*4b712a29SEd Tanous                     subValue->userSub.metricReportDefinitions.emplace_back(
649*4b712a29SEd Tanous                         mrdUri);
650144b6318SAppaRao Puli                 }
651156d6b00SAppaRao Puli             }
652156d6b00SAppaRao Puli 
653b52664e2SAppaRao Puli             std::string id =
654bd79bce8SPatrick Williams                 EventServiceManager::getInstance().addPushSubscription(
655bd79bce8SPatrick Williams                     subValue);
656b52664e2SAppaRao Puli             if (id.empty())
657e5aaf047SAppaRao Puli             {
658e5aaf047SAppaRao Puli                 messages::internalError(asyncResp->res);
659e5aaf047SAppaRao Puli                 return;
660e5aaf047SAppaRao Puli             }
661e5aaf047SAppaRao Puli 
662e5aaf047SAppaRao Puli             messages::created(asyncResp->res);
663e5aaf047SAppaRao Puli             asyncResp->res.addHeader(
664e5aaf047SAppaRao Puli                 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
6657e860f15SJohn Edward Broadbent         });
666e5aaf047SAppaRao Puli }
667e5aaf047SAppaRao Puli 
6687e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
669e5aaf047SAppaRao Puli {
6709d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
671ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
6727e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
67345ca1b86SEd Tanous             [&app](const crow::Request& req,
6747e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6757e860f15SJohn Edward Broadbent                    const std::string& param) {
6763ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
67745ca1b86SEd Tanous                 {
67845ca1b86SEd Tanous                     return;
67945ca1b86SEd Tanous                 }
6803d30708fSChicago Duan 
6813d30708fSChicago Duan                 if (param.starts_with("snmp"))
6823d30708fSChicago Duan                 {
6833d30708fSChicago Duan                     getSnmpTrapClient(asyncResp, param);
6843d30708fSChicago Duan                     return;
6853d30708fSChicago Duan                 }
6863d30708fSChicago Duan 
687b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
6887e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
689b52664e2SAppaRao Puli                 if (subValue == nullptr)
690e5aaf047SAppaRao Puli                 {
691bd79bce8SPatrick Williams                     asyncResp->res.result(
692bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
693e5aaf047SAppaRao Puli                     return;
694e5aaf047SAppaRao Puli                 }
6957e860f15SJohn Edward Broadbent                 const std::string& id = param;
696e5aaf047SAppaRao Puli 
697*4b712a29SEd Tanous                 const persistent_data::UserSubscription& userSub =
698*4b712a29SEd Tanous                     subValue->userSub;
699e56f254cSSunitha Harish 
700*4b712a29SEd Tanous                 nlohmann::json& jVal = asyncResp->res.jsonValue;
701*4b712a29SEd Tanous                 jVal["@odata.type"] =
702*4b712a29SEd Tanous                     "#EventDestination.v1_14_1.EventDestination";
703*4b712a29SEd Tanous                 jVal["Protocol"] =
704*4b712a29SEd Tanous                     event_destination::EventDestinationProtocol::Redfish;
705*4b712a29SEd Tanous                 jVal["@odata.id"] = boost::urls::format(
706*4b712a29SEd Tanous                     "/redfish/v1/EventService/Subscriptions/{}", id);
707*4b712a29SEd Tanous                 jVal["Id"] = id;
708*4b712a29SEd Tanous                 jVal["Name"] = "Event Destination " + id;
709*4b712a29SEd Tanous                 jVal["Destination"] = userSub.destinationUrl;
710*4b712a29SEd Tanous                 jVal["Context"] = userSub.customText;
711*4b712a29SEd Tanous                 jVal["SubscriptionType"] = userSub.subscriptionType;
712*4b712a29SEd Tanous                 jVal["HttpHeaders"] = nlohmann::json::array();
713*4b712a29SEd Tanous                 jVal["EventFormatType"] = userSub.eventFormatType;
714*4b712a29SEd Tanous                 jVal["RegistryPrefixes"] = userSub.registryPrefixes;
715*4b712a29SEd Tanous                 jVal["ResourceTypes"] = userSub.resourceTypes;
716*4b712a29SEd Tanous 
717*4b712a29SEd Tanous                 jVal["MessageIds"] = userSub.registryMsgIds;
718*4b712a29SEd Tanous                 jVal["DeliveryRetryPolicy"] = userSub.retryPolicy;
719*4b712a29SEd Tanous                 jVal["VerifyCertificate"] = userSub.verifyCertificate;
720144b6318SAppaRao Puli 
7211476687dSEd Tanous                 nlohmann::json::array_t mrdJsonArray;
722*4b712a29SEd Tanous                 for (const auto& mdrUri : userSub.metricReportDefinitions)
723144b6318SAppaRao Puli                 {
7241476687dSEd Tanous                     nlohmann::json::object_t mdr;
7251476687dSEd Tanous                     mdr["@odata.id"] = mdrUri;
7261476687dSEd Tanous                     mrdJsonArray.emplace_back(std::move(mdr));
727144b6318SAppaRao Puli                 }
728*4b712a29SEd Tanous                 jVal["MetricReportDefinitions"] = mrdJsonArray;
7297e860f15SJohn Edward Broadbent             });
7309d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
731ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
732ed398213SEd Tanous         // ConfigureSelf
7337eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
734ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
735432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
7367e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
73745ca1b86SEd Tanous             [&app](const crow::Request& req,
7387e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7397e860f15SJohn Edward Broadbent                    const std::string& param) {
7403ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
74145ca1b86SEd Tanous                 {
74245ca1b86SEd Tanous                     return;
74345ca1b86SEd Tanous                 }
744b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
7457e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
746b52664e2SAppaRao Puli                 if (subValue == nullptr)
747e5aaf047SAppaRao Puli                 {
748bd79bce8SPatrick Williams                     asyncResp->res.result(
749bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
750e5aaf047SAppaRao Puli                     return;
751e5aaf047SAppaRao Puli                 }
752e5aaf047SAppaRao Puli 
753e5aaf047SAppaRao Puli                 std::optional<std::string> context;
754e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
75519bb362bSEd Tanous                 std::optional<bool> verifyCertificate;
75678d4ec4fSEd Tanous                 std::optional<std::vector<nlohmann::json::object_t>> headers;
757e5aaf047SAppaRao Puli 
758bd79bce8SPatrick Williams                 if (!json_util::readJsonPatch(
759bd79bce8SPatrick Williams                         req, asyncResp->res, "Context", context,
76019bb362bSEd Tanous                         "VerifyCertificate", verifyCertificate,
761bd79bce8SPatrick Williams                         "DeliveryRetryPolicy", retryPolicy, "HttpHeaders",
762bd79bce8SPatrick Williams                         headers))
763e5aaf047SAppaRao Puli                 {
764e5aaf047SAppaRao Puli                     return;
765e5aaf047SAppaRao Puli                 }
766e5aaf047SAppaRao Puli 
767e5aaf047SAppaRao Puli                 if (context)
768e5aaf047SAppaRao Puli                 {
769*4b712a29SEd Tanous                     subValue->userSub.customText = *context;
770e5aaf047SAppaRao Puli                 }
771e5aaf047SAppaRao Puli 
772e5aaf047SAppaRao Puli                 if (headers)
773e5aaf047SAppaRao Puli                 {
774601c71aeSEd Tanous                     boost::beast::http::fields fields;
77578d4ec4fSEd Tanous                     for (const nlohmann::json::object_t& headerChunk : *headers)
776601c71aeSEd Tanous                     {
77778d4ec4fSEd Tanous                         for (const auto& it : headerChunk)
778601c71aeSEd Tanous                         {
779601c71aeSEd Tanous                             const std::string* value =
78078d4ec4fSEd Tanous                                 it.second.get_ptr<const std::string*>();
781601c71aeSEd Tanous                             if (value == nullptr)
782601c71aeSEd Tanous                             {
783601c71aeSEd Tanous                                 messages::propertyValueFormatError(
78478d4ec4fSEd Tanous                                     asyncResp->res, it.second,
78578d4ec4fSEd Tanous                                     "HttpHeaders/" + it.first);
786601c71aeSEd Tanous                                 return;
787601c71aeSEd Tanous                             }
78878d4ec4fSEd Tanous                             fields.set(it.first, *value);
789601c71aeSEd Tanous                         }
790601c71aeSEd Tanous                     }
791*4b712a29SEd Tanous                     subValue->userSub.httpHeaders = std::move(fields);
792e5aaf047SAppaRao Puli                 }
793e5aaf047SAppaRao Puli 
794e5aaf047SAppaRao Puli                 if (retryPolicy)
795e5aaf047SAppaRao Puli                 {
796bd79bce8SPatrick Williams                     if (std::ranges::find(supportedRetryPolicies,
797bd79bce8SPatrick Williams                                           *retryPolicy) ==
7983544d2a7SEd Tanous                         supportedRetryPolicies.end())
799e5aaf047SAppaRao Puli                     {
800bd79bce8SPatrick Williams                         messages::propertyValueNotInList(asyncResp->res,
801bd79bce8SPatrick Williams                                                          *retryPolicy,
802e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
803e5aaf047SAppaRao Puli                         return;
804e5aaf047SAppaRao Puli                     }
805*4b712a29SEd Tanous                     subValue->userSub.retryPolicy = *retryPolicy;
806e5aaf047SAppaRao Puli                 }
807e5aaf047SAppaRao Puli 
80819bb362bSEd Tanous                 if (verifyCertificate)
80919bb362bSEd Tanous                 {
810*4b712a29SEd Tanous                     subValue->userSub.verifyCertificate = *verifyCertificate;
81119bb362bSEd Tanous                 }
81219bb362bSEd Tanous 
813b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
8147e860f15SJohn Edward Broadbent             });
8159d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
816ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
817ed398213SEd Tanous         // ConfigureSelf
8187eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
819ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
820432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
8217e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
82245ca1b86SEd Tanous             [&app](const crow::Request& req,
8237e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8247e860f15SJohn Edward Broadbent                    const std::string& param) {
8253ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
82645ca1b86SEd Tanous                 {
82745ca1b86SEd Tanous                     return;
82845ca1b86SEd Tanous                 }
829*4b712a29SEd Tanous                 EventServiceManager& event = EventServiceManager::getInstance();
8303d30708fSChicago Duan                 if (param.starts_with("snmp"))
8313d30708fSChicago Duan                 {
8323d30708fSChicago Duan                     deleteSnmpTrapClient(asyncResp, param);
833*4b712a29SEd Tanous                     event.deleteSubscription(param);
8343d30708fSChicago Duan                     return;
8353d30708fSChicago Duan                 }
8363d30708fSChicago Duan 
837*4b712a29SEd Tanous                 if (!event.deleteSubscription(param))
838e5aaf047SAppaRao Puli                 {
839*4b712a29SEd Tanous                     messages::resourceNotFound(asyncResp->res,
840*4b712a29SEd Tanous                                                "EventDestination", param);
841e5aaf047SAppaRao Puli                     return;
842e5aaf047SAppaRao Puli                 }
843*4b712a29SEd Tanous                 messages::success(asyncResp->res);
8447e860f15SJohn Edward Broadbent             });
845e5aaf047SAppaRao Puli }
846e5aaf047SAppaRao Puli 
847e5aaf047SAppaRao Puli } // namespace redfish
848