xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision bd79bce8c3f1deb1fb2773868b9ece25233cf27b)
1e5aaf047SAppaRao Puli /*
2e5aaf047SAppaRao Puli // Copyright (c) 2020 Intel Corporation
3e5aaf047SAppaRao Puli //
4e5aaf047SAppaRao Puli // Licensed under the Apache License, Version 2.0 (the "License");
5e5aaf047SAppaRao Puli // you may not use this file except in compliance with the License.
6e5aaf047SAppaRao Puli // You may obtain a copy of the License at
7e5aaf047SAppaRao Puli //
8e5aaf047SAppaRao Puli //      http://www.apache.org/licenses/LICENSE-2.0
9e5aaf047SAppaRao Puli //
10e5aaf047SAppaRao Puli // Unless required by applicable law or agreed to in writing, software
11e5aaf047SAppaRao Puli // distributed under the License is distributed on an "AS IS" BASIS,
12e5aaf047SAppaRao Puli // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e5aaf047SAppaRao Puli // See the License for the specific language governing permissions and
14e5aaf047SAppaRao Puli // 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>
371e270c5fSPatrick Williams 
38e5aaf047SAppaRao Puli namespace redfish
39e5aaf047SAppaRao Puli {
40e5aaf047SAppaRao Puli 
41156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
42156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
43e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
44b304bd79SP Dheeraj Srujan Kumar     "Base", "OpenBMC", "TaskEvent"};
45e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
46e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
47e5aaf047SAppaRao Puli 
48e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = {
49e56f254cSSunitha Harish     "Task"};
50e56f254cSSunitha Harish 
517e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app)
52e5aaf047SAppaRao Puli {
537e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
54ed398213SEd Tanous         .privileges(redfish::privileges::getEventService)
55*bd79bce8SPatrick Williams         .methods(
56*bd79bce8SPatrick Williams             boost::beast::http::verb::
57*bd79bce8SPatrick Williams                 get)([&app](
58*bd79bce8SPatrick Williams                          const crow::Request& req,
59002d39b4SEd Tanous                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
603ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
6145ca1b86SEd Tanous             {
6245ca1b86SEd Tanous                 return;
6345ca1b86SEd Tanous             }
641476687dSEd Tanous 
651476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
661476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
671476687dSEd Tanous                 "#EventService.v1_5_0.EventService";
681476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = "EventService";
691476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "Event Service";
705e44e3d8SAppaRao Puli             asyncResp->res.jsonValue["ServerSentEventUri"] =
715e44e3d8SAppaRao Puli                 "/redfish/v1/EventService/SSE";
725e44e3d8SAppaRao Puli 
731476687dSEd Tanous             asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
741476687dSEd Tanous                 "/redfish/v1/EventService/Subscriptions";
75*bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"]
76*bd79bce8SPatrick Williams                                     ["target"] =
771476687dSEd Tanous                 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
78e5aaf047SAppaRao Puli 
7928afb49cSJunLin Chen             const persistent_data::EventServiceConfig eventServiceConfig =
8028afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
8128afb49cSJunLin Chen                     .getEventServiceConfig();
827d1cc387SAppaRao Puli 
837d1cc387SAppaRao Puli             asyncResp->res.jsonValue["Status"]["State"] =
8428afb49cSJunLin Chen                 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
85*bd79bce8SPatrick Williams             asyncResp->res.jsonValue["ServiceEnabled"] =
86*bd79bce8SPatrick Williams                 eventServiceConfig.enabled;
877e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
8828afb49cSJunLin Chen                 eventServiceConfig.retryAttempts;
89e5aaf047SAppaRao Puli             asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
9028afb49cSJunLin Chen                 eventServiceConfig.retryTimeoutInterval;
91*bd79bce8SPatrick Williams             asyncResp->res.jsonValue["EventFormatTypes"] =
92*bd79bce8SPatrick Williams                 supportedEvtFormatTypes;
930fda0f12SGeorge Liu             asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
940fda0f12SGeorge Liu             asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
9507941a88SAyushi Smriti 
96613dabeaSEd Tanous             nlohmann::json::object_t supportedSSEFilters;
97613dabeaSEd Tanous             supportedSSEFilters["EventFormatType"] = true;
98613dabeaSEd Tanous             supportedSSEFilters["MessageId"] = true;
99613dabeaSEd Tanous             supportedSSEFilters["MetricReportDefinition"] = true;
100613dabeaSEd Tanous             supportedSSEFilters["RegistryPrefix"] = true;
101613dabeaSEd Tanous             supportedSSEFilters["OriginResource"] = false;
102613dabeaSEd Tanous             supportedSSEFilters["ResourceType"] = false;
10307941a88SAyushi Smriti 
10407941a88SAyushi Smriti             asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
105613dabeaSEd Tanous                 std::move(supportedSSEFilters);
1067e860f15SJohn Edward Broadbent         });
107e5aaf047SAppaRao Puli 
1087e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
109ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
1107e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
11145ca1b86SEd Tanous             [&app](const crow::Request& req,
11245ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1133ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
114e5aaf047SAppaRao Puli                 {
11545ca1b86SEd Tanous                     return;
11645ca1b86SEd Tanous                 }
117e5aaf047SAppaRao Puli                 std::optional<bool> serviceEnabled;
118e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryAttemps;
119e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryInterval;
120e5aaf047SAppaRao Puli 
12115ed6780SWilly Tu                 if (!json_util::readJsonPatch(
1227e860f15SJohn Edward Broadbent                         req, asyncResp->res, "ServiceEnabled", serviceEnabled,
1237e860f15SJohn Edward Broadbent                         "DeliveryRetryAttempts", retryAttemps,
1247e860f15SJohn Edward Broadbent                         "DeliveryRetryIntervalSeconds", retryInterval))
125e5aaf047SAppaRao Puli                 {
126e5aaf047SAppaRao Puli                     return;
127e5aaf047SAppaRao Puli                 }
128e5aaf047SAppaRao Puli 
12928afb49cSJunLin Chen                 persistent_data::EventServiceConfig eventServiceConfig =
13028afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
13128afb49cSJunLin Chen                         .getEventServiceConfig();
1327d1cc387SAppaRao Puli 
133e5aaf047SAppaRao Puli                 if (serviceEnabled)
134e5aaf047SAppaRao Puli                 {
13528afb49cSJunLin Chen                     eventServiceConfig.enabled = *serviceEnabled;
136e5aaf047SAppaRao Puli                 }
137e5aaf047SAppaRao Puli 
138e5aaf047SAppaRao Puli                 if (retryAttemps)
139e5aaf047SAppaRao Puli                 {
140e5aaf047SAppaRao Puli                     // Supported range [1-3]
141e5aaf047SAppaRao Puli                     if ((*retryAttemps < 1) || (*retryAttemps > 3))
142e5aaf047SAppaRao Puli                     {
143e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
144e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryAttemps),
145e5aaf047SAppaRao Puli                             "DeliveryRetryAttempts", "[1-3]");
146e5aaf047SAppaRao Puli                     }
147e5aaf047SAppaRao Puli                     else
148e5aaf047SAppaRao Puli                     {
14928afb49cSJunLin Chen                         eventServiceConfig.retryAttempts = *retryAttemps;
150e5aaf047SAppaRao Puli                     }
151e5aaf047SAppaRao Puli                 }
152e5aaf047SAppaRao Puli 
153e5aaf047SAppaRao Puli                 if (retryInterval)
154e5aaf047SAppaRao Puli                 {
15533a32b34SGunnar Mills                     // Supported range [5 - 180]
15633a32b34SGunnar Mills                     if ((*retryInterval < 5) || (*retryInterval > 180))
157e5aaf047SAppaRao Puli                     {
158e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
159e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryInterval),
16033a32b34SGunnar Mills                             "DeliveryRetryIntervalSeconds", "[5-180]");
161e5aaf047SAppaRao Puli                     }
162e5aaf047SAppaRao Puli                     else
163e5aaf047SAppaRao Puli                     {
164*bd79bce8SPatrick Williams                         eventServiceConfig.retryTimeoutInterval =
165*bd79bce8SPatrick Williams                             *retryInterval;
166e5aaf047SAppaRao Puli                     }
167e5aaf047SAppaRao Puli                 }
168e5aaf047SAppaRao Puli 
1697d1cc387SAppaRao Puli                 EventServiceManager::getInstance().setEventServiceConfig(
17028afb49cSJunLin Chen                     eventServiceConfig);
1717e860f15SJohn Edward Broadbent             });
1720b4bdd93SAppaRao Puli }
1730b4bdd93SAppaRao Puli 
1747e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1750b4bdd93SAppaRao Puli {
1767e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1777e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
178ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1797e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
18045ca1b86SEd Tanous             [&app](const crow::Request& req,
1817e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1823ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
18345ca1b86SEd Tanous                 {
18445ca1b86SEd Tanous                     return;
18545ca1b86SEd Tanous                 }
1866ba8c82eSsunharis_in                 if (!EventServiceManager::getInstance().sendTestEventLog())
1876ba8c82eSsunharis_in                 {
1886ba8c82eSsunharis_in                     messages::serviceDisabled(asyncResp->res,
1896ba8c82eSsunharis_in                                               "/redfish/v1/EventService/");
1906ba8c82eSsunharis_in                     return;
1916ba8c82eSsunharis_in                 }
1928d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
1937e860f15SJohn Edward Broadbent             });
194e5aaf047SAppaRao Puli }
195e5aaf047SAppaRao Puli 
1963d30708fSChicago Duan inline void doSubscriptionCollection(
197e81de512SEd Tanous     const boost::system::error_code& ec,
1983d30708fSChicago Duan     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
1993d30708fSChicago Duan     const dbus::utility::ManagedObjectType& resp)
2003d30708fSChicago Duan {
2013d30708fSChicago Duan     if (ec)
2023d30708fSChicago Duan     {
2031306101eSEd Tanous         if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
2043d30708fSChicago Duan         {
2053d30708fSChicago Duan             // This is an optional process so just return if it isn't there
2063d30708fSChicago Duan             return;
2073d30708fSChicago Duan         }
2083d30708fSChicago Duan 
20962598e31SEd Tanous         BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
2103d30708fSChicago Duan         messages::internalError(asyncResp->res);
2113d30708fSChicago Duan         return;
2123d30708fSChicago Duan     }
2133d30708fSChicago Duan     nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
2143d30708fSChicago Duan     for (const auto& objpath : resp)
2153d30708fSChicago Duan     {
2163d30708fSChicago Duan         sdbusplus::message::object_path path(objpath.first);
2173d30708fSChicago Duan         const std::string snmpId = path.filename();
2183d30708fSChicago Duan         if (snmpId.empty())
2193d30708fSChicago Duan         {
22062598e31SEd Tanous             BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
2213d30708fSChicago Duan             messages::internalError(asyncResp->res);
2223d30708fSChicago Duan             return;
2233d30708fSChicago Duan         }
2243d30708fSChicago Duan 
2253d30708fSChicago Duan         getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
2263d30708fSChicago Duan     }
2273d30708fSChicago Duan }
2283d30708fSChicago Duan 
2297e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
230e5aaf047SAppaRao Puli {
2311ebe3e41SGayathri Leburu     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
232ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
2337e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
23445ca1b86SEd Tanous             [&app](const crow::Request& req,
2357e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2363ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
23745ca1b86SEd Tanous                 {
23845ca1b86SEd Tanous                     return;
23945ca1b86SEd Tanous                 }
2401476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
2411476687dSEd Tanous                     "#EventDestinationCollection.EventDestinationCollection";
2421476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
2431476687dSEd Tanous                     "/redfish/v1/EventService/Subscriptions";
244*bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Name"] =
245*bd79bce8SPatrick Williams                     "Event Destination Collections";
246e5aaf047SAppaRao Puli 
247*bd79bce8SPatrick Williams                 nlohmann::json& memberArray =
248*bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["Members"];
249e5aaf047SAppaRao Puli 
250b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
251b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
252b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
253*bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Members@odata.count"] =
254*bd79bce8SPatrick Williams                     subscripIds.size();
255b52664e2SAppaRao Puli 
256b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
257e5aaf047SAppaRao Puli                 {
2581476687dSEd Tanous                     nlohmann::json::object_t member;
2593d30708fSChicago Duan                     member["@odata.id"] = boost::urls::format(
2603d30708fSChicago Duan                         "/redfish/v1/EventService/Subscriptions/{}" + id);
261b2ba3072SPatrick Williams                     memberArray.emplace_back(std::move(member));
262e5aaf047SAppaRao Puli                 }
2633d30708fSChicago Duan                 crow::connections::systemBus->async_method_call(
264e81de512SEd Tanous                     [asyncResp](const boost::system::error_code& ec,
2653d30708fSChicago Duan                                 const dbus::utility::ManagedObjectType& resp) {
2663d30708fSChicago Duan                         doSubscriptionCollection(ec, asyncResp, resp);
2673d30708fSChicago Duan                     },
2683d30708fSChicago Duan                     "xyz.openbmc_project.Network.SNMP",
2693d30708fSChicago Duan                     "/xyz/openbmc_project/network/snmp/manager",
2703d30708fSChicago Duan                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
2717e860f15SJohn Edward Broadbent             });
2723d30708fSChicago Duan 
2737e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
2747eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
275*bd79bce8SPatrick Williams         .methods(
276*bd79bce8SPatrick Williams             boost::beast::http::verb::
277*bd79bce8SPatrick Williams                 post)([&app](
278*bd79bce8SPatrick Williams                           const crow::Request& req,
2797e860f15SJohn Edward Broadbent                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2803ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
28145ca1b86SEd Tanous             {
28245ca1b86SEd Tanous                 return;
28345ca1b86SEd Tanous             }
284fffb8c1fSEd Tanous             if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
285fffb8c1fSEd Tanous                 maxNoOfSubscriptions)
286e5aaf047SAppaRao Puli             {
287e5aaf047SAppaRao Puli                 messages::eventSubscriptionLimitExceeded(asyncResp->res);
288e5aaf047SAppaRao Puli                 return;
289e5aaf047SAppaRao Puli             }
290e5aaf047SAppaRao Puli             std::string destUrl;
291e5aaf047SAppaRao Puli             std::string protocol;
29219bb362bSEd Tanous             std::optional<bool> verifyCertificate;
293e5aaf047SAppaRao Puli             std::optional<std::string> context;
294e5aaf047SAppaRao Puli             std::optional<std::string> subscriptionType;
29523a21a1cSEd Tanous             std::optional<std::string> eventFormatType2;
296e5aaf047SAppaRao Puli             std::optional<std::string> retryPolicy;
297e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> msgIds;
298e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> regPrefixes;
299e56f254cSSunitha Harish             std::optional<std::vector<std::string>> resTypes;
30078d4ec4fSEd Tanous             std::optional<std::vector<nlohmann::json::object_t>> headers;
30178d4ec4fSEd Tanous             std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
302e5aaf047SAppaRao Puli 
30315ed6780SWilly Tu             if (!json_util::readJsonPatch(
304*bd79bce8SPatrick Williams                     req, asyncResp->res, "Destination", destUrl, "Context",
305*bd79bce8SPatrick Williams                     context, "Protocol", protocol, "SubscriptionType",
306*bd79bce8SPatrick Williams                     subscriptionType, "EventFormatType", eventFormatType2,
307*bd79bce8SPatrick Williams                     "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
308*bd79bce8SPatrick Williams                     "MessageIds", msgIds, "DeliveryRetryPolicy", retryPolicy,
309*bd79bce8SPatrick Williams                     "MetricReportDefinitions", mrdJsonArray, "ResourceTypes",
310*bd79bce8SPatrick Williams                     resTypes, "VerifyCertificate", verifyCertificate))
311e5aaf047SAppaRao Puli             {
312e5aaf047SAppaRao Puli                 return;
313e5aaf047SAppaRao Puli             }
314e5aaf047SAppaRao Puli 
315600af5f1SAppaRao Puli             // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
316600af5f1SAppaRao Puli             static constexpr const uint16_t maxDestinationSize = 2000;
317600af5f1SAppaRao Puli             if (destUrl.size() > maxDestinationSize)
318600af5f1SAppaRao Puli             {
319600af5f1SAppaRao Puli                 messages::stringValueTooLong(asyncResp->res, "Destination",
320600af5f1SAppaRao Puli                                              maxDestinationSize);
321600af5f1SAppaRao Puli                 return;
322600af5f1SAppaRao Puli             }
323600af5f1SAppaRao Puli 
324dd28ba82SAppaRao Puli             if (regPrefixes && msgIds)
325dd28ba82SAppaRao Puli             {
32626f6976fSEd Tanous                 if (!regPrefixes->empty() && !msgIds->empty())
327dd28ba82SAppaRao Puli                 {
328*bd79bce8SPatrick Williams                     messages::propertyValueConflict(
329*bd79bce8SPatrick Williams                         asyncResp->res, "MessageIds", "RegistryPrefixes");
330dd28ba82SAppaRao Puli                     return;
331dd28ba82SAppaRao Puli                 }
332dd28ba82SAppaRao Puli             }
333dd28ba82SAppaRao Puli 
3346fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
335a716aa74SEd Tanous                 boost::urls::parse_absolute_uri(destUrl);
336a716aa74SEd Tanous             if (!url)
337e5aaf047SAppaRao Puli             {
338*bd79bce8SPatrick Williams                 BMCWEB_LOG_WARNING(
339*bd79bce8SPatrick Williams                     "Failed to validate and split destination url");
340e5aaf047SAppaRao Puli                 messages::propertyValueFormatError(asyncResp->res, destUrl,
341e5aaf047SAppaRao Puli                                                    "Destination");
342e5aaf047SAppaRao Puli                 return;
343e5aaf047SAppaRao Puli             }
344a716aa74SEd Tanous             url->normalize();
345a716aa74SEd Tanous             crow::utility::setProtocolDefaults(*url, protocol);
346a716aa74SEd Tanous             crow::utility::setPortDefaults(*url);
347a716aa74SEd Tanous 
348a716aa74SEd Tanous             if (url->path().empty())
349a716aa74SEd Tanous             {
350a716aa74SEd Tanous                 url->set_path("/");
351a716aa74SEd Tanous             }
352a716aa74SEd Tanous 
353a716aa74SEd Tanous             if (url->has_userinfo())
354a716aa74SEd Tanous             {
355a716aa74SEd Tanous                 messages::propertyValueFormatError(asyncResp->res, destUrl,
356a716aa74SEd Tanous                                                    "Destination");
357a716aa74SEd Tanous                 return;
358a716aa74SEd Tanous             }
359b52664e2SAppaRao Puli 
3603d30708fSChicago Duan             if (protocol == "SNMPv2c")
3613d30708fSChicago Duan             {
3623d30708fSChicago Duan                 if (context)
3633d30708fSChicago Duan                 {
3643d30708fSChicago Duan                     messages::propertyValueConflict(asyncResp->res, "Context",
3653d30708fSChicago Duan                                                     "Protocol");
3663d30708fSChicago Duan                     return;
3673d30708fSChicago Duan                 }
3683d30708fSChicago Duan                 if (eventFormatType2)
3693d30708fSChicago Duan                 {
370*bd79bce8SPatrick Williams                     messages::propertyValueConflict(
371*bd79bce8SPatrick Williams                         asyncResp->res, "EventFormatType", "Protocol");
3723d30708fSChicago Duan                     return;
3733d30708fSChicago Duan                 }
3743d30708fSChicago Duan                 if (retryPolicy)
3753d30708fSChicago Duan                 {
376*bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
377*bd79bce8SPatrick Williams                                                     "RetryPolicy", "Protocol");
3783d30708fSChicago Duan                     return;
3793d30708fSChicago Duan                 }
3803d30708fSChicago Duan                 if (msgIds)
3813d30708fSChicago Duan                 {
382*bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
383*bd79bce8SPatrick Williams                                                     "MessageIds", "Protocol");
3843d30708fSChicago Duan                     return;
3853d30708fSChicago Duan                 }
3863d30708fSChicago Duan                 if (regPrefixes)
3873d30708fSChicago Duan                 {
388*bd79bce8SPatrick Williams                     messages::propertyValueConflict(
389*bd79bce8SPatrick Williams                         asyncResp->res, "RegistryPrefixes", "Protocol");
3903d30708fSChicago Duan                     return;
3913d30708fSChicago Duan                 }
3923d30708fSChicago Duan                 if (resTypes)
3933d30708fSChicago Duan                 {
394*bd79bce8SPatrick Williams                     messages::propertyValueConflict(
395*bd79bce8SPatrick Williams                         asyncResp->res, "ResourceTypes", "Protocol");
3963d30708fSChicago Duan                     return;
3973d30708fSChicago Duan                 }
3983d30708fSChicago Duan                 if (headers)
3993d30708fSChicago Duan                 {
400*bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
401*bd79bce8SPatrick Williams                                                     "HttpHeaders", "Protocol");
4023d30708fSChicago Duan                     return;
4033d30708fSChicago Duan                 }
4043d30708fSChicago Duan                 if (mrdJsonArray)
4053d30708fSChicago Duan                 {
4063d30708fSChicago Duan                     messages::propertyValueConflict(
4073d30708fSChicago Duan                         asyncResp->res, "MetricReportDefinitions", "Protocol");
4083d30708fSChicago Duan                     return;
4093d30708fSChicago Duan                 }
410a716aa74SEd Tanous                 if (url->scheme() != "snmp")
411a716aa74SEd Tanous                 {
412*bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
413*bd79bce8SPatrick Williams                                                     "Destination", "Protocol");
4143d30708fSChicago Duan                     return;
4153d30708fSChicago Duan                 }
4163d30708fSChicago Duan 
417a716aa74SEd Tanous                 addSnmpTrapClient(asyncResp, url->host_address(),
418a716aa74SEd Tanous                                   url->port_number());
419a716aa74SEd Tanous                 return;
420b52664e2SAppaRao Puli             }
4213d30708fSChicago Duan 
422a716aa74SEd Tanous             std::shared_ptr<Subscription> subValue =
423a716aa74SEd Tanous                 std::make_shared<Subscription>(*url, app.ioContext());
424b52664e2SAppaRao Puli 
425a716aa74SEd Tanous             subValue->destinationUrl = std::move(*url);
426e5aaf047SAppaRao Puli 
427e5aaf047SAppaRao Puli             if (subscriptionType)
428e5aaf047SAppaRao Puli             {
429e5aaf047SAppaRao Puli                 if (*subscriptionType != "RedfishEvent")
430e5aaf047SAppaRao Puli                 {
431fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
432fffb8c1fSEd Tanous                         asyncResp->res, *subscriptionType, "SubscriptionType");
433e5aaf047SAppaRao Puli                     return;
434e5aaf047SAppaRao Puli                 }
435b52664e2SAppaRao Puli                 subValue->subscriptionType = *subscriptionType;
436e5aaf047SAppaRao Puli             }
437e5aaf047SAppaRao Puli             else
438e5aaf047SAppaRao Puli             {
439b52664e2SAppaRao Puli                 subValue->subscriptionType = "RedfishEvent"; // Default
440e5aaf047SAppaRao Puli             }
441e5aaf047SAppaRao Puli 
442e5aaf047SAppaRao Puli             if (protocol != "Redfish")
443e5aaf047SAppaRao Puli             {
444e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, protocol,
445e5aaf047SAppaRao Puli                                                  "Protocol");
446e5aaf047SAppaRao Puli                 return;
447e5aaf047SAppaRao Puli             }
448b52664e2SAppaRao Puli             subValue->protocol = protocol;
449e5aaf047SAppaRao Puli 
45019bb362bSEd Tanous             if (verifyCertificate)
45119bb362bSEd Tanous             {
45219bb362bSEd Tanous                 subValue->verifyCertificate = *verifyCertificate;
45319bb362bSEd Tanous             }
45419bb362bSEd Tanous 
45523a21a1cSEd Tanous             if (eventFormatType2)
456e5aaf047SAppaRao Puli             {
457*bd79bce8SPatrick Williams                 if (std::ranges::find(supportedEvtFormatTypes,
458*bd79bce8SPatrick Williams                                       *eventFormatType2) ==
4593544d2a7SEd Tanous                     supportedEvtFormatTypes.end())
460e5aaf047SAppaRao Puli                 {
461fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
462fffb8c1fSEd Tanous                         asyncResp->res, *eventFormatType2, "EventFormatType");
463e5aaf047SAppaRao Puli                     return;
464e5aaf047SAppaRao Puli                 }
46523a21a1cSEd Tanous                 subValue->eventFormatType = *eventFormatType2;
466e5aaf047SAppaRao Puli             }
467e5aaf047SAppaRao Puli             else
468e5aaf047SAppaRao Puli             {
469e5aaf047SAppaRao Puli                 // If not specified, use default "Event"
47023a21a1cSEd Tanous                 subValue->eventFormatType = "Event";
471e5aaf047SAppaRao Puli             }
472e5aaf047SAppaRao Puli 
473e5aaf047SAppaRao Puli             if (context)
474e5aaf047SAppaRao Puli             {
4758ece0e45SEd Tanous                 // This value is selected arbitrarily.
476600af5f1SAppaRao Puli                 constexpr const size_t maxContextSize = 256;
477600af5f1SAppaRao Puli                 if (context->size() > maxContextSize)
478600af5f1SAppaRao Puli                 {
479600af5f1SAppaRao Puli                     messages::stringValueTooLong(asyncResp->res, "Context",
480600af5f1SAppaRao Puli                                                  maxContextSize);
481600af5f1SAppaRao Puli                     return;
482600af5f1SAppaRao Puli                 }
483b52664e2SAppaRao Puli                 subValue->customText = *context;
484e5aaf047SAppaRao Puli             }
485e5aaf047SAppaRao Puli 
486e5aaf047SAppaRao Puli             if (headers)
487e5aaf047SAppaRao Puli             {
488600af5f1SAppaRao Puli                 size_t cumulativeLen = 0;
489600af5f1SAppaRao Puli 
49078d4ec4fSEd Tanous                 for (const nlohmann::json::object_t& headerChunk : *headers)
491601c71aeSEd Tanous                 {
49278d4ec4fSEd Tanous                     for (const auto& item : headerChunk)
49378d4ec4fSEd Tanous                     {
49478d4ec4fSEd Tanous                         const std::string* value =
49578d4ec4fSEd Tanous                             item.second.get_ptr<const std::string*>();
49678d4ec4fSEd Tanous                         if (value == nullptr)
49778d4ec4fSEd Tanous                         {
49878d4ec4fSEd Tanous                             messages::propertyValueFormatError(
49978d4ec4fSEd Tanous                                 asyncResp->res, item.second,
50078d4ec4fSEd Tanous                                 "HttpHeaders/" + item.first);
50178d4ec4fSEd Tanous                             return;
50278d4ec4fSEd Tanous                         }
50378d4ec4fSEd Tanous                         // Adding a new json value is the size of the key, +
50478d4ec4fSEd Tanous                         // the size of the value + 2 * 2 quotes for each, +
50578d4ec4fSEd Tanous                         // the colon and space between. example:
50678d4ec4fSEd Tanous                         // "key": "value"
50778d4ec4fSEd Tanous                         cumulativeLen += item.first.size() + value->size() + 6;
508600af5f1SAppaRao Puli                         // This value is selected to mirror http_connection.hpp
509600af5f1SAppaRao Puli                         constexpr const uint16_t maxHeaderSizeED = 8096;
510600af5f1SAppaRao Puli                         if (cumulativeLen > maxHeaderSizeED)
511600af5f1SAppaRao Puli                         {
51278d4ec4fSEd Tanous                             messages::arraySizeTooLong(
51378d4ec4fSEd Tanous                                 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
514600af5f1SAppaRao Puli                             return;
515600af5f1SAppaRao Puli                         }
51678d4ec4fSEd Tanous                         subValue->httpHeaders.set(item.first, *value);
517601c71aeSEd Tanous                     }
518601c71aeSEd Tanous                 }
519e5aaf047SAppaRao Puli             }
520e5aaf047SAppaRao Puli 
521e5aaf047SAppaRao Puli             if (regPrefixes)
522e5aaf047SAppaRao Puli             {
523e5aaf047SAppaRao Puli                 for (const std::string& it : *regPrefixes)
524e5aaf047SAppaRao Puli                 {
5253544d2a7SEd Tanous                     if (std::ranges::find(supportedRegPrefixes, it) ==
5263544d2a7SEd Tanous                         supportedRegPrefixes.end())
527e5aaf047SAppaRao Puli                     {
528fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
529fffb8c1fSEd Tanous                                                          "RegistryPrefixes");
530e5aaf047SAppaRao Puli                         return;
531e5aaf047SAppaRao Puli                     }
532e5aaf047SAppaRao Puli                 }
533b52664e2SAppaRao Puli                 subValue->registryPrefixes = *regPrefixes;
534e5aaf047SAppaRao Puli             }
535e5aaf047SAppaRao Puli 
536e56f254cSSunitha Harish             if (resTypes)
537e56f254cSSunitha Harish             {
538e56f254cSSunitha Harish                 for (const std::string& it : *resTypes)
539e56f254cSSunitha Harish                 {
5403544d2a7SEd Tanous                     if (std::ranges::find(supportedResourceTypes, it) ==
5413544d2a7SEd Tanous                         supportedResourceTypes.end())
542e56f254cSSunitha Harish                     {
543e56f254cSSunitha Harish                         messages::propertyValueNotInList(asyncResp->res, it,
544e56f254cSSunitha Harish                                                          "ResourceTypes");
545e56f254cSSunitha Harish                         return;
546e56f254cSSunitha Harish                     }
547e56f254cSSunitha Harish                 }
548e56f254cSSunitha Harish                 subValue->resourceTypes = *resTypes;
549e56f254cSSunitha Harish             }
550e56f254cSSunitha Harish 
551e5aaf047SAppaRao Puli             if (msgIds)
552e5aaf047SAppaRao Puli             {
553b304bd79SP Dheeraj Srujan Kumar                 std::vector<std::string> registryPrefix;
554b304bd79SP Dheeraj Srujan Kumar 
5557e860f15SJohn Edward Broadbent                 // If no registry prefixes are mentioned, consider all
5567e860f15SJohn Edward Broadbent                 // supported prefixes
557b304bd79SP Dheeraj Srujan Kumar                 if (subValue->registryPrefixes.empty())
558b304bd79SP Dheeraj Srujan Kumar                 {
559b304bd79SP Dheeraj Srujan Kumar                     registryPrefix.assign(supportedRegPrefixes.begin(),
560b304bd79SP Dheeraj Srujan Kumar                                           supportedRegPrefixes.end());
561b304bd79SP Dheeraj Srujan Kumar                 }
562b304bd79SP Dheeraj Srujan Kumar                 else
563b304bd79SP Dheeraj Srujan Kumar                 {
564b304bd79SP Dheeraj Srujan Kumar                     registryPrefix = subValue->registryPrefixes;
565b304bd79SP Dheeraj Srujan Kumar                 }
566b304bd79SP Dheeraj Srujan Kumar 
567b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& id : *msgIds)
568b304bd79SP Dheeraj Srujan Kumar                 {
569b304bd79SP Dheeraj Srujan Kumar                     bool validId = false;
570b304bd79SP Dheeraj Srujan Kumar 
571b304bd79SP Dheeraj Srujan Kumar                     // Check for Message ID in each of the selected Registry
572b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& it : registryPrefix)
573b304bd79SP Dheeraj Srujan Kumar                     {
574fffb8c1fSEd Tanous                         const std::span<const redfish::registries::MessageEntry>
575fffb8c1fSEd Tanous                             registry =
576fffb8c1fSEd Tanous                                 redfish::registries::getRegistryFromPrefix(it);
577b304bd79SP Dheeraj Srujan Kumar 
5783544d2a7SEd Tanous                         if (std::ranges::any_of(
5793544d2a7SEd Tanous                                 registry,
580fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
581fffb8c1fSEd Tanous                                           messageEntry) {
58255f79e6fSEd Tanous                                     return id == messageEntry.first;
583b304bd79SP Dheeraj Srujan Kumar                                 }))
584b304bd79SP Dheeraj Srujan Kumar                         {
585b304bd79SP Dheeraj Srujan Kumar                             validId = true;
586b304bd79SP Dheeraj Srujan Kumar                             break;
587b304bd79SP Dheeraj Srujan Kumar                         }
588b304bd79SP Dheeraj Srujan Kumar                     }
589b304bd79SP Dheeraj Srujan Kumar 
590b304bd79SP Dheeraj Srujan Kumar                     if (!validId)
591b304bd79SP Dheeraj Srujan Kumar                     {
592b304bd79SP Dheeraj Srujan Kumar                         messages::propertyValueNotInList(asyncResp->res, id,
593b304bd79SP Dheeraj Srujan Kumar                                                          "MessageIds");
594b304bd79SP Dheeraj Srujan Kumar                         return;
595b304bd79SP Dheeraj Srujan Kumar                     }
596b304bd79SP Dheeraj Srujan Kumar                 }
597b304bd79SP Dheeraj Srujan Kumar 
598b52664e2SAppaRao Puli                 subValue->registryMsgIds = *msgIds;
599e5aaf047SAppaRao Puli             }
600e5aaf047SAppaRao Puli 
601e5aaf047SAppaRao Puli             if (retryPolicy)
602e5aaf047SAppaRao Puli             {
6033544d2a7SEd Tanous                 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
6043544d2a7SEd Tanous                     supportedRetryPolicies.end())
605e5aaf047SAppaRao Puli                 {
606*bd79bce8SPatrick Williams                     messages::propertyValueNotInList(
607*bd79bce8SPatrick Williams                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
608e5aaf047SAppaRao Puli                     return;
609e5aaf047SAppaRao Puli                 }
610b52664e2SAppaRao Puli                 subValue->retryPolicy = *retryPolicy;
611e5aaf047SAppaRao Puli             }
612e5aaf047SAppaRao Puli             else
613e5aaf047SAppaRao Puli             {
614e5aaf047SAppaRao Puli                 // Default "TerminateAfterRetries"
615b52664e2SAppaRao Puli                 subValue->retryPolicy = "TerminateAfterRetries";
616e5aaf047SAppaRao Puli             }
617e5aaf047SAppaRao Puli 
618144b6318SAppaRao Puli             if (mrdJsonArray)
619156d6b00SAppaRao Puli             {
62078d4ec4fSEd Tanous                 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
621144b6318SAppaRao Puli                 {
622144b6318SAppaRao Puli                     std::string mrdUri;
623ea2e6eecSWilly Tu 
62478d4ec4fSEd Tanous                     if (!json_util::readJsonObject(mrdObj, asyncResp->res,
62578d4ec4fSEd Tanous                                                    "@odata.id", mrdUri))
626ea2e6eecSWilly Tu 
627144b6318SAppaRao Puli                     {
628144b6318SAppaRao Puli                         return;
629144b6318SAppaRao Puli                     }
630ea2e6eecSWilly Tu                     subValue->metricReportDefinitions.emplace_back(mrdUri);
631144b6318SAppaRao Puli                 }
632156d6b00SAppaRao Puli             }
633156d6b00SAppaRao Puli 
634b52664e2SAppaRao Puli             std::string id =
635*bd79bce8SPatrick Williams                 EventServiceManager::getInstance().addPushSubscription(
636*bd79bce8SPatrick Williams                     subValue);
637b52664e2SAppaRao Puli             if (id.empty())
638e5aaf047SAppaRao Puli             {
639e5aaf047SAppaRao Puli                 messages::internalError(asyncResp->res);
640e5aaf047SAppaRao Puli                 return;
641e5aaf047SAppaRao Puli             }
642e5aaf047SAppaRao Puli 
643e5aaf047SAppaRao Puli             messages::created(asyncResp->res);
644e5aaf047SAppaRao Puli             asyncResp->res.addHeader(
645e5aaf047SAppaRao Puli                 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
6467e860f15SJohn Edward Broadbent         });
647e5aaf047SAppaRao Puli }
648e5aaf047SAppaRao Puli 
6497e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
650e5aaf047SAppaRao Puli {
6519d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
652ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
6537e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
65445ca1b86SEd Tanous             [&app](const crow::Request& req,
6557e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6567e860f15SJohn Edward Broadbent                    const std::string& param) {
6573ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
65845ca1b86SEd Tanous                 {
65945ca1b86SEd Tanous                     return;
66045ca1b86SEd Tanous                 }
6613d30708fSChicago Duan 
6623d30708fSChicago Duan                 if (param.starts_with("snmp"))
6633d30708fSChicago Duan                 {
6643d30708fSChicago Duan                     getSnmpTrapClient(asyncResp, param);
6653d30708fSChicago Duan                     return;
6663d30708fSChicago Duan                 }
6673d30708fSChicago Duan 
668b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
6697e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
670b52664e2SAppaRao Puli                 if (subValue == nullptr)
671e5aaf047SAppaRao Puli                 {
672*bd79bce8SPatrick Williams                     asyncResp->res.result(
673*bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
674e5aaf047SAppaRao Puli                     return;
675e5aaf047SAppaRao Puli                 }
6767e860f15SJohn Edward Broadbent                 const std::string& id = param;
677e5aaf047SAppaRao Puli 
6781476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
6793d30708fSChicago Duan                     "#EventDestination.v1_8_0.EventDestination";
680539d8c6bSEd Tanous                 asyncResp->res.jsonValue["Protocol"] =
681539d8c6bSEd Tanous                     event_destination::EventDestinationProtocol::Redfish;
6823b32780dSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] = boost::urls::format(
6833b32780dSEd Tanous                     "/redfish/v1/EventService/Subscriptions/{}", id);
684e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Id"] = id;
685e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
686*bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Destination"] =
687*bd79bce8SPatrick Williams                     subValue->destinationUrl;
688b52664e2SAppaRao Puli                 asyncResp->res.jsonValue["Context"] = subValue->customText;
689e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["SubscriptionType"] =
690b52664e2SAppaRao Puli                     subValue->subscriptionType;
691*bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["HttpHeaders"] =
692*bd79bce8SPatrick Williams                     nlohmann::json::array();
693*bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["EventFormatType"] =
694*bd79bce8SPatrick Williams                     subValue->eventFormatType;
695e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["RegistryPrefixes"] =
696b52664e2SAppaRao Puli                     subValue->registryPrefixes;
697*bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["ResourceTypes"] =
698*bd79bce8SPatrick Williams                     subValue->resourceTypes;
699e56f254cSSunitha Harish 
700*bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["MessageIds"] =
701*bd79bce8SPatrick Williams                     subValue->registryMsgIds;
702*bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
703*bd79bce8SPatrick Williams                     subValue->retryPolicy;
70419bb362bSEd Tanous                 asyncResp->res.jsonValue["VerifyCertificate"] =
70519bb362bSEd Tanous                     subValue->verifyCertificate;
706144b6318SAppaRao Puli 
7071476687dSEd Tanous                 nlohmann::json::array_t mrdJsonArray;
708144b6318SAppaRao Puli                 for (const auto& mdrUri : subValue->metricReportDefinitions)
709144b6318SAppaRao Puli                 {
7101476687dSEd Tanous                     nlohmann::json::object_t mdr;
7111476687dSEd Tanous                     mdr["@odata.id"] = mdrUri;
7121476687dSEd Tanous                     mrdJsonArray.emplace_back(std::move(mdr));
713144b6318SAppaRao Puli                 }
714*bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["MetricReportDefinitions"] =
715*bd79bce8SPatrick Williams                     mrdJsonArray;
7167e860f15SJohn Edward Broadbent             });
7179d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
718ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
719ed398213SEd Tanous         // ConfigureSelf
7207eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
721ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
722432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
7237e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
72445ca1b86SEd Tanous             [&app](const crow::Request& req,
7257e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7267e860f15SJohn Edward Broadbent                    const std::string& param) {
7273ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
72845ca1b86SEd Tanous                 {
72945ca1b86SEd Tanous                     return;
73045ca1b86SEd Tanous                 }
731b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
7327e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
733b52664e2SAppaRao Puli                 if (subValue == nullptr)
734e5aaf047SAppaRao Puli                 {
735*bd79bce8SPatrick Williams                     asyncResp->res.result(
736*bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
737e5aaf047SAppaRao Puli                     return;
738e5aaf047SAppaRao Puli                 }
739e5aaf047SAppaRao Puli 
740e5aaf047SAppaRao Puli                 std::optional<std::string> context;
741e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
74219bb362bSEd Tanous                 std::optional<bool> verifyCertificate;
74378d4ec4fSEd Tanous                 std::optional<std::vector<nlohmann::json::object_t>> headers;
744e5aaf047SAppaRao Puli 
745*bd79bce8SPatrick Williams                 if (!json_util::readJsonPatch(
746*bd79bce8SPatrick Williams                         req, asyncResp->res, "Context", context,
74719bb362bSEd Tanous                         "VerifyCertificate", verifyCertificate,
748*bd79bce8SPatrick Williams                         "DeliveryRetryPolicy", retryPolicy, "HttpHeaders",
749*bd79bce8SPatrick Williams                         headers))
750e5aaf047SAppaRao Puli                 {
751e5aaf047SAppaRao Puli                     return;
752e5aaf047SAppaRao Puli                 }
753e5aaf047SAppaRao Puli 
754e5aaf047SAppaRao Puli                 if (context)
755e5aaf047SAppaRao Puli                 {
756b52664e2SAppaRao Puli                     subValue->customText = *context;
757e5aaf047SAppaRao Puli                 }
758e5aaf047SAppaRao Puli 
759e5aaf047SAppaRao Puli                 if (headers)
760e5aaf047SAppaRao Puli                 {
761601c71aeSEd Tanous                     boost::beast::http::fields fields;
76278d4ec4fSEd Tanous                     for (const nlohmann::json::object_t& headerChunk : *headers)
763601c71aeSEd Tanous                     {
76478d4ec4fSEd Tanous                         for (const auto& it : headerChunk)
765601c71aeSEd Tanous                         {
766601c71aeSEd Tanous                             const std::string* value =
76778d4ec4fSEd Tanous                                 it.second.get_ptr<const std::string*>();
768601c71aeSEd Tanous                             if (value == nullptr)
769601c71aeSEd Tanous                             {
770601c71aeSEd Tanous                                 messages::propertyValueFormatError(
77178d4ec4fSEd Tanous                                     asyncResp->res, it.second,
77278d4ec4fSEd Tanous                                     "HttpHeaders/" + it.first);
773601c71aeSEd Tanous                                 return;
774601c71aeSEd Tanous                             }
77578d4ec4fSEd Tanous                             fields.set(it.first, *value);
776601c71aeSEd Tanous                         }
777601c71aeSEd Tanous                     }
77878d4ec4fSEd Tanous                     subValue->httpHeaders = std::move(fields);
779e5aaf047SAppaRao Puli                 }
780e5aaf047SAppaRao Puli 
781e5aaf047SAppaRao Puli                 if (retryPolicy)
782e5aaf047SAppaRao Puli                 {
783*bd79bce8SPatrick Williams                     if (std::ranges::find(supportedRetryPolicies,
784*bd79bce8SPatrick Williams                                           *retryPolicy) ==
7853544d2a7SEd Tanous                         supportedRetryPolicies.end())
786e5aaf047SAppaRao Puli                     {
787*bd79bce8SPatrick Williams                         messages::propertyValueNotInList(asyncResp->res,
788*bd79bce8SPatrick Williams                                                          *retryPolicy,
789e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
790e5aaf047SAppaRao Puli                         return;
791e5aaf047SAppaRao Puli                     }
792b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
793e5aaf047SAppaRao Puli                 }
794e5aaf047SAppaRao Puli 
79519bb362bSEd Tanous                 if (verifyCertificate)
79619bb362bSEd Tanous                 {
79719bb362bSEd Tanous                     subValue->verifyCertificate = *verifyCertificate;
79819bb362bSEd Tanous                 }
79919bb362bSEd Tanous 
800b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
8017e860f15SJohn Edward Broadbent             });
8029d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
803ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
804ed398213SEd Tanous         // ConfigureSelf
8057eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
806ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
807432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
8087e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
80945ca1b86SEd Tanous             [&app](const crow::Request& req,
8107e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8117e860f15SJohn Edward Broadbent                    const std::string& param) {
8123ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
81345ca1b86SEd Tanous                 {
81445ca1b86SEd Tanous                     return;
81545ca1b86SEd Tanous                 }
8163d30708fSChicago Duan 
8173d30708fSChicago Duan                 if (param.starts_with("snmp"))
8183d30708fSChicago Duan                 {
8193d30708fSChicago Duan                     deleteSnmpTrapClient(asyncResp, param);
820*bd79bce8SPatrick Williams                     EventServiceManager::getInstance().deleteSubscription(
821*bd79bce8SPatrick Williams                         param);
8223d30708fSChicago Duan                     return;
8233d30708fSChicago Duan                 }
8243d30708fSChicago Duan 
825*bd79bce8SPatrick Williams                 if (!EventServiceManager::getInstance().isSubscriptionExist(
826*bd79bce8SPatrick Williams                         param))
827e5aaf047SAppaRao Puli                 {
828*bd79bce8SPatrick Williams                     asyncResp->res.result(
829*bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
830e5aaf047SAppaRao Puli                     return;
831e5aaf047SAppaRao Puli                 }
8327e860f15SJohn Edward Broadbent                 EventServiceManager::getInstance().deleteSubscription(param);
8337e860f15SJohn Edward Broadbent             });
834e5aaf047SAppaRao Puli }
835e5aaf047SAppaRao Puli 
836e5aaf047SAppaRao Puli } // namespace redfish
837