xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision 5fe4ef35821f946c91d9c20cee01e632d6d3ffd4)
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();
357b07942e3SGeorge Liu 
358b07942e3SGeorge Liu             // port_number returns zero if it is not a valid representable port
359b07942e3SGeorge Liu             if (url->has_port() && url->port_number() == 0)
360b07942e3SGeorge Liu             {
361b07942e3SGeorge Liu                 BMCWEB_LOG_WARNING("{} is an invalid port in destination url",
362b07942e3SGeorge Liu                                    url->port());
363b07942e3SGeorge Liu                 messages::propertyValueFormatError(asyncResp->res, destUrl,
364b07942e3SGeorge Liu                                                    "Destination");
365b07942e3SGeorge Liu                 return;
366b07942e3SGeorge Liu             }
367b07942e3SGeorge 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>(
447*5fe4ef35SMyung Bae                     std::make_shared<persistent_data::UserSubscription>(), *url,
448*5fe4ef35SMyung Bae                     app.ioContext());
449e5aaf047SAppaRao Puli 
450e5aaf047SAppaRao Puli             if (subscriptionType)
451e5aaf047SAppaRao Puli             {
452e5aaf047SAppaRao Puli                 if (*subscriptionType != "RedfishEvent")
453e5aaf047SAppaRao Puli                 {
454fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
455fffb8c1fSEd Tanous                         asyncResp->res, *subscriptionType, "SubscriptionType");
456e5aaf047SAppaRao Puli                     return;
457e5aaf047SAppaRao Puli                 }
458*5fe4ef35SMyung Bae                 subValue->userSub->subscriptionType = *subscriptionType;
459e5aaf047SAppaRao Puli             }
460e5aaf047SAppaRao Puli             else
461e5aaf047SAppaRao Puli             {
4624b712a29SEd Tanous                 // Default
463*5fe4ef35SMyung Bae                 subValue->userSub->subscriptionType = "RedfishEvent";
464e5aaf047SAppaRao Puli             }
465e5aaf047SAppaRao Puli 
466e5aaf047SAppaRao Puli             if (protocol != "Redfish")
467e5aaf047SAppaRao Puli             {
468e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, protocol,
469e5aaf047SAppaRao Puli                                                  "Protocol");
470e5aaf047SAppaRao Puli                 return;
471e5aaf047SAppaRao Puli             }
472*5fe4ef35SMyung Bae             subValue->userSub->protocol = protocol;
473e5aaf047SAppaRao Puli 
47419bb362bSEd Tanous             if (verifyCertificate)
47519bb362bSEd Tanous             {
476*5fe4ef35SMyung Bae                 subValue->userSub->verifyCertificate = *verifyCertificate;
47719bb362bSEd Tanous             }
47819bb362bSEd Tanous 
47923a21a1cSEd Tanous             if (eventFormatType2)
480e5aaf047SAppaRao Puli             {
481bd79bce8SPatrick Williams                 if (std::ranges::find(supportedEvtFormatTypes,
482bd79bce8SPatrick Williams                                       *eventFormatType2) ==
4833544d2a7SEd Tanous                     supportedEvtFormatTypes.end())
484e5aaf047SAppaRao Puli                 {
485fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
486fffb8c1fSEd Tanous                         asyncResp->res, *eventFormatType2, "EventFormatType");
487e5aaf047SAppaRao Puli                     return;
488e5aaf047SAppaRao Puli                 }
489*5fe4ef35SMyung Bae                 subValue->userSub->eventFormatType = *eventFormatType2;
490e5aaf047SAppaRao Puli             }
491e5aaf047SAppaRao Puli             else
492e5aaf047SAppaRao Puli             {
493e5aaf047SAppaRao Puli                 // If not specified, use default "Event"
494*5fe4ef35SMyung Bae                 subValue->userSub->eventFormatType = "Event";
495e5aaf047SAppaRao Puli             }
496e5aaf047SAppaRao Puli 
497e5aaf047SAppaRao Puli             if (context)
498e5aaf047SAppaRao Puli             {
4998ece0e45SEd Tanous                 // This value is selected arbitrarily.
500600af5f1SAppaRao Puli                 constexpr const size_t maxContextSize = 256;
501600af5f1SAppaRao Puli                 if (context->size() > maxContextSize)
502600af5f1SAppaRao Puli                 {
503600af5f1SAppaRao Puli                     messages::stringValueTooLong(asyncResp->res, "Context",
504600af5f1SAppaRao Puli                                                  maxContextSize);
505600af5f1SAppaRao Puli                     return;
506600af5f1SAppaRao Puli                 }
507*5fe4ef35SMyung Bae                 subValue->userSub->customText = *context;
508e5aaf047SAppaRao Puli             }
509e5aaf047SAppaRao Puli 
510e5aaf047SAppaRao Puli             if (headers)
511e5aaf047SAppaRao Puli             {
512600af5f1SAppaRao Puli                 size_t cumulativeLen = 0;
513600af5f1SAppaRao Puli 
51478d4ec4fSEd Tanous                 for (const nlohmann::json::object_t& headerChunk : *headers)
515601c71aeSEd Tanous                 {
51678d4ec4fSEd Tanous                     for (const auto& item : headerChunk)
51778d4ec4fSEd Tanous                     {
51878d4ec4fSEd Tanous                         const std::string* value =
51978d4ec4fSEd Tanous                             item.second.get_ptr<const std::string*>();
52078d4ec4fSEd Tanous                         if (value == nullptr)
52178d4ec4fSEd Tanous                         {
52278d4ec4fSEd Tanous                             messages::propertyValueFormatError(
52378d4ec4fSEd Tanous                                 asyncResp->res, item.second,
52478d4ec4fSEd Tanous                                 "HttpHeaders/" + item.first);
52578d4ec4fSEd Tanous                             return;
52678d4ec4fSEd Tanous                         }
52778d4ec4fSEd Tanous                         // Adding a new json value is the size of the key, +
52878d4ec4fSEd Tanous                         // the size of the value + 2 * 2 quotes for each, +
52978d4ec4fSEd Tanous                         // the colon and space between. example:
53078d4ec4fSEd Tanous                         // "key": "value"
53178d4ec4fSEd Tanous                         cumulativeLen += item.first.size() + value->size() + 6;
532600af5f1SAppaRao Puli                         // This value is selected to mirror http_connection.hpp
533600af5f1SAppaRao Puli                         constexpr const uint16_t maxHeaderSizeED = 8096;
534600af5f1SAppaRao Puli                         if (cumulativeLen > maxHeaderSizeED)
535600af5f1SAppaRao Puli                         {
53678d4ec4fSEd Tanous                             messages::arraySizeTooLong(
53778d4ec4fSEd Tanous                                 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
538600af5f1SAppaRao Puli                             return;
539600af5f1SAppaRao Puli                         }
540*5fe4ef35SMyung Bae                         subValue->userSub->httpHeaders.set(item.first, *value);
541601c71aeSEd Tanous                     }
542601c71aeSEd Tanous                 }
543e5aaf047SAppaRao Puli             }
544e5aaf047SAppaRao Puli 
545e5aaf047SAppaRao Puli             if (regPrefixes)
546e5aaf047SAppaRao Puli             {
547e5aaf047SAppaRao Puli                 for (const std::string& it : *regPrefixes)
548e5aaf047SAppaRao Puli                 {
5493544d2a7SEd Tanous                     if (std::ranges::find(supportedRegPrefixes, it) ==
5503544d2a7SEd Tanous                         supportedRegPrefixes.end())
551e5aaf047SAppaRao Puli                     {
552fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
553fffb8c1fSEd Tanous                                                          "RegistryPrefixes");
554e5aaf047SAppaRao Puli                         return;
555e5aaf047SAppaRao Puli                     }
556e5aaf047SAppaRao Puli                 }
557*5fe4ef35SMyung Bae                 subValue->userSub->registryPrefixes = *regPrefixes;
558e5aaf047SAppaRao Puli             }
559e5aaf047SAppaRao Puli 
560a14c9113SEd Tanous             if (originResources)
561a14c9113SEd Tanous             {
562*5fe4ef35SMyung Bae                 subValue->userSub->originResources = *originResources;
563a14c9113SEd Tanous             }
564a14c9113SEd Tanous 
565e56f254cSSunitha Harish             if (resTypes)
566e56f254cSSunitha Harish             {
567e56f254cSSunitha Harish                 for (const std::string& it : *resTypes)
568e56f254cSSunitha Harish                 {
5693544d2a7SEd Tanous                     if (std::ranges::find(supportedResourceTypes, it) ==
5703544d2a7SEd Tanous                         supportedResourceTypes.end())
571e56f254cSSunitha Harish                     {
572e56f254cSSunitha Harish                         messages::propertyValueNotInList(asyncResp->res, it,
573e56f254cSSunitha Harish                                                          "ResourceTypes");
574e56f254cSSunitha Harish                         return;
575e56f254cSSunitha Harish                     }
576e56f254cSSunitha Harish                 }
577*5fe4ef35SMyung Bae                 subValue->userSub->resourceTypes = *resTypes;
578e56f254cSSunitha Harish             }
579e56f254cSSunitha Harish 
580e5aaf047SAppaRao Puli             if (msgIds)
581e5aaf047SAppaRao Puli             {
582b304bd79SP Dheeraj Srujan Kumar                 std::vector<std::string> registryPrefix;
583b304bd79SP Dheeraj Srujan Kumar 
5847e860f15SJohn Edward Broadbent                 // If no registry prefixes are mentioned, consider all
5857e860f15SJohn Edward Broadbent                 // supported prefixes
586*5fe4ef35SMyung Bae                 if (subValue->userSub->registryPrefixes.empty())
587b304bd79SP Dheeraj Srujan Kumar                 {
588b304bd79SP Dheeraj Srujan Kumar                     registryPrefix.assign(supportedRegPrefixes.begin(),
589b304bd79SP Dheeraj Srujan Kumar                                           supportedRegPrefixes.end());
590b304bd79SP Dheeraj Srujan Kumar                 }
591b304bd79SP Dheeraj Srujan Kumar                 else
592b304bd79SP Dheeraj Srujan Kumar                 {
593*5fe4ef35SMyung Bae                     registryPrefix = subValue->userSub->registryPrefixes;
594b304bd79SP Dheeraj Srujan Kumar                 }
595b304bd79SP Dheeraj Srujan Kumar 
596b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& id : *msgIds)
597b304bd79SP Dheeraj Srujan Kumar                 {
598b304bd79SP Dheeraj Srujan Kumar                     bool validId = false;
599b304bd79SP Dheeraj Srujan Kumar 
600b304bd79SP Dheeraj Srujan Kumar                     // Check for Message ID in each of the selected Registry
601b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& it : registryPrefix)
602b304bd79SP Dheeraj Srujan Kumar                     {
603fffb8c1fSEd Tanous                         const std::span<const redfish::registries::MessageEntry>
604fffb8c1fSEd Tanous                             registry =
605fffb8c1fSEd Tanous                                 redfish::registries::getRegistryFromPrefix(it);
606b304bd79SP Dheeraj Srujan Kumar 
6073544d2a7SEd Tanous                         if (std::ranges::any_of(
6083544d2a7SEd Tanous                                 registry,
609fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
610fffb8c1fSEd Tanous                                           messageEntry) {
61155f79e6fSEd Tanous                                     return id == messageEntry.first;
612b304bd79SP Dheeraj Srujan Kumar                                 }))
613b304bd79SP Dheeraj Srujan Kumar                         {
614b304bd79SP Dheeraj Srujan Kumar                             validId = true;
615b304bd79SP Dheeraj Srujan Kumar                             break;
616b304bd79SP Dheeraj Srujan Kumar                         }
617b304bd79SP Dheeraj Srujan Kumar                     }
618b304bd79SP Dheeraj Srujan Kumar 
619b304bd79SP Dheeraj Srujan Kumar                     if (!validId)
620b304bd79SP Dheeraj Srujan Kumar                     {
621b304bd79SP Dheeraj Srujan Kumar                         messages::propertyValueNotInList(asyncResp->res, id,
622b304bd79SP Dheeraj Srujan Kumar                                                          "MessageIds");
623b304bd79SP Dheeraj Srujan Kumar                         return;
624b304bd79SP Dheeraj Srujan Kumar                     }
625b304bd79SP Dheeraj Srujan Kumar                 }
626b304bd79SP Dheeraj Srujan Kumar 
627*5fe4ef35SMyung Bae                 subValue->userSub->registryMsgIds = *msgIds;
628e5aaf047SAppaRao Puli             }
629e5aaf047SAppaRao Puli 
630e5aaf047SAppaRao Puli             if (retryPolicy)
631e5aaf047SAppaRao Puli             {
6323544d2a7SEd Tanous                 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
6333544d2a7SEd Tanous                     supportedRetryPolicies.end())
634e5aaf047SAppaRao Puli                 {
635bd79bce8SPatrick Williams                     messages::propertyValueNotInList(
636bd79bce8SPatrick Williams                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
637e5aaf047SAppaRao Puli                     return;
638e5aaf047SAppaRao Puli                 }
639*5fe4ef35SMyung Bae                 subValue->userSub->retryPolicy = *retryPolicy;
640e5aaf047SAppaRao Puli             }
641e5aaf047SAppaRao Puli             else
642e5aaf047SAppaRao Puli             {
643e5aaf047SAppaRao Puli                 // Default "TerminateAfterRetries"
644*5fe4ef35SMyung Bae                 subValue->userSub->retryPolicy = "TerminateAfterRetries";
645e5aaf047SAppaRao Puli             }
646e5aaf047SAppaRao Puli 
647144b6318SAppaRao Puli             if (mrdJsonArray)
648156d6b00SAppaRao Puli             {
64978d4ec4fSEd Tanous                 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
650144b6318SAppaRao Puli                 {
651144b6318SAppaRao Puli                     std::string mrdUri;
652ea2e6eecSWilly Tu 
65378d4ec4fSEd Tanous                     if (!json_util::readJsonObject(mrdObj, asyncResp->res,
65478d4ec4fSEd Tanous                                                    "@odata.id", mrdUri))
655ea2e6eecSWilly Tu 
656144b6318SAppaRao Puli                     {
657144b6318SAppaRao Puli                         return;
658144b6318SAppaRao Puli                     }
659*5fe4ef35SMyung Bae                     subValue->userSub->metricReportDefinitions.emplace_back(
6604b712a29SEd Tanous                         mrdUri);
661144b6318SAppaRao Puli                 }
662156d6b00SAppaRao Puli             }
663156d6b00SAppaRao Puli 
664b52664e2SAppaRao Puli             std::string id =
665bd79bce8SPatrick Williams                 EventServiceManager::getInstance().addPushSubscription(
666bd79bce8SPatrick Williams                     subValue);
667b52664e2SAppaRao Puli             if (id.empty())
668e5aaf047SAppaRao Puli             {
669e5aaf047SAppaRao Puli                 messages::internalError(asyncResp->res);
670e5aaf047SAppaRao Puli                 return;
671e5aaf047SAppaRao Puli             }
672e5aaf047SAppaRao Puli 
673e5aaf047SAppaRao Puli             messages::created(asyncResp->res);
674e5aaf047SAppaRao Puli             asyncResp->res.addHeader(
675e5aaf047SAppaRao Puli                 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
6767e860f15SJohn Edward Broadbent         });
677e5aaf047SAppaRao Puli }
678e5aaf047SAppaRao Puli 
6797e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
680e5aaf047SAppaRao Puli {
6819d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
682ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
6837e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
68445ca1b86SEd Tanous             [&app](const crow::Request& req,
6857e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6867e860f15SJohn Edward Broadbent                    const std::string& param) {
6873ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
68845ca1b86SEd Tanous                 {
68945ca1b86SEd Tanous                     return;
69045ca1b86SEd Tanous                 }
6913d30708fSChicago Duan 
6923d30708fSChicago Duan                 if (param.starts_with("snmp"))
6933d30708fSChicago Duan                 {
6943d30708fSChicago Duan                     getSnmpTrapClient(asyncResp, param);
6953d30708fSChicago Duan                     return;
6963d30708fSChicago Duan                 }
6973d30708fSChicago Duan 
698b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
6997e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
700b52664e2SAppaRao Puli                 if (subValue == nullptr)
701e5aaf047SAppaRao Puli                 {
702bd79bce8SPatrick Williams                     asyncResp->res.result(
703bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
704e5aaf047SAppaRao Puli                     return;
705e5aaf047SAppaRao Puli                 }
7067e860f15SJohn Edward Broadbent                 const std::string& id = param;
707e5aaf047SAppaRao Puli 
7084b712a29SEd Tanous                 const persistent_data::UserSubscription& userSub =
709*5fe4ef35SMyung Bae                     *subValue->userSub;
710e56f254cSSunitha Harish 
7114b712a29SEd Tanous                 nlohmann::json& jVal = asyncResp->res.jsonValue;
7124b712a29SEd Tanous                 jVal["@odata.type"] =
7134b712a29SEd Tanous                     "#EventDestination.v1_14_1.EventDestination";
7144b712a29SEd Tanous                 jVal["Protocol"] =
7154b712a29SEd Tanous                     event_destination::EventDestinationProtocol::Redfish;
7164b712a29SEd Tanous                 jVal["@odata.id"] = boost::urls::format(
7174b712a29SEd Tanous                     "/redfish/v1/EventService/Subscriptions/{}", id);
7184b712a29SEd Tanous                 jVal["Id"] = id;
7194b712a29SEd Tanous                 jVal["Name"] = "Event Destination " + id;
7204b712a29SEd Tanous                 jVal["Destination"] = userSub.destinationUrl;
7214b712a29SEd Tanous                 jVal["Context"] = userSub.customText;
7224b712a29SEd Tanous                 jVal["SubscriptionType"] = userSub.subscriptionType;
7234b712a29SEd Tanous                 jVal["HttpHeaders"] = nlohmann::json::array();
7244b712a29SEd Tanous                 jVal["EventFormatType"] = userSub.eventFormatType;
7254b712a29SEd Tanous                 jVal["RegistryPrefixes"] = userSub.registryPrefixes;
7264b712a29SEd Tanous                 jVal["ResourceTypes"] = userSub.resourceTypes;
7274b712a29SEd Tanous 
7284b712a29SEd Tanous                 jVal["MessageIds"] = userSub.registryMsgIds;
7294b712a29SEd Tanous                 jVal["DeliveryRetryPolicy"] = userSub.retryPolicy;
7304b712a29SEd Tanous                 jVal["VerifyCertificate"] = userSub.verifyCertificate;
731144b6318SAppaRao Puli 
7321476687dSEd Tanous                 nlohmann::json::array_t mrdJsonArray;
7334b712a29SEd Tanous                 for (const auto& mdrUri : userSub.metricReportDefinitions)
734144b6318SAppaRao Puli                 {
7351476687dSEd Tanous                     nlohmann::json::object_t mdr;
7361476687dSEd Tanous                     mdr["@odata.id"] = mdrUri;
7371476687dSEd Tanous                     mrdJsonArray.emplace_back(std::move(mdr));
738144b6318SAppaRao Puli                 }
7394b712a29SEd Tanous                 jVal["MetricReportDefinitions"] = mrdJsonArray;
7407e860f15SJohn Edward Broadbent             });
7419d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
742ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
743ed398213SEd Tanous         // ConfigureSelf
7447eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
745ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
746432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
7477e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
74845ca1b86SEd Tanous             [&app](const crow::Request& req,
7497e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7507e860f15SJohn Edward Broadbent                    const std::string& param) {
7513ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
75245ca1b86SEd Tanous                 {
75345ca1b86SEd Tanous                     return;
75445ca1b86SEd Tanous                 }
755b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
7567e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
757b52664e2SAppaRao Puli                 if (subValue == nullptr)
758e5aaf047SAppaRao Puli                 {
759bd79bce8SPatrick Williams                     asyncResp->res.result(
760bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
761e5aaf047SAppaRao Puli                     return;
762e5aaf047SAppaRao Puli                 }
763e5aaf047SAppaRao Puli 
764e5aaf047SAppaRao Puli                 std::optional<std::string> context;
765e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
76619bb362bSEd Tanous                 std::optional<bool> verifyCertificate;
76778d4ec4fSEd Tanous                 std::optional<std::vector<nlohmann::json::object_t>> headers;
768e5aaf047SAppaRao Puli 
769afc474aeSMyung Bae                 if (!json_util::readJsonPatch( //
770afc474aeSMyung Bae                         req, asyncResp->res, //
771afc474aeSMyung Bae                         "Context", context, //
772afc474aeSMyung Bae                         "DeliveryRetryPolicy", retryPolicy, //
773afc474aeSMyung Bae                         "HttpHeaders", headers, //
774afc474aeSMyung Bae                         "VerifyCertificate", verifyCertificate //
775afc474aeSMyung Bae                         ))
776e5aaf047SAppaRao Puli                 {
777e5aaf047SAppaRao Puli                     return;
778e5aaf047SAppaRao Puli                 }
779e5aaf047SAppaRao Puli 
780e5aaf047SAppaRao Puli                 if (context)
781e5aaf047SAppaRao Puli                 {
782*5fe4ef35SMyung Bae                     subValue->userSub->customText = *context;
783e5aaf047SAppaRao Puli                 }
784e5aaf047SAppaRao Puli 
785e5aaf047SAppaRao Puli                 if (headers)
786e5aaf047SAppaRao Puli                 {
787601c71aeSEd Tanous                     boost::beast::http::fields fields;
78878d4ec4fSEd Tanous                     for (const nlohmann::json::object_t& headerChunk : *headers)
789601c71aeSEd Tanous                     {
79078d4ec4fSEd Tanous                         for (const auto& it : headerChunk)
791601c71aeSEd Tanous                         {
792601c71aeSEd Tanous                             const std::string* value =
79378d4ec4fSEd Tanous                                 it.second.get_ptr<const std::string*>();
794601c71aeSEd Tanous                             if (value == nullptr)
795601c71aeSEd Tanous                             {
796601c71aeSEd Tanous                                 messages::propertyValueFormatError(
79778d4ec4fSEd Tanous                                     asyncResp->res, it.second,
79878d4ec4fSEd Tanous                                     "HttpHeaders/" + it.first);
799601c71aeSEd Tanous                                 return;
800601c71aeSEd Tanous                             }
80178d4ec4fSEd Tanous                             fields.set(it.first, *value);
802601c71aeSEd Tanous                         }
803601c71aeSEd Tanous                     }
804*5fe4ef35SMyung Bae                     subValue->userSub->httpHeaders = std::move(fields);
805e5aaf047SAppaRao Puli                 }
806e5aaf047SAppaRao Puli 
807e5aaf047SAppaRao Puli                 if (retryPolicy)
808e5aaf047SAppaRao Puli                 {
809bd79bce8SPatrick Williams                     if (std::ranges::find(supportedRetryPolicies,
810bd79bce8SPatrick Williams                                           *retryPolicy) ==
8113544d2a7SEd Tanous                         supportedRetryPolicies.end())
812e5aaf047SAppaRao Puli                     {
813bd79bce8SPatrick Williams                         messages::propertyValueNotInList(asyncResp->res,
814bd79bce8SPatrick Williams                                                          *retryPolicy,
815e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
816e5aaf047SAppaRao Puli                         return;
817e5aaf047SAppaRao Puli                     }
818*5fe4ef35SMyung Bae                     subValue->userSub->retryPolicy = *retryPolicy;
819e5aaf047SAppaRao Puli                 }
820e5aaf047SAppaRao Puli 
82119bb362bSEd Tanous                 if (verifyCertificate)
82219bb362bSEd Tanous                 {
823*5fe4ef35SMyung Bae                     subValue->userSub->verifyCertificate = *verifyCertificate;
82419bb362bSEd Tanous                 }
82519bb362bSEd Tanous 
826b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
8277e860f15SJohn Edward Broadbent             });
8289d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
829ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
830ed398213SEd Tanous         // ConfigureSelf
8317eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
832ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
833432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
8347e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
83545ca1b86SEd Tanous             [&app](const crow::Request& req,
8367e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8377e860f15SJohn Edward Broadbent                    const std::string& param) {
8383ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
83945ca1b86SEd Tanous                 {
84045ca1b86SEd Tanous                     return;
84145ca1b86SEd Tanous                 }
8424b712a29SEd Tanous                 EventServiceManager& event = EventServiceManager::getInstance();
8433d30708fSChicago Duan                 if (param.starts_with("snmp"))
8443d30708fSChicago Duan                 {
8453d30708fSChicago Duan                     deleteSnmpTrapClient(asyncResp, param);
8464b712a29SEd Tanous                     event.deleteSubscription(param);
8473d30708fSChicago Duan                     return;
8483d30708fSChicago Duan                 }
8493d30708fSChicago Duan 
8504b712a29SEd Tanous                 if (!event.deleteSubscription(param))
851e5aaf047SAppaRao Puli                 {
8524b712a29SEd Tanous                     messages::resourceNotFound(asyncResp->res,
8534b712a29SEd Tanous                                                "EventDestination", param);
854e5aaf047SAppaRao Puli                     return;
855e5aaf047SAppaRao Puli                 }
8564b712a29SEd Tanous                 messages::success(asyncResp->res);
8577e860f15SJohn Edward Broadbent             });
858e5aaf047SAppaRao Puli }
859e5aaf047SAppaRao Puli 
860e5aaf047SAppaRao Puli } // namespace redfish
861