xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision d109e2b60f7bb367dc8115475c6cb86bca6e1914)
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"
23*d109e2b6SAlexander Hansen #include "registries.hpp"
243ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
25*d109e2b6SAlexander Hansen #include "registries_selector.hpp"
263d30708fSChicago Duan #include "snmp_trap_event_clients.hpp"
27*d109e2b6SAlexander Hansen #include "utils/json_utils.hpp"
28e5aaf047SAppaRao Puli 
29601c71aeSEd Tanous #include <boost/beast/http/fields.hpp>
303d30708fSChicago Duan #include <boost/system/error_code.hpp>
31a716aa74SEd Tanous #include <boost/url/parse.hpp>
323d30708fSChicago Duan #include <sdbusplus/unpack_properties.hpp>
333d30708fSChicago Duan #include <utils/dbus_utils.hpp>
34ed398213SEd Tanous 
353d30708fSChicago Duan #include <charconv>
363d30708fSChicago Duan #include <memory>
373544d2a7SEd Tanous #include <ranges>
381e270c5fSPatrick Williams #include <span>
393d30708fSChicago Duan #include <string>
40a14c9113SEd Tanous #include <vector>
411e270c5fSPatrick Williams 
42e5aaf047SAppaRao Puli namespace redfish
43e5aaf047SAppaRao Puli {
44e5aaf047SAppaRao Puli 
45156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
46156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
47e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
48b304bd79SP Dheeraj Srujan Kumar     "Base", "OpenBMC", "TaskEvent"};
49e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
50e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
51e5aaf047SAppaRao Puli 
52e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = {
53e56f254cSSunitha Harish     "Task"};
54e56f254cSSunitha Harish 
557e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app)
56e5aaf047SAppaRao Puli {
577e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
58ed398213SEd Tanous         .privileges(redfish::privileges::getEventService)
59bd79bce8SPatrick Williams         .methods(
60bd79bce8SPatrick Williams             boost::beast::http::verb::
61bd79bce8SPatrick Williams                 get)([&app](
62bd79bce8SPatrick Williams                          const crow::Request& req,
63002d39b4SEd Tanous                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
643ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
6545ca1b86SEd Tanous             {
6645ca1b86SEd Tanous                 return;
6745ca1b86SEd Tanous             }
681476687dSEd Tanous 
691476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
701476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
711476687dSEd Tanous                 "#EventService.v1_5_0.EventService";
721476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = "EventService";
731476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "Event Service";
745e44e3d8SAppaRao Puli             asyncResp->res.jsonValue["ServerSentEventUri"] =
755e44e3d8SAppaRao Puli                 "/redfish/v1/EventService/SSE";
765e44e3d8SAppaRao Puli 
771476687dSEd Tanous             asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
781476687dSEd Tanous                 "/redfish/v1/EventService/Subscriptions";
79bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"]
80bd79bce8SPatrick Williams                                     ["target"] =
811476687dSEd Tanous                 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
82e5aaf047SAppaRao Puli 
8328afb49cSJunLin Chen             const persistent_data::EventServiceConfig eventServiceConfig =
8428afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
8528afb49cSJunLin Chen                     .getEventServiceConfig();
867d1cc387SAppaRao Puli 
877d1cc387SAppaRao Puli             asyncResp->res.jsonValue["Status"]["State"] =
8828afb49cSJunLin Chen                 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
89bd79bce8SPatrick Williams             asyncResp->res.jsonValue["ServiceEnabled"] =
90bd79bce8SPatrick Williams                 eventServiceConfig.enabled;
917e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
9228afb49cSJunLin Chen                 eventServiceConfig.retryAttempts;
93e5aaf047SAppaRao Puli             asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
9428afb49cSJunLin Chen                 eventServiceConfig.retryTimeoutInterval;
95bd79bce8SPatrick Williams             asyncResp->res.jsonValue["EventFormatTypes"] =
96bd79bce8SPatrick Williams                 supportedEvtFormatTypes;
970fda0f12SGeorge Liu             asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
980fda0f12SGeorge Liu             asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
9907941a88SAyushi Smriti 
100613dabeaSEd Tanous             nlohmann::json::object_t supportedSSEFilters;
101613dabeaSEd Tanous             supportedSSEFilters["EventFormatType"] = true;
102613dabeaSEd Tanous             supportedSSEFilters["MessageId"] = true;
103613dabeaSEd Tanous             supportedSSEFilters["MetricReportDefinition"] = true;
104613dabeaSEd Tanous             supportedSSEFilters["RegistryPrefix"] = true;
105613dabeaSEd Tanous             supportedSSEFilters["OriginResource"] = false;
106613dabeaSEd Tanous             supportedSSEFilters["ResourceType"] = false;
10707941a88SAyushi Smriti 
10807941a88SAyushi Smriti             asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
109613dabeaSEd Tanous                 std::move(supportedSSEFilters);
1107e860f15SJohn Edward Broadbent         });
111e5aaf047SAppaRao Puli 
1127e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
113ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
1147e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
11545ca1b86SEd Tanous             [&app](const crow::Request& req,
11645ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1173ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
118e5aaf047SAppaRao Puli                 {
11945ca1b86SEd Tanous                     return;
12045ca1b86SEd Tanous                 }
121e5aaf047SAppaRao Puli                 std::optional<bool> serviceEnabled;
122e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryAttemps;
123e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryInterval;
124afc474aeSMyung Bae                 if (!json_util::readJsonPatch( //
125afc474aeSMyung Bae                         req, asyncResp->res, //
126afc474aeSMyung Bae                         "DeliveryRetryAttempts", retryAttemps, //
127afc474aeSMyung Bae                         "DeliveryRetryIntervalSeconds", retryInterval, //
128afc474aeSMyung Bae                         "ServiceEnabled", serviceEnabled //
129afc474aeSMyung Bae                         ))
130e5aaf047SAppaRao Puli                 {
131e5aaf047SAppaRao Puli                     return;
132e5aaf047SAppaRao Puli                 }
133e5aaf047SAppaRao Puli 
13428afb49cSJunLin Chen                 persistent_data::EventServiceConfig eventServiceConfig =
13528afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
13628afb49cSJunLin Chen                         .getEventServiceConfig();
1377d1cc387SAppaRao Puli 
138e5aaf047SAppaRao Puli                 if (serviceEnabled)
139e5aaf047SAppaRao Puli                 {
14028afb49cSJunLin Chen                     eventServiceConfig.enabled = *serviceEnabled;
141e5aaf047SAppaRao Puli                 }
142e5aaf047SAppaRao Puli 
143e5aaf047SAppaRao Puli                 if (retryAttemps)
144e5aaf047SAppaRao Puli                 {
145e5aaf047SAppaRao Puli                     // Supported range [1-3]
146e5aaf047SAppaRao Puli                     if ((*retryAttemps < 1) || (*retryAttemps > 3))
147e5aaf047SAppaRao Puli                     {
148e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
149e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryAttemps),
150e5aaf047SAppaRao Puli                             "DeliveryRetryAttempts", "[1-3]");
151e5aaf047SAppaRao Puli                     }
152e5aaf047SAppaRao Puli                     else
153e5aaf047SAppaRao Puli                     {
15428afb49cSJunLin Chen                         eventServiceConfig.retryAttempts = *retryAttemps;
155e5aaf047SAppaRao Puli                     }
156e5aaf047SAppaRao Puli                 }
157e5aaf047SAppaRao Puli 
158e5aaf047SAppaRao Puli                 if (retryInterval)
159e5aaf047SAppaRao Puli                 {
16033a32b34SGunnar Mills                     // Supported range [5 - 180]
16133a32b34SGunnar Mills                     if ((*retryInterval < 5) || (*retryInterval > 180))
162e5aaf047SAppaRao Puli                     {
163e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
164e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryInterval),
16533a32b34SGunnar Mills                             "DeliveryRetryIntervalSeconds", "[5-180]");
166e5aaf047SAppaRao Puli                     }
167e5aaf047SAppaRao Puli                     else
168e5aaf047SAppaRao Puli                     {
169bd79bce8SPatrick Williams                         eventServiceConfig.retryTimeoutInterval =
170bd79bce8SPatrick Williams                             *retryInterval;
171e5aaf047SAppaRao Puli                     }
172e5aaf047SAppaRao Puli                 }
173e5aaf047SAppaRao Puli 
1747d1cc387SAppaRao Puli                 EventServiceManager::getInstance().setEventServiceConfig(
17528afb49cSJunLin Chen                     eventServiceConfig);
1767e860f15SJohn Edward Broadbent             });
1770b4bdd93SAppaRao Puli }
1780b4bdd93SAppaRao Puli 
1797e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1800b4bdd93SAppaRao Puli {
1817e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1827e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
183ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1847e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
18545ca1b86SEd Tanous             [&app](const crow::Request& req,
1867e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1873ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
18845ca1b86SEd Tanous                 {
18945ca1b86SEd Tanous                     return;
19045ca1b86SEd Tanous                 }
1916ba8c82eSsunharis_in                 if (!EventServiceManager::getInstance().sendTestEventLog())
1926ba8c82eSsunharis_in                 {
1936ba8c82eSsunharis_in                     messages::serviceDisabled(asyncResp->res,
1946ba8c82eSsunharis_in                                               "/redfish/v1/EventService/");
1956ba8c82eSsunharis_in                     return;
1966ba8c82eSsunharis_in                 }
1978d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
1987e860f15SJohn Edward Broadbent             });
199e5aaf047SAppaRao Puli }
200e5aaf047SAppaRao Puli 
2013d30708fSChicago Duan inline void doSubscriptionCollection(
202e81de512SEd Tanous     const boost::system::error_code& ec,
2033d30708fSChicago Duan     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2043d30708fSChicago Duan     const dbus::utility::ManagedObjectType& resp)
2053d30708fSChicago Duan {
2063d30708fSChicago Duan     if (ec)
2073d30708fSChicago Duan     {
2081306101eSEd Tanous         if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
2093d30708fSChicago Duan         {
2103d30708fSChicago Duan             // This is an optional process so just return if it isn't there
2113d30708fSChicago Duan             return;
2123d30708fSChicago Duan         }
2133d30708fSChicago Duan 
21462598e31SEd Tanous         BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
2153d30708fSChicago Duan         messages::internalError(asyncResp->res);
2163d30708fSChicago Duan         return;
2173d30708fSChicago Duan     }
2183d30708fSChicago Duan     nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
2193d30708fSChicago Duan     for (const auto& objpath : resp)
2203d30708fSChicago Duan     {
2213d30708fSChicago Duan         sdbusplus::message::object_path path(objpath.first);
2223d30708fSChicago Duan         const std::string snmpId = path.filename();
2233d30708fSChicago Duan         if (snmpId.empty())
2243d30708fSChicago Duan         {
22562598e31SEd Tanous             BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
2263d30708fSChicago Duan             messages::internalError(asyncResp->res);
2273d30708fSChicago Duan             return;
2283d30708fSChicago Duan         }
2293d30708fSChicago Duan 
2303d30708fSChicago Duan         getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
2313d30708fSChicago Duan     }
2323d30708fSChicago Duan }
2333d30708fSChicago Duan 
2347e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
235e5aaf047SAppaRao Puli {
2361ebe3e41SGayathri Leburu     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
237ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
2387e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
23945ca1b86SEd Tanous             [&app](const crow::Request& req,
2407e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2413ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
24245ca1b86SEd Tanous                 {
24345ca1b86SEd Tanous                     return;
24445ca1b86SEd Tanous                 }
2451476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
2461476687dSEd Tanous                     "#EventDestinationCollection.EventDestinationCollection";
2471476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
2481476687dSEd Tanous                     "/redfish/v1/EventService/Subscriptions";
249bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Name"] =
250bd79bce8SPatrick Williams                     "Event Destination Collections";
251e5aaf047SAppaRao Puli 
252bd79bce8SPatrick Williams                 nlohmann::json& memberArray =
253bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["Members"];
254e5aaf047SAppaRao Puli 
255b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
256b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
257b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
258bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Members@odata.count"] =
259bd79bce8SPatrick Williams                     subscripIds.size();
260b52664e2SAppaRao Puli 
261b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
262e5aaf047SAppaRao Puli                 {
2631476687dSEd Tanous                     nlohmann::json::object_t member;
2643d30708fSChicago Duan                     member["@odata.id"] = boost::urls::format(
2653d30708fSChicago Duan                         "/redfish/v1/EventService/Subscriptions/{}" + id);
266b2ba3072SPatrick Williams                     memberArray.emplace_back(std::move(member));
267e5aaf047SAppaRao Puli                 }
2683d30708fSChicago Duan                 crow::connections::systemBus->async_method_call(
269e81de512SEd Tanous                     [asyncResp](const boost::system::error_code& ec,
2703d30708fSChicago Duan                                 const dbus::utility::ManagedObjectType& resp) {
2713d30708fSChicago Duan                         doSubscriptionCollection(ec, asyncResp, resp);
2723d30708fSChicago Duan                     },
2733d30708fSChicago Duan                     "xyz.openbmc_project.Network.SNMP",
2743d30708fSChicago Duan                     "/xyz/openbmc_project/network/snmp/manager",
2753d30708fSChicago Duan                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
2767e860f15SJohn Edward Broadbent             });
2773d30708fSChicago Duan 
2787e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
2797eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
280bd79bce8SPatrick Williams         .methods(
281bd79bce8SPatrick Williams             boost::beast::http::verb::
282bd79bce8SPatrick Williams                 post)([&app](
283bd79bce8SPatrick Williams                           const crow::Request& req,
2847e860f15SJohn Edward Broadbent                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2853ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
28645ca1b86SEd Tanous             {
28745ca1b86SEd Tanous                 return;
28845ca1b86SEd Tanous             }
289fffb8c1fSEd Tanous             if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
290fffb8c1fSEd Tanous                 maxNoOfSubscriptions)
291e5aaf047SAppaRao Puli             {
292e5aaf047SAppaRao Puli                 messages::eventSubscriptionLimitExceeded(asyncResp->res);
293e5aaf047SAppaRao Puli                 return;
294e5aaf047SAppaRao Puli             }
295e5aaf047SAppaRao Puli             std::string destUrl;
296e5aaf047SAppaRao Puli             std::string protocol;
29719bb362bSEd Tanous             std::optional<bool> verifyCertificate;
298e5aaf047SAppaRao Puli             std::optional<std::string> context;
299e5aaf047SAppaRao Puli             std::optional<std::string> subscriptionType;
30023a21a1cSEd Tanous             std::optional<std::string> eventFormatType2;
301e5aaf047SAppaRao Puli             std::optional<std::string> retryPolicy;
302e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> msgIds;
303e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> regPrefixes;
304a14c9113SEd Tanous             std::optional<std::vector<std::string>> originResources;
305e56f254cSSunitha Harish             std::optional<std::vector<std::string>> resTypes;
30678d4ec4fSEd Tanous             std::optional<std::vector<nlohmann::json::object_t>> headers;
30778d4ec4fSEd Tanous             std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
308e5aaf047SAppaRao Puli 
309afc474aeSMyung Bae             if (!json_util::readJsonPatch( //
310afc474aeSMyung Bae                     req, asyncResp->res, //
311afc474aeSMyung Bae                     "Context", context, //
312afc474aeSMyung Bae                     "DeliveryRetryPolicy", retryPolicy, //
313afc474aeSMyung Bae                     "Destination", destUrl, //
314afc474aeSMyung Bae                     "EventFormatType", eventFormatType2, //
315afc474aeSMyung Bae                     "HttpHeaders", headers, //
316afc474aeSMyung Bae                     "MessageIds", msgIds, //
317afc474aeSMyung Bae                     "MetricReportDefinitions", mrdJsonArray, //
318afc474aeSMyung Bae                     "OriginResources", originResources, //
319afc474aeSMyung Bae                     "Protocol", protocol, //
320afc474aeSMyung Bae                     "RegistryPrefixes", regPrefixes, //
321afc474aeSMyung Bae                     "ResourceTypes", resTypes, //
322afc474aeSMyung Bae                     "SubscriptionType", subscriptionType, //
323afc474aeSMyung Bae                     "VerifyCertificate", verifyCertificate //
3244b712a29SEd Tanous                     ))
325e5aaf047SAppaRao Puli             {
326e5aaf047SAppaRao Puli                 return;
327e5aaf047SAppaRao Puli             }
3284b712a29SEd Tanous             // clang-format on
329e5aaf047SAppaRao Puli 
330600af5f1SAppaRao Puli             // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
331600af5f1SAppaRao Puli             static constexpr const uint16_t maxDestinationSize = 2000;
332600af5f1SAppaRao Puli             if (destUrl.size() > maxDestinationSize)
333600af5f1SAppaRao Puli             {
334600af5f1SAppaRao Puli                 messages::stringValueTooLong(asyncResp->res, "Destination",
335600af5f1SAppaRao Puli                                              maxDestinationSize);
336600af5f1SAppaRao Puli                 return;
337600af5f1SAppaRao Puli             }
338600af5f1SAppaRao Puli 
339dd28ba82SAppaRao Puli             if (regPrefixes && msgIds)
340dd28ba82SAppaRao Puli             {
34126f6976fSEd Tanous                 if (!regPrefixes->empty() && !msgIds->empty())
342dd28ba82SAppaRao Puli                 {
343bd79bce8SPatrick Williams                     messages::propertyValueConflict(
344bd79bce8SPatrick Williams                         asyncResp->res, "MessageIds", "RegistryPrefixes");
345dd28ba82SAppaRao Puli                     return;
346dd28ba82SAppaRao Puli                 }
347dd28ba82SAppaRao Puli             }
348dd28ba82SAppaRao Puli 
3496fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
350a716aa74SEd Tanous                 boost::urls::parse_absolute_uri(destUrl);
351a716aa74SEd Tanous             if (!url)
352e5aaf047SAppaRao Puli             {
353bd79bce8SPatrick Williams                 BMCWEB_LOG_WARNING(
354bd79bce8SPatrick Williams                     "Failed to validate and split destination url");
355e5aaf047SAppaRao Puli                 messages::propertyValueFormatError(asyncResp->res, destUrl,
356e5aaf047SAppaRao Puli                                                    "Destination");
357e5aaf047SAppaRao Puli                 return;
358e5aaf047SAppaRao Puli             }
359a716aa74SEd Tanous             url->normalize();
360b07942e3SGeorge Liu 
361b07942e3SGeorge Liu             // port_number returns zero if it is not a valid representable port
362b07942e3SGeorge Liu             if (url->has_port() && url->port_number() == 0)
363b07942e3SGeorge Liu             {
364b07942e3SGeorge Liu                 BMCWEB_LOG_WARNING("{} is an invalid port in destination url",
365b07942e3SGeorge Liu                                    url->port());
366b07942e3SGeorge Liu                 messages::propertyValueFormatError(asyncResp->res, destUrl,
367b07942e3SGeorge Liu                                                    "Destination");
368b07942e3SGeorge Liu                 return;
369b07942e3SGeorge Liu             }
370b07942e3SGeorge Liu 
371a716aa74SEd Tanous             crow::utility::setProtocolDefaults(*url, protocol);
372a716aa74SEd Tanous             crow::utility::setPortDefaults(*url);
373a716aa74SEd Tanous 
374a716aa74SEd Tanous             if (url->path().empty())
375a716aa74SEd Tanous             {
376a716aa74SEd Tanous                 url->set_path("/");
377a716aa74SEd Tanous             }
378a716aa74SEd Tanous 
379a716aa74SEd Tanous             if (url->has_userinfo())
380a716aa74SEd Tanous             {
381a716aa74SEd Tanous                 messages::propertyValueFormatError(asyncResp->res, destUrl,
382a716aa74SEd Tanous                                                    "Destination");
383a716aa74SEd Tanous                 return;
384a716aa74SEd Tanous             }
385b52664e2SAppaRao Puli 
3863d30708fSChicago Duan             if (protocol == "SNMPv2c")
3873d30708fSChicago Duan             {
3883d30708fSChicago Duan                 if (context)
3893d30708fSChicago Duan                 {
3903d30708fSChicago Duan                     messages::propertyValueConflict(asyncResp->res, "Context",
3913d30708fSChicago Duan                                                     "Protocol");
3923d30708fSChicago Duan                     return;
3933d30708fSChicago Duan                 }
3943d30708fSChicago Duan                 if (eventFormatType2)
3953d30708fSChicago Duan                 {
396bd79bce8SPatrick Williams                     messages::propertyValueConflict(
397bd79bce8SPatrick Williams                         asyncResp->res, "EventFormatType", "Protocol");
3983d30708fSChicago Duan                     return;
3993d30708fSChicago Duan                 }
4003d30708fSChicago Duan                 if (retryPolicy)
4013d30708fSChicago Duan                 {
402bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
403bd79bce8SPatrick Williams                                                     "RetryPolicy", "Protocol");
4043d30708fSChicago Duan                     return;
4053d30708fSChicago Duan                 }
4063d30708fSChicago Duan                 if (msgIds)
4073d30708fSChicago Duan                 {
408bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
409bd79bce8SPatrick Williams                                                     "MessageIds", "Protocol");
4103d30708fSChicago Duan                     return;
4113d30708fSChicago Duan                 }
4123d30708fSChicago Duan                 if (regPrefixes)
4133d30708fSChicago Duan                 {
414bd79bce8SPatrick Williams                     messages::propertyValueConflict(
415bd79bce8SPatrick Williams                         asyncResp->res, "RegistryPrefixes", "Protocol");
4163d30708fSChicago Duan                     return;
4173d30708fSChicago Duan                 }
4183d30708fSChicago Duan                 if (resTypes)
4193d30708fSChicago Duan                 {
420bd79bce8SPatrick Williams                     messages::propertyValueConflict(
421bd79bce8SPatrick Williams                         asyncResp->res, "ResourceTypes", "Protocol");
4223d30708fSChicago Duan                     return;
4233d30708fSChicago Duan                 }
4243d30708fSChicago Duan                 if (headers)
4253d30708fSChicago Duan                 {
426bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
427bd79bce8SPatrick Williams                                                     "HttpHeaders", "Protocol");
4283d30708fSChicago Duan                     return;
4293d30708fSChicago Duan                 }
4303d30708fSChicago Duan                 if (mrdJsonArray)
4313d30708fSChicago Duan                 {
4323d30708fSChicago Duan                     messages::propertyValueConflict(
4333d30708fSChicago Duan                         asyncResp->res, "MetricReportDefinitions", "Protocol");
4343d30708fSChicago Duan                     return;
4353d30708fSChicago Duan                 }
436a716aa74SEd Tanous                 if (url->scheme() != "snmp")
437a716aa74SEd Tanous                 {
438bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
439bd79bce8SPatrick Williams                                                     "Destination", "Protocol");
4403d30708fSChicago Duan                     return;
4413d30708fSChicago Duan                 }
4423d30708fSChicago Duan 
443a716aa74SEd Tanous                 addSnmpTrapClient(asyncResp, url->host_address(),
444a716aa74SEd Tanous                                   url->port_number());
445a716aa74SEd Tanous                 return;
446b52664e2SAppaRao Puli             }
4473d30708fSChicago Duan 
448a716aa74SEd Tanous             std::shared_ptr<Subscription> subValue =
44921a94d5cSMyung Bae                 std::make_shared<Subscription>(
4505fe4ef35SMyung Bae                     std::make_shared<persistent_data::UserSubscription>(), *url,
4515fe4ef35SMyung Bae                     app.ioContext());
452e5aaf047SAppaRao Puli 
453e5aaf047SAppaRao Puli             if (subscriptionType)
454e5aaf047SAppaRao Puli             {
455e5aaf047SAppaRao Puli                 if (*subscriptionType != "RedfishEvent")
456e5aaf047SAppaRao Puli                 {
457fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
458fffb8c1fSEd Tanous                         asyncResp->res, *subscriptionType, "SubscriptionType");
459e5aaf047SAppaRao Puli                     return;
460e5aaf047SAppaRao Puli                 }
4615fe4ef35SMyung Bae                 subValue->userSub->subscriptionType = *subscriptionType;
462e5aaf047SAppaRao Puli             }
463e5aaf047SAppaRao Puli             else
464e5aaf047SAppaRao Puli             {
4654b712a29SEd Tanous                 // Default
4665fe4ef35SMyung Bae                 subValue->userSub->subscriptionType = "RedfishEvent";
467e5aaf047SAppaRao Puli             }
468e5aaf047SAppaRao Puli 
469e5aaf047SAppaRao Puli             if (protocol != "Redfish")
470e5aaf047SAppaRao Puli             {
471e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, protocol,
472e5aaf047SAppaRao Puli                                                  "Protocol");
473e5aaf047SAppaRao Puli                 return;
474e5aaf047SAppaRao Puli             }
4755fe4ef35SMyung Bae             subValue->userSub->protocol = protocol;
476e5aaf047SAppaRao Puli 
47719bb362bSEd Tanous             if (verifyCertificate)
47819bb362bSEd Tanous             {
4795fe4ef35SMyung Bae                 subValue->userSub->verifyCertificate = *verifyCertificate;
48019bb362bSEd Tanous             }
48119bb362bSEd Tanous 
48223a21a1cSEd Tanous             if (eventFormatType2)
483e5aaf047SAppaRao Puli             {
484bd79bce8SPatrick Williams                 if (std::ranges::find(supportedEvtFormatTypes,
485bd79bce8SPatrick Williams                                       *eventFormatType2) ==
4863544d2a7SEd Tanous                     supportedEvtFormatTypes.end())
487e5aaf047SAppaRao Puli                 {
488fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
489fffb8c1fSEd Tanous                         asyncResp->res, *eventFormatType2, "EventFormatType");
490e5aaf047SAppaRao Puli                     return;
491e5aaf047SAppaRao Puli                 }
4925fe4ef35SMyung Bae                 subValue->userSub->eventFormatType = *eventFormatType2;
493e5aaf047SAppaRao Puli             }
494e5aaf047SAppaRao Puli             else
495e5aaf047SAppaRao Puli             {
496e5aaf047SAppaRao Puli                 // If not specified, use default "Event"
4975fe4ef35SMyung Bae                 subValue->userSub->eventFormatType = "Event";
498e5aaf047SAppaRao Puli             }
499e5aaf047SAppaRao Puli 
500e5aaf047SAppaRao Puli             if (context)
501e5aaf047SAppaRao Puli             {
5028ece0e45SEd Tanous                 // This value is selected arbitrarily.
503600af5f1SAppaRao Puli                 constexpr const size_t maxContextSize = 256;
504600af5f1SAppaRao Puli                 if (context->size() > maxContextSize)
505600af5f1SAppaRao Puli                 {
506600af5f1SAppaRao Puli                     messages::stringValueTooLong(asyncResp->res, "Context",
507600af5f1SAppaRao Puli                                                  maxContextSize);
508600af5f1SAppaRao Puli                     return;
509600af5f1SAppaRao Puli                 }
5105fe4ef35SMyung Bae                 subValue->userSub->customText = *context;
511e5aaf047SAppaRao Puli             }
512e5aaf047SAppaRao Puli 
513e5aaf047SAppaRao Puli             if (headers)
514e5aaf047SAppaRao Puli             {
515600af5f1SAppaRao Puli                 size_t cumulativeLen = 0;
516600af5f1SAppaRao Puli 
51778d4ec4fSEd Tanous                 for (const nlohmann::json::object_t& headerChunk : *headers)
518601c71aeSEd Tanous                 {
51978d4ec4fSEd Tanous                     for (const auto& item : headerChunk)
52078d4ec4fSEd Tanous                     {
52178d4ec4fSEd Tanous                         const std::string* value =
52278d4ec4fSEd Tanous                             item.second.get_ptr<const std::string*>();
52378d4ec4fSEd Tanous                         if (value == nullptr)
52478d4ec4fSEd Tanous                         {
52578d4ec4fSEd Tanous                             messages::propertyValueFormatError(
52678d4ec4fSEd Tanous                                 asyncResp->res, item.second,
52778d4ec4fSEd Tanous                                 "HttpHeaders/" + item.first);
52878d4ec4fSEd Tanous                             return;
52978d4ec4fSEd Tanous                         }
53078d4ec4fSEd Tanous                         // Adding a new json value is the size of the key, +
53178d4ec4fSEd Tanous                         // the size of the value + 2 * 2 quotes for each, +
53278d4ec4fSEd Tanous                         // the colon and space between. example:
53378d4ec4fSEd Tanous                         // "key": "value"
53478d4ec4fSEd Tanous                         cumulativeLen += item.first.size() + value->size() + 6;
535600af5f1SAppaRao Puli                         // This value is selected to mirror http_connection.hpp
536600af5f1SAppaRao Puli                         constexpr const uint16_t maxHeaderSizeED = 8096;
537600af5f1SAppaRao Puli                         if (cumulativeLen > maxHeaderSizeED)
538600af5f1SAppaRao Puli                         {
53978d4ec4fSEd Tanous                             messages::arraySizeTooLong(
54078d4ec4fSEd Tanous                                 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
541600af5f1SAppaRao Puli                             return;
542600af5f1SAppaRao Puli                         }
5435fe4ef35SMyung Bae                         subValue->userSub->httpHeaders.set(item.first, *value);
544601c71aeSEd Tanous                     }
545601c71aeSEd Tanous                 }
546e5aaf047SAppaRao Puli             }
547e5aaf047SAppaRao Puli 
548e5aaf047SAppaRao Puli             if (regPrefixes)
549e5aaf047SAppaRao Puli             {
550e5aaf047SAppaRao Puli                 for (const std::string& it : *regPrefixes)
551e5aaf047SAppaRao Puli                 {
5523544d2a7SEd Tanous                     if (std::ranges::find(supportedRegPrefixes, it) ==
5533544d2a7SEd Tanous                         supportedRegPrefixes.end())
554e5aaf047SAppaRao Puli                     {
555fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
556fffb8c1fSEd Tanous                                                          "RegistryPrefixes");
557e5aaf047SAppaRao Puli                         return;
558e5aaf047SAppaRao Puli                     }
559e5aaf047SAppaRao Puli                 }
5605fe4ef35SMyung Bae                 subValue->userSub->registryPrefixes = *regPrefixes;
561e5aaf047SAppaRao Puli             }
562e5aaf047SAppaRao Puli 
563a14c9113SEd Tanous             if (originResources)
564a14c9113SEd Tanous             {
5655fe4ef35SMyung Bae                 subValue->userSub->originResources = *originResources;
566a14c9113SEd Tanous             }
567a14c9113SEd Tanous 
568e56f254cSSunitha Harish             if (resTypes)
569e56f254cSSunitha Harish             {
570e56f254cSSunitha Harish                 for (const std::string& it : *resTypes)
571e56f254cSSunitha Harish                 {
5723544d2a7SEd Tanous                     if (std::ranges::find(supportedResourceTypes, it) ==
5733544d2a7SEd Tanous                         supportedResourceTypes.end())
574e56f254cSSunitha Harish                     {
575e56f254cSSunitha Harish                         messages::propertyValueNotInList(asyncResp->res, it,
576e56f254cSSunitha Harish                                                          "ResourceTypes");
577e56f254cSSunitha Harish                         return;
578e56f254cSSunitha Harish                     }
579e56f254cSSunitha Harish                 }
5805fe4ef35SMyung Bae                 subValue->userSub->resourceTypes = *resTypes;
581e56f254cSSunitha Harish             }
582e56f254cSSunitha Harish 
583e5aaf047SAppaRao Puli             if (msgIds)
584e5aaf047SAppaRao Puli             {
585b304bd79SP Dheeraj Srujan Kumar                 std::vector<std::string> registryPrefix;
586b304bd79SP Dheeraj Srujan Kumar 
5877e860f15SJohn Edward Broadbent                 // If no registry prefixes are mentioned, consider all
5887e860f15SJohn Edward Broadbent                 // supported prefixes
5895fe4ef35SMyung Bae                 if (subValue->userSub->registryPrefixes.empty())
590b304bd79SP Dheeraj Srujan Kumar                 {
591b304bd79SP Dheeraj Srujan Kumar                     registryPrefix.assign(supportedRegPrefixes.begin(),
592b304bd79SP Dheeraj Srujan Kumar                                           supportedRegPrefixes.end());
593b304bd79SP Dheeraj Srujan Kumar                 }
594b304bd79SP Dheeraj Srujan Kumar                 else
595b304bd79SP Dheeraj Srujan Kumar                 {
5965fe4ef35SMyung Bae                     registryPrefix = subValue->userSub->registryPrefixes;
597b304bd79SP Dheeraj Srujan Kumar                 }
598b304bd79SP Dheeraj Srujan Kumar 
599b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& id : *msgIds)
600b304bd79SP Dheeraj Srujan Kumar                 {
601b304bd79SP Dheeraj Srujan Kumar                     bool validId = false;
602b304bd79SP Dheeraj Srujan Kumar 
603b304bd79SP Dheeraj Srujan Kumar                     // Check for Message ID in each of the selected Registry
604b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& it : registryPrefix)
605b304bd79SP Dheeraj Srujan Kumar                     {
606fffb8c1fSEd Tanous                         const std::span<const redfish::registries::MessageEntry>
607fffb8c1fSEd Tanous                             registry =
608fffb8c1fSEd Tanous                                 redfish::registries::getRegistryFromPrefix(it);
609b304bd79SP Dheeraj Srujan Kumar 
6103544d2a7SEd Tanous                         if (std::ranges::any_of(
6113544d2a7SEd Tanous                                 registry,
612fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
613fffb8c1fSEd Tanous                                           messageEntry) {
61455f79e6fSEd Tanous                                     return id == messageEntry.first;
615b304bd79SP Dheeraj Srujan Kumar                                 }))
616b304bd79SP Dheeraj Srujan Kumar                         {
617b304bd79SP Dheeraj Srujan Kumar                             validId = true;
618b304bd79SP Dheeraj Srujan Kumar                             break;
619b304bd79SP Dheeraj Srujan Kumar                         }
620b304bd79SP Dheeraj Srujan Kumar                     }
621b304bd79SP Dheeraj Srujan Kumar 
622b304bd79SP Dheeraj Srujan Kumar                     if (!validId)
623b304bd79SP Dheeraj Srujan Kumar                     {
624b304bd79SP Dheeraj Srujan Kumar                         messages::propertyValueNotInList(asyncResp->res, id,
625b304bd79SP Dheeraj Srujan Kumar                                                          "MessageIds");
626b304bd79SP Dheeraj Srujan Kumar                         return;
627b304bd79SP Dheeraj Srujan Kumar                     }
628b304bd79SP Dheeraj Srujan Kumar                 }
629b304bd79SP Dheeraj Srujan Kumar 
6305fe4ef35SMyung Bae                 subValue->userSub->registryMsgIds = *msgIds;
631e5aaf047SAppaRao Puli             }
632e5aaf047SAppaRao Puli 
633e5aaf047SAppaRao Puli             if (retryPolicy)
634e5aaf047SAppaRao Puli             {
6353544d2a7SEd Tanous                 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
6363544d2a7SEd Tanous                     supportedRetryPolicies.end())
637e5aaf047SAppaRao Puli                 {
638bd79bce8SPatrick Williams                     messages::propertyValueNotInList(
639bd79bce8SPatrick Williams                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
640e5aaf047SAppaRao Puli                     return;
641e5aaf047SAppaRao Puli                 }
6425fe4ef35SMyung Bae                 subValue->userSub->retryPolicy = *retryPolicy;
643e5aaf047SAppaRao Puli             }
644e5aaf047SAppaRao Puli             else
645e5aaf047SAppaRao Puli             {
646e5aaf047SAppaRao Puli                 // Default "TerminateAfterRetries"
6475fe4ef35SMyung Bae                 subValue->userSub->retryPolicy = "TerminateAfterRetries";
648e5aaf047SAppaRao Puli             }
649e5aaf047SAppaRao Puli 
650144b6318SAppaRao Puli             if (mrdJsonArray)
651156d6b00SAppaRao Puli             {
65278d4ec4fSEd Tanous                 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
653144b6318SAppaRao Puli                 {
654144b6318SAppaRao Puli                     std::string mrdUri;
655ea2e6eecSWilly Tu 
65678d4ec4fSEd Tanous                     if (!json_util::readJsonObject(mrdObj, asyncResp->res,
65778d4ec4fSEd Tanous                                                    "@odata.id", mrdUri))
658ea2e6eecSWilly Tu 
659144b6318SAppaRao Puli                     {
660144b6318SAppaRao Puli                         return;
661144b6318SAppaRao Puli                     }
6625fe4ef35SMyung Bae                     subValue->userSub->metricReportDefinitions.emplace_back(
6634b712a29SEd Tanous                         mrdUri);
664144b6318SAppaRao Puli                 }
665156d6b00SAppaRao Puli             }
666156d6b00SAppaRao Puli 
667b52664e2SAppaRao Puli             std::string id =
668bd79bce8SPatrick Williams                 EventServiceManager::getInstance().addPushSubscription(
669bd79bce8SPatrick Williams                     subValue);
670b52664e2SAppaRao Puli             if (id.empty())
671e5aaf047SAppaRao Puli             {
672e5aaf047SAppaRao Puli                 messages::internalError(asyncResp->res);
673e5aaf047SAppaRao Puli                 return;
674e5aaf047SAppaRao Puli             }
675e5aaf047SAppaRao Puli 
676e5aaf047SAppaRao Puli             messages::created(asyncResp->res);
677e5aaf047SAppaRao Puli             asyncResp->res.addHeader(
678e5aaf047SAppaRao Puli                 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
6797e860f15SJohn Edward Broadbent         });
680e5aaf047SAppaRao Puli }
681e5aaf047SAppaRao Puli 
6827e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
683e5aaf047SAppaRao Puli {
6849d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
685ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
6867e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
68745ca1b86SEd Tanous             [&app](const crow::Request& req,
6887e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6897e860f15SJohn Edward Broadbent                    const std::string& param) {
6903ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
69145ca1b86SEd Tanous                 {
69245ca1b86SEd Tanous                     return;
69345ca1b86SEd Tanous                 }
6943d30708fSChicago Duan 
6953d30708fSChicago Duan                 if (param.starts_with("snmp"))
6963d30708fSChicago Duan                 {
6973d30708fSChicago Duan                     getSnmpTrapClient(asyncResp, param);
6983d30708fSChicago Duan                     return;
6993d30708fSChicago Duan                 }
7003d30708fSChicago Duan 
701b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
7027e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
703b52664e2SAppaRao Puli                 if (subValue == nullptr)
704e5aaf047SAppaRao Puli                 {
705bd79bce8SPatrick Williams                     asyncResp->res.result(
706bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
707e5aaf047SAppaRao Puli                     return;
708e5aaf047SAppaRao Puli                 }
7097e860f15SJohn Edward Broadbent                 const std::string& id = param;
710e5aaf047SAppaRao Puli 
7114b712a29SEd Tanous                 const persistent_data::UserSubscription& userSub =
7125fe4ef35SMyung Bae                     *subValue->userSub;
713e56f254cSSunitha Harish 
7144b712a29SEd Tanous                 nlohmann::json& jVal = asyncResp->res.jsonValue;
7154b712a29SEd Tanous                 jVal["@odata.type"] =
7164b712a29SEd Tanous                     "#EventDestination.v1_14_1.EventDestination";
7174b712a29SEd Tanous                 jVal["Protocol"] =
7184b712a29SEd Tanous                     event_destination::EventDestinationProtocol::Redfish;
7194b712a29SEd Tanous                 jVal["@odata.id"] = boost::urls::format(
7204b712a29SEd Tanous                     "/redfish/v1/EventService/Subscriptions/{}", id);
7214b712a29SEd Tanous                 jVal["Id"] = id;
7224b712a29SEd Tanous                 jVal["Name"] = "Event Destination " + id;
7234b712a29SEd Tanous                 jVal["Destination"] = userSub.destinationUrl;
7244b712a29SEd Tanous                 jVal["Context"] = userSub.customText;
7254b712a29SEd Tanous                 jVal["SubscriptionType"] = userSub.subscriptionType;
7264b712a29SEd Tanous                 jVal["HttpHeaders"] = nlohmann::json::array();
7274b712a29SEd Tanous                 jVal["EventFormatType"] = userSub.eventFormatType;
7284b712a29SEd Tanous                 jVal["RegistryPrefixes"] = userSub.registryPrefixes;
7294b712a29SEd Tanous                 jVal["ResourceTypes"] = userSub.resourceTypes;
7304b712a29SEd Tanous 
7314b712a29SEd Tanous                 jVal["MessageIds"] = userSub.registryMsgIds;
7324b712a29SEd Tanous                 jVal["DeliveryRetryPolicy"] = userSub.retryPolicy;
7334b712a29SEd Tanous                 jVal["VerifyCertificate"] = userSub.verifyCertificate;
734144b6318SAppaRao Puli 
7351476687dSEd Tanous                 nlohmann::json::array_t mrdJsonArray;
7364b712a29SEd Tanous                 for (const auto& mdrUri : userSub.metricReportDefinitions)
737144b6318SAppaRao Puli                 {
7381476687dSEd Tanous                     nlohmann::json::object_t mdr;
7391476687dSEd Tanous                     mdr["@odata.id"] = mdrUri;
7401476687dSEd Tanous                     mrdJsonArray.emplace_back(std::move(mdr));
741144b6318SAppaRao Puli                 }
7424b712a29SEd Tanous                 jVal["MetricReportDefinitions"] = mrdJsonArray;
7437e860f15SJohn Edward Broadbent             });
7449d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
745ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
746ed398213SEd Tanous         // ConfigureSelf
7477eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
748ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
749432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
7507e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
75145ca1b86SEd Tanous             [&app](const crow::Request& req,
7527e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7537e860f15SJohn Edward Broadbent                    const std::string& param) {
7543ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
75545ca1b86SEd Tanous                 {
75645ca1b86SEd Tanous                     return;
75745ca1b86SEd Tanous                 }
758b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
7597e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
760b52664e2SAppaRao Puli                 if (subValue == nullptr)
761e5aaf047SAppaRao Puli                 {
762bd79bce8SPatrick Williams                     asyncResp->res.result(
763bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
764e5aaf047SAppaRao Puli                     return;
765e5aaf047SAppaRao Puli                 }
766e5aaf047SAppaRao Puli 
767e5aaf047SAppaRao Puli                 std::optional<std::string> context;
768e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
76919bb362bSEd Tanous                 std::optional<bool> verifyCertificate;
77078d4ec4fSEd Tanous                 std::optional<std::vector<nlohmann::json::object_t>> headers;
771e5aaf047SAppaRao Puli 
772afc474aeSMyung Bae                 if (!json_util::readJsonPatch( //
773afc474aeSMyung Bae                         req, asyncResp->res, //
774afc474aeSMyung Bae                         "Context", context, //
775afc474aeSMyung Bae                         "DeliveryRetryPolicy", retryPolicy, //
776afc474aeSMyung Bae                         "HttpHeaders", headers, //
777afc474aeSMyung Bae                         "VerifyCertificate", verifyCertificate //
778afc474aeSMyung Bae                         ))
779e5aaf047SAppaRao Puli                 {
780e5aaf047SAppaRao Puli                     return;
781e5aaf047SAppaRao Puli                 }
782e5aaf047SAppaRao Puli 
783e5aaf047SAppaRao Puli                 if (context)
784e5aaf047SAppaRao Puli                 {
7855fe4ef35SMyung Bae                     subValue->userSub->customText = *context;
786e5aaf047SAppaRao Puli                 }
787e5aaf047SAppaRao Puli 
788e5aaf047SAppaRao Puli                 if (headers)
789e5aaf047SAppaRao Puli                 {
790601c71aeSEd Tanous                     boost::beast::http::fields fields;
79178d4ec4fSEd Tanous                     for (const nlohmann::json::object_t& headerChunk : *headers)
792601c71aeSEd Tanous                     {
79378d4ec4fSEd Tanous                         for (const auto& it : headerChunk)
794601c71aeSEd Tanous                         {
795601c71aeSEd Tanous                             const std::string* value =
79678d4ec4fSEd Tanous                                 it.second.get_ptr<const std::string*>();
797601c71aeSEd Tanous                             if (value == nullptr)
798601c71aeSEd Tanous                             {
799601c71aeSEd Tanous                                 messages::propertyValueFormatError(
80078d4ec4fSEd Tanous                                     asyncResp->res, it.second,
80178d4ec4fSEd Tanous                                     "HttpHeaders/" + it.first);
802601c71aeSEd Tanous                                 return;
803601c71aeSEd Tanous                             }
80478d4ec4fSEd Tanous                             fields.set(it.first, *value);
805601c71aeSEd Tanous                         }
806601c71aeSEd Tanous                     }
8075fe4ef35SMyung Bae                     subValue->userSub->httpHeaders = std::move(fields);
808e5aaf047SAppaRao Puli                 }
809e5aaf047SAppaRao Puli 
810e5aaf047SAppaRao Puli                 if (retryPolicy)
811e5aaf047SAppaRao Puli                 {
812bd79bce8SPatrick Williams                     if (std::ranges::find(supportedRetryPolicies,
813bd79bce8SPatrick Williams                                           *retryPolicy) ==
8143544d2a7SEd Tanous                         supportedRetryPolicies.end())
815e5aaf047SAppaRao Puli                     {
816bd79bce8SPatrick Williams                         messages::propertyValueNotInList(asyncResp->res,
817bd79bce8SPatrick Williams                                                          *retryPolicy,
818e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
819e5aaf047SAppaRao Puli                         return;
820e5aaf047SAppaRao Puli                     }
8215fe4ef35SMyung Bae                     subValue->userSub->retryPolicy = *retryPolicy;
822e5aaf047SAppaRao Puli                 }
823e5aaf047SAppaRao Puli 
82419bb362bSEd Tanous                 if (verifyCertificate)
82519bb362bSEd Tanous                 {
8265fe4ef35SMyung Bae                     subValue->userSub->verifyCertificate = *verifyCertificate;
82719bb362bSEd Tanous                 }
82819bb362bSEd Tanous 
829b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
8307e860f15SJohn Edward Broadbent             });
8319d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
832ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
833ed398213SEd Tanous         // ConfigureSelf
8347eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
835ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
836432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
8377e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
83845ca1b86SEd Tanous             [&app](const crow::Request& req,
8397e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8407e860f15SJohn Edward Broadbent                    const std::string& param) {
8413ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
84245ca1b86SEd Tanous                 {
84345ca1b86SEd Tanous                     return;
84445ca1b86SEd Tanous                 }
8454b712a29SEd Tanous                 EventServiceManager& event = EventServiceManager::getInstance();
8463d30708fSChicago Duan                 if (param.starts_with("snmp"))
8473d30708fSChicago Duan                 {
8483d30708fSChicago Duan                     deleteSnmpTrapClient(asyncResp, param);
8494b712a29SEd Tanous                     event.deleteSubscription(param);
8503d30708fSChicago Duan                     return;
8513d30708fSChicago Duan                 }
8523d30708fSChicago Duan 
8534b712a29SEd Tanous                 if (!event.deleteSubscription(param))
854e5aaf047SAppaRao Puli                 {
8554b712a29SEd Tanous                     messages::resourceNotFound(asyncResp->res,
8564b712a29SEd Tanous                                                "EventDestination", param);
857e5aaf047SAppaRao Puli                     return;
858e5aaf047SAppaRao Puli                 }
8594b712a29SEd Tanous                 messages::success(asyncResp->res);
8607e860f15SJohn Edward Broadbent             });
861e5aaf047SAppaRao Puli }
862e5aaf047SAppaRao Puli 
863e5aaf047SAppaRao Puli } // namespace redfish
864