xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision b07942e362fd4e33d9aca9860b6341e995543a5d)
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;
121afc474aeSMyung Bae                 if (!json_util::readJsonPatch( //
122afc474aeSMyung Bae                         req, asyncResp->res, //
123afc474aeSMyung Bae                         "DeliveryRetryAttempts", retryAttemps, //
124afc474aeSMyung Bae                         "DeliveryRetryIntervalSeconds", retryInterval, //
125afc474aeSMyung Bae                         "ServiceEnabled", serviceEnabled //
126afc474aeSMyung Bae                         ))
127e5aaf047SAppaRao Puli                 {
128e5aaf047SAppaRao Puli                     return;
129e5aaf047SAppaRao Puli                 }
130e5aaf047SAppaRao Puli 
13128afb49cSJunLin Chen                 persistent_data::EventServiceConfig eventServiceConfig =
13228afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
13328afb49cSJunLin Chen                         .getEventServiceConfig();
1347d1cc387SAppaRao Puli 
135e5aaf047SAppaRao Puli                 if (serviceEnabled)
136e5aaf047SAppaRao Puli                 {
13728afb49cSJunLin Chen                     eventServiceConfig.enabled = *serviceEnabled;
138e5aaf047SAppaRao Puli                 }
139e5aaf047SAppaRao Puli 
140e5aaf047SAppaRao Puli                 if (retryAttemps)
141e5aaf047SAppaRao Puli                 {
142e5aaf047SAppaRao Puli                     // Supported range [1-3]
143e5aaf047SAppaRao Puli                     if ((*retryAttemps < 1) || (*retryAttemps > 3))
144e5aaf047SAppaRao Puli                     {
145e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
146e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryAttemps),
147e5aaf047SAppaRao Puli                             "DeliveryRetryAttempts", "[1-3]");
148e5aaf047SAppaRao Puli                     }
149e5aaf047SAppaRao Puli                     else
150e5aaf047SAppaRao Puli                     {
15128afb49cSJunLin Chen                         eventServiceConfig.retryAttempts = *retryAttemps;
152e5aaf047SAppaRao Puli                     }
153e5aaf047SAppaRao Puli                 }
154e5aaf047SAppaRao Puli 
155e5aaf047SAppaRao Puli                 if (retryInterval)
156e5aaf047SAppaRao Puli                 {
15733a32b34SGunnar Mills                     // Supported range [5 - 180]
15833a32b34SGunnar Mills                     if ((*retryInterval < 5) || (*retryInterval > 180))
159e5aaf047SAppaRao Puli                     {
160e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
161e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryInterval),
16233a32b34SGunnar Mills                             "DeliveryRetryIntervalSeconds", "[5-180]");
163e5aaf047SAppaRao Puli                     }
164e5aaf047SAppaRao Puli                     else
165e5aaf047SAppaRao Puli                     {
166bd79bce8SPatrick Williams                         eventServiceConfig.retryTimeoutInterval =
167bd79bce8SPatrick Williams                             *retryInterval;
168e5aaf047SAppaRao Puli                     }
169e5aaf047SAppaRao Puli                 }
170e5aaf047SAppaRao Puli 
1717d1cc387SAppaRao Puli                 EventServiceManager::getInstance().setEventServiceConfig(
17228afb49cSJunLin Chen                     eventServiceConfig);
1737e860f15SJohn Edward Broadbent             });
1740b4bdd93SAppaRao Puli }
1750b4bdd93SAppaRao Puli 
1767e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1770b4bdd93SAppaRao Puli {
1787e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1797e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
180ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1817e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
18245ca1b86SEd Tanous             [&app](const crow::Request& req,
1837e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1843ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
18545ca1b86SEd Tanous                 {
18645ca1b86SEd Tanous                     return;
18745ca1b86SEd Tanous                 }
1886ba8c82eSsunharis_in                 if (!EventServiceManager::getInstance().sendTestEventLog())
1896ba8c82eSsunharis_in                 {
1906ba8c82eSsunharis_in                     messages::serviceDisabled(asyncResp->res,
1916ba8c82eSsunharis_in                                               "/redfish/v1/EventService/");
1926ba8c82eSsunharis_in                     return;
1936ba8c82eSsunharis_in                 }
1948d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
1957e860f15SJohn Edward Broadbent             });
196e5aaf047SAppaRao Puli }
197e5aaf047SAppaRao Puli 
1983d30708fSChicago Duan inline void doSubscriptionCollection(
199e81de512SEd Tanous     const boost::system::error_code& ec,
2003d30708fSChicago Duan     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2013d30708fSChicago Duan     const dbus::utility::ManagedObjectType& resp)
2023d30708fSChicago Duan {
2033d30708fSChicago Duan     if (ec)
2043d30708fSChicago Duan     {
2051306101eSEd Tanous         if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
2063d30708fSChicago Duan         {
2073d30708fSChicago Duan             // This is an optional process so just return if it isn't there
2083d30708fSChicago Duan             return;
2093d30708fSChicago Duan         }
2103d30708fSChicago Duan 
21162598e31SEd Tanous         BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
2123d30708fSChicago Duan         messages::internalError(asyncResp->res);
2133d30708fSChicago Duan         return;
2143d30708fSChicago Duan     }
2153d30708fSChicago Duan     nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
2163d30708fSChicago Duan     for (const auto& objpath : resp)
2173d30708fSChicago Duan     {
2183d30708fSChicago Duan         sdbusplus::message::object_path path(objpath.first);
2193d30708fSChicago Duan         const std::string snmpId = path.filename();
2203d30708fSChicago Duan         if (snmpId.empty())
2213d30708fSChicago Duan         {
22262598e31SEd Tanous             BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
2233d30708fSChicago Duan             messages::internalError(asyncResp->res);
2243d30708fSChicago Duan             return;
2253d30708fSChicago Duan         }
2263d30708fSChicago Duan 
2273d30708fSChicago Duan         getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
2283d30708fSChicago Duan     }
2293d30708fSChicago Duan }
2303d30708fSChicago Duan 
2317e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
232e5aaf047SAppaRao Puli {
2331ebe3e41SGayathri Leburu     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
234ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
2357e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
23645ca1b86SEd Tanous             [&app](const crow::Request& req,
2377e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2383ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
23945ca1b86SEd Tanous                 {
24045ca1b86SEd Tanous                     return;
24145ca1b86SEd Tanous                 }
2421476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
2431476687dSEd Tanous                     "#EventDestinationCollection.EventDestinationCollection";
2441476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
2451476687dSEd Tanous                     "/redfish/v1/EventService/Subscriptions";
246bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Name"] =
247bd79bce8SPatrick Williams                     "Event Destination Collections";
248e5aaf047SAppaRao Puli 
249bd79bce8SPatrick Williams                 nlohmann::json& memberArray =
250bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["Members"];
251e5aaf047SAppaRao Puli 
252b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
253b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
254b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
255bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Members@odata.count"] =
256bd79bce8SPatrick Williams                     subscripIds.size();
257b52664e2SAppaRao Puli 
258b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
259e5aaf047SAppaRao Puli                 {
2601476687dSEd Tanous                     nlohmann::json::object_t member;
2613d30708fSChicago Duan                     member["@odata.id"] = boost::urls::format(
2623d30708fSChicago Duan                         "/redfish/v1/EventService/Subscriptions/{}" + id);
263b2ba3072SPatrick Williams                     memberArray.emplace_back(std::move(member));
264e5aaf047SAppaRao Puli                 }
2653d30708fSChicago Duan                 crow::connections::systemBus->async_method_call(
266e81de512SEd Tanous                     [asyncResp](const boost::system::error_code& ec,
2673d30708fSChicago Duan                                 const dbus::utility::ManagedObjectType& resp) {
2683d30708fSChicago Duan                         doSubscriptionCollection(ec, asyncResp, resp);
2693d30708fSChicago Duan                     },
2703d30708fSChicago Duan                     "xyz.openbmc_project.Network.SNMP",
2713d30708fSChicago Duan                     "/xyz/openbmc_project/network/snmp/manager",
2723d30708fSChicago Duan                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
2737e860f15SJohn Edward Broadbent             });
2743d30708fSChicago Duan 
2757e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
2767eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
277bd79bce8SPatrick Williams         .methods(
278bd79bce8SPatrick Williams             boost::beast::http::verb::
279bd79bce8SPatrick Williams                 post)([&app](
280bd79bce8SPatrick Williams                           const crow::Request& req,
2817e860f15SJohn Edward Broadbent                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2823ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
28345ca1b86SEd Tanous             {
28445ca1b86SEd Tanous                 return;
28545ca1b86SEd Tanous             }
286fffb8c1fSEd Tanous             if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
287fffb8c1fSEd Tanous                 maxNoOfSubscriptions)
288e5aaf047SAppaRao Puli             {
289e5aaf047SAppaRao Puli                 messages::eventSubscriptionLimitExceeded(asyncResp->res);
290e5aaf047SAppaRao Puli                 return;
291e5aaf047SAppaRao Puli             }
292e5aaf047SAppaRao Puli             std::string destUrl;
293e5aaf047SAppaRao Puli             std::string protocol;
29419bb362bSEd Tanous             std::optional<bool> verifyCertificate;
295e5aaf047SAppaRao Puli             std::optional<std::string> context;
296e5aaf047SAppaRao Puli             std::optional<std::string> subscriptionType;
29723a21a1cSEd Tanous             std::optional<std::string> eventFormatType2;
298e5aaf047SAppaRao Puli             std::optional<std::string> retryPolicy;
299e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> msgIds;
300e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> regPrefixes;
301a14c9113SEd Tanous             std::optional<std::vector<std::string>> originResources;
302e56f254cSSunitha Harish             std::optional<std::vector<std::string>> resTypes;
30378d4ec4fSEd Tanous             std::optional<std::vector<nlohmann::json::object_t>> headers;
30478d4ec4fSEd Tanous             std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
305e5aaf047SAppaRao Puli 
306afc474aeSMyung Bae             if (!json_util::readJsonPatch( //
307afc474aeSMyung Bae                     req, asyncResp->res, //
308afc474aeSMyung Bae                     "Context", context, //
309afc474aeSMyung Bae                     "DeliveryRetryPolicy", retryPolicy, //
310afc474aeSMyung Bae                     "Destination", destUrl, //
311afc474aeSMyung Bae                     "EventFormatType", eventFormatType2, //
312afc474aeSMyung Bae                     "HttpHeaders", headers, //
313afc474aeSMyung Bae                     "MessageIds", msgIds, //
314afc474aeSMyung Bae                     "MetricReportDefinitions", mrdJsonArray, //
315afc474aeSMyung Bae                     "OriginResources", originResources, //
316afc474aeSMyung Bae                     "Protocol", protocol, //
317afc474aeSMyung Bae                     "RegistryPrefixes", regPrefixes, //
318afc474aeSMyung Bae                     "ResourceTypes", resTypes, //
319afc474aeSMyung Bae                     "SubscriptionType", subscriptionType, //
320afc474aeSMyung Bae                     "VerifyCertificate", verifyCertificate //
3214b712a29SEd Tanous                     ))
322e5aaf047SAppaRao Puli             {
323e5aaf047SAppaRao Puli                 return;
324e5aaf047SAppaRao Puli             }
3254b712a29SEd 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();
357*b07942e3SGeorge Liu 
358*b07942e3SGeorge Liu             // port_number returns zero if it is not a valid representable port
359*b07942e3SGeorge Liu             if (url->has_port() && url->port_number() == 0)
360*b07942e3SGeorge Liu             {
361*b07942e3SGeorge Liu                 BMCWEB_LOG_WARNING("{} is an invalid port in destination url",
362*b07942e3SGeorge Liu                                    url->port());
363*b07942e3SGeorge Liu                 messages::propertyValueFormatError(asyncResp->res, destUrl,
364*b07942e3SGeorge Liu                                                    "Destination");
365*b07942e3SGeorge Liu                 return;
366*b07942e3SGeorge Liu             }
367*b07942e3SGeorge Liu 
368a716aa74SEd Tanous             crow::utility::setProtocolDefaults(*url, protocol);
369a716aa74SEd Tanous             crow::utility::setPortDefaults(*url);
370a716aa74SEd Tanous 
371a716aa74SEd Tanous             if (url->path().empty())
372a716aa74SEd Tanous             {
373a716aa74SEd Tanous                 url->set_path("/");
374a716aa74SEd Tanous             }
375a716aa74SEd Tanous 
376a716aa74SEd Tanous             if (url->has_userinfo())
377a716aa74SEd Tanous             {
378a716aa74SEd Tanous                 messages::propertyValueFormatError(asyncResp->res, destUrl,
379a716aa74SEd Tanous                                                    "Destination");
380a716aa74SEd Tanous                 return;
381a716aa74SEd Tanous             }
382b52664e2SAppaRao Puli 
3833d30708fSChicago Duan             if (protocol == "SNMPv2c")
3843d30708fSChicago Duan             {
3853d30708fSChicago Duan                 if (context)
3863d30708fSChicago Duan                 {
3873d30708fSChicago Duan                     messages::propertyValueConflict(asyncResp->res, "Context",
3883d30708fSChicago Duan                                                     "Protocol");
3893d30708fSChicago Duan                     return;
3903d30708fSChicago Duan                 }
3913d30708fSChicago Duan                 if (eventFormatType2)
3923d30708fSChicago Duan                 {
393bd79bce8SPatrick Williams                     messages::propertyValueConflict(
394bd79bce8SPatrick Williams                         asyncResp->res, "EventFormatType", "Protocol");
3953d30708fSChicago Duan                     return;
3963d30708fSChicago Duan                 }
3973d30708fSChicago Duan                 if (retryPolicy)
3983d30708fSChicago Duan                 {
399bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
400bd79bce8SPatrick Williams                                                     "RetryPolicy", "Protocol");
4013d30708fSChicago Duan                     return;
4023d30708fSChicago Duan                 }
4033d30708fSChicago Duan                 if (msgIds)
4043d30708fSChicago Duan                 {
405bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
406bd79bce8SPatrick Williams                                                     "MessageIds", "Protocol");
4073d30708fSChicago Duan                     return;
4083d30708fSChicago Duan                 }
4093d30708fSChicago Duan                 if (regPrefixes)
4103d30708fSChicago Duan                 {
411bd79bce8SPatrick Williams                     messages::propertyValueConflict(
412bd79bce8SPatrick Williams                         asyncResp->res, "RegistryPrefixes", "Protocol");
4133d30708fSChicago Duan                     return;
4143d30708fSChicago Duan                 }
4153d30708fSChicago Duan                 if (resTypes)
4163d30708fSChicago Duan                 {
417bd79bce8SPatrick Williams                     messages::propertyValueConflict(
418bd79bce8SPatrick Williams                         asyncResp->res, "ResourceTypes", "Protocol");
4193d30708fSChicago Duan                     return;
4203d30708fSChicago Duan                 }
4213d30708fSChicago Duan                 if (headers)
4223d30708fSChicago Duan                 {
423bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
424bd79bce8SPatrick Williams                                                     "HttpHeaders", "Protocol");
4253d30708fSChicago Duan                     return;
4263d30708fSChicago Duan                 }
4273d30708fSChicago Duan                 if (mrdJsonArray)
4283d30708fSChicago Duan                 {
4293d30708fSChicago Duan                     messages::propertyValueConflict(
4303d30708fSChicago Duan                         asyncResp->res, "MetricReportDefinitions", "Protocol");
4313d30708fSChicago Duan                     return;
4323d30708fSChicago Duan                 }
433a716aa74SEd Tanous                 if (url->scheme() != "snmp")
434a716aa74SEd Tanous                 {
435bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
436bd79bce8SPatrick Williams                                                     "Destination", "Protocol");
4373d30708fSChicago Duan                     return;
4383d30708fSChicago Duan                 }
4393d30708fSChicago Duan 
440a716aa74SEd Tanous                 addSnmpTrapClient(asyncResp, url->host_address(),
441a716aa74SEd Tanous                                   url->port_number());
442a716aa74SEd Tanous                 return;
443b52664e2SAppaRao Puli             }
4443d30708fSChicago Duan 
445a716aa74SEd Tanous             std::shared_ptr<Subscription> subValue =
44621a94d5cSMyung Bae                 std::make_shared<Subscription>(
44721a94d5cSMyung Bae                     persistent_data::UserSubscription{}, *url, app.ioContext());
448b52664e2SAppaRao Puli 
4494b712a29SEd Tanous             subValue->userSub.destinationUrl = std::move(*url);
450e5aaf047SAppaRao Puli 
451e5aaf047SAppaRao Puli             if (subscriptionType)
452e5aaf047SAppaRao Puli             {
453e5aaf047SAppaRao Puli                 if (*subscriptionType != "RedfishEvent")
454e5aaf047SAppaRao Puli                 {
455fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
456fffb8c1fSEd Tanous                         asyncResp->res, *subscriptionType, "SubscriptionType");
457e5aaf047SAppaRao Puli                     return;
458e5aaf047SAppaRao Puli                 }
4594b712a29SEd Tanous                 subValue->userSub.subscriptionType = *subscriptionType;
460e5aaf047SAppaRao Puli             }
461e5aaf047SAppaRao Puli             else
462e5aaf047SAppaRao Puli             {
4634b712a29SEd Tanous                 // Default
4644b712a29SEd Tanous                 subValue->userSub.subscriptionType = "RedfishEvent";
465e5aaf047SAppaRao Puli             }
466e5aaf047SAppaRao Puli 
467e5aaf047SAppaRao Puli             if (protocol != "Redfish")
468e5aaf047SAppaRao Puli             {
469e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, protocol,
470e5aaf047SAppaRao Puli                                                  "Protocol");
471e5aaf047SAppaRao Puli                 return;
472e5aaf047SAppaRao Puli             }
4734b712a29SEd Tanous             subValue->userSub.protocol = protocol;
474e5aaf047SAppaRao Puli 
47519bb362bSEd Tanous             if (verifyCertificate)
47619bb362bSEd Tanous             {
4774b712a29SEd Tanous                 subValue->userSub.verifyCertificate = *verifyCertificate;
47819bb362bSEd Tanous             }
47919bb362bSEd Tanous 
48023a21a1cSEd Tanous             if (eventFormatType2)
481e5aaf047SAppaRao Puli             {
482bd79bce8SPatrick Williams                 if (std::ranges::find(supportedEvtFormatTypes,
483bd79bce8SPatrick Williams                                       *eventFormatType2) ==
4843544d2a7SEd Tanous                     supportedEvtFormatTypes.end())
485e5aaf047SAppaRao Puli                 {
486fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
487fffb8c1fSEd Tanous                         asyncResp->res, *eventFormatType2, "EventFormatType");
488e5aaf047SAppaRao Puli                     return;
489e5aaf047SAppaRao Puli                 }
4904b712a29SEd Tanous                 subValue->userSub.eventFormatType = *eventFormatType2;
491e5aaf047SAppaRao Puli             }
492e5aaf047SAppaRao Puli             else
493e5aaf047SAppaRao Puli             {
494e5aaf047SAppaRao Puli                 // If not specified, use default "Event"
4954b712a29SEd Tanous                 subValue->userSub.eventFormatType = "Event";
496e5aaf047SAppaRao Puli             }
497e5aaf047SAppaRao Puli 
498e5aaf047SAppaRao Puli             if (context)
499e5aaf047SAppaRao Puli             {
5008ece0e45SEd Tanous                 // This value is selected arbitrarily.
501600af5f1SAppaRao Puli                 constexpr const size_t maxContextSize = 256;
502600af5f1SAppaRao Puli                 if (context->size() > maxContextSize)
503600af5f1SAppaRao Puli                 {
504600af5f1SAppaRao Puli                     messages::stringValueTooLong(asyncResp->res, "Context",
505600af5f1SAppaRao Puli                                                  maxContextSize);
506600af5f1SAppaRao Puli                     return;
507600af5f1SAppaRao Puli                 }
5084b712a29SEd Tanous                 subValue->userSub.customText = *context;
509e5aaf047SAppaRao Puli             }
510e5aaf047SAppaRao Puli 
511e5aaf047SAppaRao Puli             if (headers)
512e5aaf047SAppaRao Puli             {
513600af5f1SAppaRao Puli                 size_t cumulativeLen = 0;
514600af5f1SAppaRao Puli 
51578d4ec4fSEd Tanous                 for (const nlohmann::json::object_t& headerChunk : *headers)
516601c71aeSEd Tanous                 {
51778d4ec4fSEd Tanous                     for (const auto& item : headerChunk)
51878d4ec4fSEd Tanous                     {
51978d4ec4fSEd Tanous                         const std::string* value =
52078d4ec4fSEd Tanous                             item.second.get_ptr<const std::string*>();
52178d4ec4fSEd Tanous                         if (value == nullptr)
52278d4ec4fSEd Tanous                         {
52378d4ec4fSEd Tanous                             messages::propertyValueFormatError(
52478d4ec4fSEd Tanous                                 asyncResp->res, item.second,
52578d4ec4fSEd Tanous                                 "HttpHeaders/" + item.first);
52678d4ec4fSEd Tanous                             return;
52778d4ec4fSEd Tanous                         }
52878d4ec4fSEd Tanous                         // Adding a new json value is the size of the key, +
52978d4ec4fSEd Tanous                         // the size of the value + 2 * 2 quotes for each, +
53078d4ec4fSEd Tanous                         // the colon and space between. example:
53178d4ec4fSEd Tanous                         // "key": "value"
53278d4ec4fSEd Tanous                         cumulativeLen += item.first.size() + value->size() + 6;
533600af5f1SAppaRao Puli                         // This value is selected to mirror http_connection.hpp
534600af5f1SAppaRao Puli                         constexpr const uint16_t maxHeaderSizeED = 8096;
535600af5f1SAppaRao Puli                         if (cumulativeLen > maxHeaderSizeED)
536600af5f1SAppaRao Puli                         {
53778d4ec4fSEd Tanous                             messages::arraySizeTooLong(
53878d4ec4fSEd Tanous                                 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
539600af5f1SAppaRao Puli                             return;
540600af5f1SAppaRao Puli                         }
5414b712a29SEd Tanous                         subValue->userSub.httpHeaders.set(item.first, *value);
542601c71aeSEd Tanous                     }
543601c71aeSEd Tanous                 }
544e5aaf047SAppaRao Puli             }
545e5aaf047SAppaRao Puli 
546e5aaf047SAppaRao Puli             if (regPrefixes)
547e5aaf047SAppaRao Puli             {
548e5aaf047SAppaRao Puli                 for (const std::string& it : *regPrefixes)
549e5aaf047SAppaRao Puli                 {
5503544d2a7SEd Tanous                     if (std::ranges::find(supportedRegPrefixes, it) ==
5513544d2a7SEd Tanous                         supportedRegPrefixes.end())
552e5aaf047SAppaRao Puli                     {
553fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
554fffb8c1fSEd Tanous                                                          "RegistryPrefixes");
555e5aaf047SAppaRao Puli                         return;
556e5aaf047SAppaRao Puli                     }
557e5aaf047SAppaRao Puli                 }
5584b712a29SEd Tanous                 subValue->userSub.registryPrefixes = *regPrefixes;
559e5aaf047SAppaRao Puli             }
560e5aaf047SAppaRao Puli 
561a14c9113SEd Tanous             if (originResources)
562a14c9113SEd Tanous             {
5634b712a29SEd Tanous                 subValue->userSub.originResources = *originResources;
564a14c9113SEd Tanous             }
565a14c9113SEd Tanous 
566e56f254cSSunitha Harish             if (resTypes)
567e56f254cSSunitha Harish             {
568e56f254cSSunitha Harish                 for (const std::string& it : *resTypes)
569e56f254cSSunitha Harish                 {
5703544d2a7SEd Tanous                     if (std::ranges::find(supportedResourceTypes, it) ==
5713544d2a7SEd Tanous                         supportedResourceTypes.end())
572e56f254cSSunitha Harish                     {
573e56f254cSSunitha Harish                         messages::propertyValueNotInList(asyncResp->res, it,
574e56f254cSSunitha Harish                                                          "ResourceTypes");
575e56f254cSSunitha Harish                         return;
576e56f254cSSunitha Harish                     }
577e56f254cSSunitha Harish                 }
5784b712a29SEd Tanous                 subValue->userSub.resourceTypes = *resTypes;
579e56f254cSSunitha Harish             }
580e56f254cSSunitha Harish 
581e5aaf047SAppaRao Puli             if (msgIds)
582e5aaf047SAppaRao Puli             {
583b304bd79SP Dheeraj Srujan Kumar                 std::vector<std::string> registryPrefix;
584b304bd79SP Dheeraj Srujan Kumar 
5857e860f15SJohn Edward Broadbent                 // If no registry prefixes are mentioned, consider all
5867e860f15SJohn Edward Broadbent                 // supported prefixes
5874b712a29SEd Tanous                 if (subValue->userSub.registryPrefixes.empty())
588b304bd79SP Dheeraj Srujan Kumar                 {
589b304bd79SP Dheeraj Srujan Kumar                     registryPrefix.assign(supportedRegPrefixes.begin(),
590b304bd79SP Dheeraj Srujan Kumar                                           supportedRegPrefixes.end());
591b304bd79SP Dheeraj Srujan Kumar                 }
592b304bd79SP Dheeraj Srujan Kumar                 else
593b304bd79SP Dheeraj Srujan Kumar                 {
5944b712a29SEd Tanous                     registryPrefix = subValue->userSub.registryPrefixes;
595b304bd79SP Dheeraj Srujan Kumar                 }
596b304bd79SP Dheeraj Srujan Kumar 
597b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& id : *msgIds)
598b304bd79SP Dheeraj Srujan Kumar                 {
599b304bd79SP Dheeraj Srujan Kumar                     bool validId = false;
600b304bd79SP Dheeraj Srujan Kumar 
601b304bd79SP Dheeraj Srujan Kumar                     // Check for Message ID in each of the selected Registry
602b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& it : registryPrefix)
603b304bd79SP Dheeraj Srujan Kumar                     {
604fffb8c1fSEd Tanous                         const std::span<const redfish::registries::MessageEntry>
605fffb8c1fSEd Tanous                             registry =
606fffb8c1fSEd Tanous                                 redfish::registries::getRegistryFromPrefix(it);
607b304bd79SP Dheeraj Srujan Kumar 
6083544d2a7SEd Tanous                         if (std::ranges::any_of(
6093544d2a7SEd Tanous                                 registry,
610fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
611fffb8c1fSEd Tanous                                           messageEntry) {
61255f79e6fSEd Tanous                                     return id == messageEntry.first;
613b304bd79SP Dheeraj Srujan Kumar                                 }))
614b304bd79SP Dheeraj Srujan Kumar                         {
615b304bd79SP Dheeraj Srujan Kumar                             validId = true;
616b304bd79SP Dheeraj Srujan Kumar                             break;
617b304bd79SP Dheeraj Srujan Kumar                         }
618b304bd79SP Dheeraj Srujan Kumar                     }
619b304bd79SP Dheeraj Srujan Kumar 
620b304bd79SP Dheeraj Srujan Kumar                     if (!validId)
621b304bd79SP Dheeraj Srujan Kumar                     {
622b304bd79SP Dheeraj Srujan Kumar                         messages::propertyValueNotInList(asyncResp->res, id,
623b304bd79SP Dheeraj Srujan Kumar                                                          "MessageIds");
624b304bd79SP Dheeraj Srujan Kumar                         return;
625b304bd79SP Dheeraj Srujan Kumar                     }
626b304bd79SP Dheeraj Srujan Kumar                 }
627b304bd79SP Dheeraj Srujan Kumar 
6284b712a29SEd Tanous                 subValue->userSub.registryMsgIds = *msgIds;
629e5aaf047SAppaRao Puli             }
630e5aaf047SAppaRao Puli 
631e5aaf047SAppaRao Puli             if (retryPolicy)
632e5aaf047SAppaRao Puli             {
6333544d2a7SEd Tanous                 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
6343544d2a7SEd Tanous                     supportedRetryPolicies.end())
635e5aaf047SAppaRao Puli                 {
636bd79bce8SPatrick Williams                     messages::propertyValueNotInList(
637bd79bce8SPatrick Williams                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
638e5aaf047SAppaRao Puli                     return;
639e5aaf047SAppaRao Puli                 }
6404b712a29SEd Tanous                 subValue->userSub.retryPolicy = *retryPolicy;
641e5aaf047SAppaRao Puli             }
642e5aaf047SAppaRao Puli             else
643e5aaf047SAppaRao Puli             {
644e5aaf047SAppaRao Puli                 // Default "TerminateAfterRetries"
6454b712a29SEd Tanous                 subValue->userSub.retryPolicy = "TerminateAfterRetries";
646e5aaf047SAppaRao Puli             }
647e5aaf047SAppaRao Puli 
648144b6318SAppaRao Puli             if (mrdJsonArray)
649156d6b00SAppaRao Puli             {
65078d4ec4fSEd Tanous                 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
651144b6318SAppaRao Puli                 {
652144b6318SAppaRao Puli                     std::string mrdUri;
653ea2e6eecSWilly Tu 
65478d4ec4fSEd Tanous                     if (!json_util::readJsonObject(mrdObj, asyncResp->res,
65578d4ec4fSEd Tanous                                                    "@odata.id", mrdUri))
656ea2e6eecSWilly Tu 
657144b6318SAppaRao Puli                     {
658144b6318SAppaRao Puli                         return;
659144b6318SAppaRao Puli                     }
6604b712a29SEd Tanous                     subValue->userSub.metricReportDefinitions.emplace_back(
6614b712a29SEd Tanous                         mrdUri);
662144b6318SAppaRao Puli                 }
663156d6b00SAppaRao Puli             }
664156d6b00SAppaRao Puli 
665b52664e2SAppaRao Puli             std::string id =
666bd79bce8SPatrick Williams                 EventServiceManager::getInstance().addPushSubscription(
667bd79bce8SPatrick Williams                     subValue);
668b52664e2SAppaRao Puli             if (id.empty())
669e5aaf047SAppaRao Puli             {
670e5aaf047SAppaRao Puli                 messages::internalError(asyncResp->res);
671e5aaf047SAppaRao Puli                 return;
672e5aaf047SAppaRao Puli             }
673e5aaf047SAppaRao Puli 
674e5aaf047SAppaRao Puli             messages::created(asyncResp->res);
675e5aaf047SAppaRao Puli             asyncResp->res.addHeader(
676e5aaf047SAppaRao Puli                 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
6777e860f15SJohn Edward Broadbent         });
678e5aaf047SAppaRao Puli }
679e5aaf047SAppaRao Puli 
6807e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
681e5aaf047SAppaRao Puli {
6829d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
683ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
6847e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
68545ca1b86SEd Tanous             [&app](const crow::Request& req,
6867e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6877e860f15SJohn Edward Broadbent                    const std::string& param) {
6883ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
68945ca1b86SEd Tanous                 {
69045ca1b86SEd Tanous                     return;
69145ca1b86SEd Tanous                 }
6923d30708fSChicago Duan 
6933d30708fSChicago Duan                 if (param.starts_with("snmp"))
6943d30708fSChicago Duan                 {
6953d30708fSChicago Duan                     getSnmpTrapClient(asyncResp, param);
6963d30708fSChicago Duan                     return;
6973d30708fSChicago Duan                 }
6983d30708fSChicago Duan 
699b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
7007e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
701b52664e2SAppaRao Puli                 if (subValue == nullptr)
702e5aaf047SAppaRao Puli                 {
703bd79bce8SPatrick Williams                     asyncResp->res.result(
704bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
705e5aaf047SAppaRao Puli                     return;
706e5aaf047SAppaRao Puli                 }
7077e860f15SJohn Edward Broadbent                 const std::string& id = param;
708e5aaf047SAppaRao Puli 
7094b712a29SEd Tanous                 const persistent_data::UserSubscription& userSub =
7104b712a29SEd Tanous                     subValue->userSub;
711e56f254cSSunitha Harish 
7124b712a29SEd Tanous                 nlohmann::json& jVal = asyncResp->res.jsonValue;
7134b712a29SEd Tanous                 jVal["@odata.type"] =
7144b712a29SEd Tanous                     "#EventDestination.v1_14_1.EventDestination";
7154b712a29SEd Tanous                 jVal["Protocol"] =
7164b712a29SEd Tanous                     event_destination::EventDestinationProtocol::Redfish;
7174b712a29SEd Tanous                 jVal["@odata.id"] = boost::urls::format(
7184b712a29SEd Tanous                     "/redfish/v1/EventService/Subscriptions/{}", id);
7194b712a29SEd Tanous                 jVal["Id"] = id;
7204b712a29SEd Tanous                 jVal["Name"] = "Event Destination " + id;
7214b712a29SEd Tanous                 jVal["Destination"] = userSub.destinationUrl;
7224b712a29SEd Tanous                 jVal["Context"] = userSub.customText;
7234b712a29SEd Tanous                 jVal["SubscriptionType"] = userSub.subscriptionType;
7244b712a29SEd Tanous                 jVal["HttpHeaders"] = nlohmann::json::array();
7254b712a29SEd Tanous                 jVal["EventFormatType"] = userSub.eventFormatType;
7264b712a29SEd Tanous                 jVal["RegistryPrefixes"] = userSub.registryPrefixes;
7274b712a29SEd Tanous                 jVal["ResourceTypes"] = userSub.resourceTypes;
7284b712a29SEd Tanous 
7294b712a29SEd Tanous                 jVal["MessageIds"] = userSub.registryMsgIds;
7304b712a29SEd Tanous                 jVal["DeliveryRetryPolicy"] = userSub.retryPolicy;
7314b712a29SEd Tanous                 jVal["VerifyCertificate"] = userSub.verifyCertificate;
732144b6318SAppaRao Puli 
7331476687dSEd Tanous                 nlohmann::json::array_t mrdJsonArray;
7344b712a29SEd Tanous                 for (const auto& mdrUri : userSub.metricReportDefinitions)
735144b6318SAppaRao Puli                 {
7361476687dSEd Tanous                     nlohmann::json::object_t mdr;
7371476687dSEd Tanous                     mdr["@odata.id"] = mdrUri;
7381476687dSEd Tanous                     mrdJsonArray.emplace_back(std::move(mdr));
739144b6318SAppaRao Puli                 }
7404b712a29SEd Tanous                 jVal["MetricReportDefinitions"] = mrdJsonArray;
7417e860f15SJohn Edward Broadbent             });
7429d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
743ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
744ed398213SEd Tanous         // ConfigureSelf
7457eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
746ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
747432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
7487e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
74945ca1b86SEd Tanous             [&app](const crow::Request& req,
7507e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7517e860f15SJohn Edward Broadbent                    const std::string& param) {
7523ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
75345ca1b86SEd Tanous                 {
75445ca1b86SEd Tanous                     return;
75545ca1b86SEd Tanous                 }
756b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
7577e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
758b52664e2SAppaRao Puli                 if (subValue == nullptr)
759e5aaf047SAppaRao Puli                 {
760bd79bce8SPatrick Williams                     asyncResp->res.result(
761bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
762e5aaf047SAppaRao Puli                     return;
763e5aaf047SAppaRao Puli                 }
764e5aaf047SAppaRao Puli 
765e5aaf047SAppaRao Puli                 std::optional<std::string> context;
766e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
76719bb362bSEd Tanous                 std::optional<bool> verifyCertificate;
76878d4ec4fSEd Tanous                 std::optional<std::vector<nlohmann::json::object_t>> headers;
769e5aaf047SAppaRao Puli 
770afc474aeSMyung Bae                 if (!json_util::readJsonPatch( //
771afc474aeSMyung Bae                         req, asyncResp->res, //
772afc474aeSMyung Bae                         "Context", context, //
773afc474aeSMyung Bae                         "DeliveryRetryPolicy", retryPolicy, //
774afc474aeSMyung Bae                         "HttpHeaders", headers, //
775afc474aeSMyung Bae                         "VerifyCertificate", verifyCertificate //
776afc474aeSMyung Bae                         ))
777e5aaf047SAppaRao Puli                 {
778e5aaf047SAppaRao Puli                     return;
779e5aaf047SAppaRao Puli                 }
780e5aaf047SAppaRao Puli 
781e5aaf047SAppaRao Puli                 if (context)
782e5aaf047SAppaRao Puli                 {
7834b712a29SEd Tanous                     subValue->userSub.customText = *context;
784e5aaf047SAppaRao Puli                 }
785e5aaf047SAppaRao Puli 
786e5aaf047SAppaRao Puli                 if (headers)
787e5aaf047SAppaRao Puli                 {
788601c71aeSEd Tanous                     boost::beast::http::fields fields;
78978d4ec4fSEd Tanous                     for (const nlohmann::json::object_t& headerChunk : *headers)
790601c71aeSEd Tanous                     {
79178d4ec4fSEd Tanous                         for (const auto& it : headerChunk)
792601c71aeSEd Tanous                         {
793601c71aeSEd Tanous                             const std::string* value =
79478d4ec4fSEd Tanous                                 it.second.get_ptr<const std::string*>();
795601c71aeSEd Tanous                             if (value == nullptr)
796601c71aeSEd Tanous                             {
797601c71aeSEd Tanous                                 messages::propertyValueFormatError(
79878d4ec4fSEd Tanous                                     asyncResp->res, it.second,
79978d4ec4fSEd Tanous                                     "HttpHeaders/" + it.first);
800601c71aeSEd Tanous                                 return;
801601c71aeSEd Tanous                             }
80278d4ec4fSEd Tanous                             fields.set(it.first, *value);
803601c71aeSEd Tanous                         }
804601c71aeSEd Tanous                     }
8054b712a29SEd Tanous                     subValue->userSub.httpHeaders = std::move(fields);
806e5aaf047SAppaRao Puli                 }
807e5aaf047SAppaRao Puli 
808e5aaf047SAppaRao Puli                 if (retryPolicy)
809e5aaf047SAppaRao Puli                 {
810bd79bce8SPatrick Williams                     if (std::ranges::find(supportedRetryPolicies,
811bd79bce8SPatrick Williams                                           *retryPolicy) ==
8123544d2a7SEd Tanous                         supportedRetryPolicies.end())
813e5aaf047SAppaRao Puli                     {
814bd79bce8SPatrick Williams                         messages::propertyValueNotInList(asyncResp->res,
815bd79bce8SPatrick Williams                                                          *retryPolicy,
816e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
817e5aaf047SAppaRao Puli                         return;
818e5aaf047SAppaRao Puli                     }
8194b712a29SEd Tanous                     subValue->userSub.retryPolicy = *retryPolicy;
820e5aaf047SAppaRao Puli                 }
821e5aaf047SAppaRao Puli 
82219bb362bSEd Tanous                 if (verifyCertificate)
82319bb362bSEd Tanous                 {
8244b712a29SEd Tanous                     subValue->userSub.verifyCertificate = *verifyCertificate;
82519bb362bSEd Tanous                 }
82619bb362bSEd Tanous 
82756ba386dSMyung Bae                 // Sync Subscription to UserSubscriptionConfig
82856ba386dSMyung Bae                 persistent_data::EventServiceStore::getInstance()
82956ba386dSMyung Bae                     .updateUserSubscriptionConfig(subValue->userSub);
83056ba386dSMyung Bae 
831b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
8327e860f15SJohn Edward Broadbent             });
8339d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
834ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
835ed398213SEd Tanous         // ConfigureSelf
8367eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
837ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
838432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
8397e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
84045ca1b86SEd Tanous             [&app](const crow::Request& req,
8417e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8427e860f15SJohn Edward Broadbent                    const std::string& param) {
8433ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
84445ca1b86SEd Tanous                 {
84545ca1b86SEd Tanous                     return;
84645ca1b86SEd Tanous                 }
8474b712a29SEd Tanous                 EventServiceManager& event = EventServiceManager::getInstance();
8483d30708fSChicago Duan                 if (param.starts_with("snmp"))
8493d30708fSChicago Duan                 {
8503d30708fSChicago Duan                     deleteSnmpTrapClient(asyncResp, param);
8514b712a29SEd Tanous                     event.deleteSubscription(param);
8523d30708fSChicago Duan                     return;
8533d30708fSChicago Duan                 }
8543d30708fSChicago Duan 
8554b712a29SEd Tanous                 if (!event.deleteSubscription(param))
856e5aaf047SAppaRao Puli                 {
8574b712a29SEd Tanous                     messages::resourceNotFound(asyncResp->res,
8584b712a29SEd Tanous                                                "EventDestination", param);
859e5aaf047SAppaRao Puli                     return;
860e5aaf047SAppaRao Puli                 }
8614b712a29SEd Tanous                 messages::success(asyncResp->res);
8627e860f15SJohn Edward Broadbent             });
863e5aaf047SAppaRao Puli }
864e5aaf047SAppaRao Puli 
865e5aaf047SAppaRao Puli } // namespace redfish
866