xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision fb54610544f97b989b549d8fc94518e2d38c9467)
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"
23d109e2b6SAlexander Hansen #include "registries.hpp"
243ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
25d109e2b6SAlexander Hansen #include "registries_selector.hpp"
263d30708fSChicago Duan #include "snmp_trap_event_clients.hpp"
27d109e2b6SAlexander 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>
375064a25bSMyung Bae #include <optional>
383544d2a7SEd Tanous #include <ranges>
391e270c5fSPatrick Williams #include <span>
403d30708fSChicago Duan #include <string>
41a14c9113SEd Tanous #include <vector>
421e270c5fSPatrick Williams 
43e5aaf047SAppaRao Puli namespace redfish
44e5aaf047SAppaRao Puli {
45e5aaf047SAppaRao Puli 
46156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
47156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
48*fb546105SMyung Bae static constexpr const std::array<const char*, 4> supportedRegPrefixes = {
49*fb546105SMyung Bae     "Base", "OpenBMC", "TaskEvent", "HeartbeatEvent"};
50e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
51e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
52e5aaf047SAppaRao Puli 
53*fb546105SMyung Bae static constexpr const std::array<const char*, 2> supportedResourceTypes = {
54*fb546105SMyung Bae     "Task", "Heartbeat"};
55e56f254cSSunitha Harish 
567e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app)
57e5aaf047SAppaRao Puli {
587e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
59ed398213SEd Tanous         .privileges(redfish::privileges::getEventService)
60bd79bce8SPatrick Williams         .methods(
61bd79bce8SPatrick Williams             boost::beast::http::verb::
62bd79bce8SPatrick Williams                 get)([&app](
63bd79bce8SPatrick Williams                          const crow::Request& req,
64002d39b4SEd Tanous                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
653ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
6645ca1b86SEd Tanous             {
6745ca1b86SEd Tanous                 return;
6845ca1b86SEd Tanous             }
691476687dSEd Tanous 
701476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
711476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
721476687dSEd Tanous                 "#EventService.v1_5_0.EventService";
731476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = "EventService";
741476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "Event Service";
755e44e3d8SAppaRao Puli             asyncResp->res.jsonValue["ServerSentEventUri"] =
765e44e3d8SAppaRao Puli                 "/redfish/v1/EventService/SSE";
775e44e3d8SAppaRao Puli 
781476687dSEd Tanous             asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
791476687dSEd Tanous                 "/redfish/v1/EventService/Subscriptions";
80bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"]
81bd79bce8SPatrick Williams                                     ["target"] =
821476687dSEd Tanous                 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
83e5aaf047SAppaRao Puli 
8428afb49cSJunLin Chen             const persistent_data::EventServiceConfig eventServiceConfig =
8528afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
8628afb49cSJunLin Chen                     .getEventServiceConfig();
877d1cc387SAppaRao Puli 
887d1cc387SAppaRao Puli             asyncResp->res.jsonValue["Status"]["State"] =
8928afb49cSJunLin Chen                 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
90bd79bce8SPatrick Williams             asyncResp->res.jsonValue["ServiceEnabled"] =
91bd79bce8SPatrick Williams                 eventServiceConfig.enabled;
927e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
9328afb49cSJunLin Chen                 eventServiceConfig.retryAttempts;
94e5aaf047SAppaRao Puli             asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
9528afb49cSJunLin Chen                 eventServiceConfig.retryTimeoutInterval;
96bd79bce8SPatrick Williams             asyncResp->res.jsonValue["EventFormatTypes"] =
97bd79bce8SPatrick Williams                 supportedEvtFormatTypes;
980fda0f12SGeorge Liu             asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
990fda0f12SGeorge Liu             asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
10007941a88SAyushi Smriti 
101613dabeaSEd Tanous             nlohmann::json::object_t supportedSSEFilters;
102613dabeaSEd Tanous             supportedSSEFilters["EventFormatType"] = true;
103613dabeaSEd Tanous             supportedSSEFilters["MessageId"] = true;
104613dabeaSEd Tanous             supportedSSEFilters["MetricReportDefinition"] = true;
105613dabeaSEd Tanous             supportedSSEFilters["RegistryPrefix"] = true;
106613dabeaSEd Tanous             supportedSSEFilters["OriginResource"] = false;
107613dabeaSEd Tanous             supportedSSEFilters["ResourceType"] = false;
10807941a88SAyushi Smriti 
10907941a88SAyushi Smriti             asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
110613dabeaSEd Tanous                 std::move(supportedSSEFilters);
1117e860f15SJohn Edward Broadbent         });
112e5aaf047SAppaRao Puli 
1137e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
114ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
1157e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
11645ca1b86SEd Tanous             [&app](const crow::Request& req,
11745ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1183ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
119e5aaf047SAppaRao Puli                 {
12045ca1b86SEd Tanous                     return;
12145ca1b86SEd Tanous                 }
122e5aaf047SAppaRao Puli                 std::optional<bool> serviceEnabled;
123e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryAttemps;
124e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryInterval;
125afc474aeSMyung Bae                 if (!json_util::readJsonPatch( //
126afc474aeSMyung Bae                         req, asyncResp->res, //
127afc474aeSMyung Bae                         "DeliveryRetryAttempts", retryAttemps, //
128afc474aeSMyung Bae                         "DeliveryRetryIntervalSeconds", retryInterval, //
129afc474aeSMyung Bae                         "ServiceEnabled", serviceEnabled //
130afc474aeSMyung Bae                         ))
131e5aaf047SAppaRao Puli                 {
132e5aaf047SAppaRao Puli                     return;
133e5aaf047SAppaRao Puli                 }
134e5aaf047SAppaRao Puli 
13528afb49cSJunLin Chen                 persistent_data::EventServiceConfig eventServiceConfig =
13628afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
13728afb49cSJunLin Chen                         .getEventServiceConfig();
1387d1cc387SAppaRao Puli 
139e5aaf047SAppaRao Puli                 if (serviceEnabled)
140e5aaf047SAppaRao Puli                 {
14128afb49cSJunLin Chen                     eventServiceConfig.enabled = *serviceEnabled;
142e5aaf047SAppaRao Puli                 }
143e5aaf047SAppaRao Puli 
144e5aaf047SAppaRao Puli                 if (retryAttemps)
145e5aaf047SAppaRao Puli                 {
146e5aaf047SAppaRao Puli                     // Supported range [1-3]
147e5aaf047SAppaRao Puli                     if ((*retryAttemps < 1) || (*retryAttemps > 3))
148e5aaf047SAppaRao Puli                     {
149e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
150e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryAttemps),
151e5aaf047SAppaRao Puli                             "DeliveryRetryAttempts", "[1-3]");
152e5aaf047SAppaRao Puli                     }
153e5aaf047SAppaRao Puli                     else
154e5aaf047SAppaRao Puli                     {
15528afb49cSJunLin Chen                         eventServiceConfig.retryAttempts = *retryAttemps;
156e5aaf047SAppaRao Puli                     }
157e5aaf047SAppaRao Puli                 }
158e5aaf047SAppaRao Puli 
159e5aaf047SAppaRao Puli                 if (retryInterval)
160e5aaf047SAppaRao Puli                 {
16133a32b34SGunnar Mills                     // Supported range [5 - 180]
16233a32b34SGunnar Mills                     if ((*retryInterval < 5) || (*retryInterval > 180))
163e5aaf047SAppaRao Puli                     {
164e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
165e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryInterval),
16633a32b34SGunnar Mills                             "DeliveryRetryIntervalSeconds", "[5-180]");
167e5aaf047SAppaRao Puli                     }
168e5aaf047SAppaRao Puli                     else
169e5aaf047SAppaRao Puli                     {
170bd79bce8SPatrick Williams                         eventServiceConfig.retryTimeoutInterval =
171bd79bce8SPatrick Williams                             *retryInterval;
172e5aaf047SAppaRao Puli                     }
173e5aaf047SAppaRao Puli                 }
174e5aaf047SAppaRao Puli 
1757d1cc387SAppaRao Puli                 EventServiceManager::getInstance().setEventServiceConfig(
17628afb49cSJunLin Chen                     eventServiceConfig);
1777e860f15SJohn Edward Broadbent             });
1780b4bdd93SAppaRao Puli }
1790b4bdd93SAppaRao Puli 
1807e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1810b4bdd93SAppaRao Puli {
1827e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1837e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
184ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1857e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
18645ca1b86SEd Tanous             [&app](const crow::Request& req,
1877e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1883ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
18945ca1b86SEd Tanous                 {
19045ca1b86SEd Tanous                     return;
19145ca1b86SEd Tanous                 }
1926ba8c82eSsunharis_in                 if (!EventServiceManager::getInstance().sendTestEventLog())
1936ba8c82eSsunharis_in                 {
1946ba8c82eSsunharis_in                     messages::serviceDisabled(asyncResp->res,
1956ba8c82eSsunharis_in                                               "/redfish/v1/EventService/");
1966ba8c82eSsunharis_in                     return;
1976ba8c82eSsunharis_in                 }
1988d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
1997e860f15SJohn Edward Broadbent             });
200e5aaf047SAppaRao Puli }
201e5aaf047SAppaRao Puli 
2023d30708fSChicago Duan inline void doSubscriptionCollection(
203e81de512SEd Tanous     const boost::system::error_code& ec,
2043d30708fSChicago Duan     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2053d30708fSChicago Duan     const dbus::utility::ManagedObjectType& resp)
2063d30708fSChicago Duan {
2073d30708fSChicago Duan     if (ec)
2083d30708fSChicago Duan     {
2091306101eSEd Tanous         if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
2103d30708fSChicago Duan         {
2113d30708fSChicago Duan             // This is an optional process so just return if it isn't there
2123d30708fSChicago Duan             return;
2133d30708fSChicago Duan         }
2143d30708fSChicago Duan 
21562598e31SEd Tanous         BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
2163d30708fSChicago Duan         messages::internalError(asyncResp->res);
2173d30708fSChicago Duan         return;
2183d30708fSChicago Duan     }
2193d30708fSChicago Duan     nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
2203d30708fSChicago Duan     for (const auto& objpath : resp)
2213d30708fSChicago Duan     {
2223d30708fSChicago Duan         sdbusplus::message::object_path path(objpath.first);
2233d30708fSChicago Duan         const std::string snmpId = path.filename();
2243d30708fSChicago Duan         if (snmpId.empty())
2253d30708fSChicago Duan         {
22662598e31SEd Tanous             BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
2273d30708fSChicago Duan             messages::internalError(asyncResp->res);
2283d30708fSChicago Duan             return;
2293d30708fSChicago Duan         }
2303d30708fSChicago Duan 
2313d30708fSChicago Duan         getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
2323d30708fSChicago Duan     }
2333d30708fSChicago Duan }
2343d30708fSChicago Duan 
2357e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
236e5aaf047SAppaRao Puli {
2371ebe3e41SGayathri Leburu     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
238ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
2397e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
24045ca1b86SEd Tanous             [&app](const crow::Request& req,
2417e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2423ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
24345ca1b86SEd Tanous                 {
24445ca1b86SEd Tanous                     return;
24545ca1b86SEd Tanous                 }
2461476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
2471476687dSEd Tanous                     "#EventDestinationCollection.EventDestinationCollection";
2481476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
2491476687dSEd Tanous                     "/redfish/v1/EventService/Subscriptions";
250bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Name"] =
251bd79bce8SPatrick Williams                     "Event Destination Collections";
252e5aaf047SAppaRao Puli 
253bd79bce8SPatrick Williams                 nlohmann::json& memberArray =
254bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["Members"];
255e5aaf047SAppaRao Puli 
256b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
257b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
258b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
259bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Members@odata.count"] =
260bd79bce8SPatrick Williams                     subscripIds.size();
261b52664e2SAppaRao Puli 
262b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
263e5aaf047SAppaRao Puli                 {
2641476687dSEd Tanous                     nlohmann::json::object_t member;
2653d30708fSChicago Duan                     member["@odata.id"] = boost::urls::format(
2663d30708fSChicago Duan                         "/redfish/v1/EventService/Subscriptions/{}" + id);
267b2ba3072SPatrick Williams                     memberArray.emplace_back(std::move(member));
268e5aaf047SAppaRao Puli                 }
2693d30708fSChicago Duan                 crow::connections::systemBus->async_method_call(
270e81de512SEd Tanous                     [asyncResp](const boost::system::error_code& ec,
2713d30708fSChicago Duan                                 const dbus::utility::ManagedObjectType& resp) {
2723d30708fSChicago Duan                         doSubscriptionCollection(ec, asyncResp, resp);
2733d30708fSChicago Duan                     },
2743d30708fSChicago Duan                     "xyz.openbmc_project.Network.SNMP",
2753d30708fSChicago Duan                     "/xyz/openbmc_project/network/snmp/manager",
2763d30708fSChicago Duan                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
2777e860f15SJohn Edward Broadbent             });
2783d30708fSChicago Duan 
2797e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
2807eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
281bd79bce8SPatrick Williams         .methods(
282bd79bce8SPatrick Williams             boost::beast::http::verb::
283bd79bce8SPatrick Williams                 post)([&app](
284bd79bce8SPatrick Williams                           const crow::Request& req,
2857e860f15SJohn Edward Broadbent                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2863ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
28745ca1b86SEd Tanous             {
28845ca1b86SEd Tanous                 return;
28945ca1b86SEd Tanous             }
290fffb8c1fSEd Tanous             if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
291fffb8c1fSEd Tanous                 maxNoOfSubscriptions)
292e5aaf047SAppaRao Puli             {
293e5aaf047SAppaRao Puli                 messages::eventSubscriptionLimitExceeded(asyncResp->res);
294e5aaf047SAppaRao Puli                 return;
295e5aaf047SAppaRao Puli             }
296e5aaf047SAppaRao Puli             std::string destUrl;
297e5aaf047SAppaRao Puli             std::string protocol;
29819bb362bSEd Tanous             std::optional<bool> verifyCertificate;
299e5aaf047SAppaRao Puli             std::optional<std::string> context;
300e5aaf047SAppaRao Puli             std::optional<std::string> subscriptionType;
30123a21a1cSEd Tanous             std::optional<std::string> eventFormatType2;
302e5aaf047SAppaRao Puli             std::optional<std::string> retryPolicy;
3035064a25bSMyung Bae             std::optional<bool> sendHeartbeat;
3045064a25bSMyung Bae             std::optional<uint64_t> hbIntervalMinutes;
305e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> msgIds;
306e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> regPrefixes;
307a14c9113SEd Tanous             std::optional<std::vector<std::string>> originResources;
308e56f254cSSunitha Harish             std::optional<std::vector<std::string>> resTypes;
30978d4ec4fSEd Tanous             std::optional<std::vector<nlohmann::json::object_t>> headers;
31078d4ec4fSEd Tanous             std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
311e5aaf047SAppaRao Puli 
312afc474aeSMyung Bae             if (!json_util::readJsonPatch( //
313afc474aeSMyung Bae                     req, asyncResp->res, //
314afc474aeSMyung Bae                     "Context", context, //
315afc474aeSMyung Bae                     "DeliveryRetryPolicy", retryPolicy, //
316afc474aeSMyung Bae                     "Destination", destUrl, //
317afc474aeSMyung Bae                     "EventFormatType", eventFormatType2, //
3185064a25bSMyung Bae                     "HeartbeatIntervalMinutes", hbIntervalMinutes, //
319afc474aeSMyung Bae                     "HttpHeaders", headers, //
320afc474aeSMyung Bae                     "MessageIds", msgIds, //
321afc474aeSMyung Bae                     "MetricReportDefinitions", mrdJsonArray, //
322afc474aeSMyung Bae                     "OriginResources", originResources, //
323afc474aeSMyung Bae                     "Protocol", protocol, //
324afc474aeSMyung Bae                     "RegistryPrefixes", regPrefixes, //
325afc474aeSMyung Bae                     "ResourceTypes", resTypes, //
3265064a25bSMyung Bae                     "SendHeartbeat", sendHeartbeat, //
327afc474aeSMyung Bae                     "SubscriptionType", subscriptionType, //
328afc474aeSMyung Bae                     "VerifyCertificate", verifyCertificate //
3294b712a29SEd Tanous                     ))
330e5aaf047SAppaRao Puli             {
331e5aaf047SAppaRao Puli                 return;
332e5aaf047SAppaRao Puli             }
3334b712a29SEd Tanous             // clang-format on
334e5aaf047SAppaRao Puli 
335600af5f1SAppaRao Puli             // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
336600af5f1SAppaRao Puli             static constexpr const uint16_t maxDestinationSize = 2000;
337600af5f1SAppaRao Puli             if (destUrl.size() > maxDestinationSize)
338600af5f1SAppaRao Puli             {
339600af5f1SAppaRao Puli                 messages::stringValueTooLong(asyncResp->res, "Destination",
340600af5f1SAppaRao Puli                                              maxDestinationSize);
341600af5f1SAppaRao Puli                 return;
342600af5f1SAppaRao Puli             }
343600af5f1SAppaRao Puli 
344dd28ba82SAppaRao Puli             if (regPrefixes && msgIds)
345dd28ba82SAppaRao Puli             {
34626f6976fSEd Tanous                 if (!regPrefixes->empty() && !msgIds->empty())
347dd28ba82SAppaRao Puli                 {
348bd79bce8SPatrick Williams                     messages::propertyValueConflict(
349bd79bce8SPatrick Williams                         asyncResp->res, "MessageIds", "RegistryPrefixes");
350dd28ba82SAppaRao Puli                     return;
351dd28ba82SAppaRao Puli                 }
352dd28ba82SAppaRao Puli             }
353dd28ba82SAppaRao Puli 
3546fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
355a716aa74SEd Tanous                 boost::urls::parse_absolute_uri(destUrl);
356a716aa74SEd Tanous             if (!url)
357e5aaf047SAppaRao Puli             {
358bd79bce8SPatrick Williams                 BMCWEB_LOG_WARNING(
359bd79bce8SPatrick Williams                     "Failed to validate and split destination url");
360e5aaf047SAppaRao Puli                 messages::propertyValueFormatError(asyncResp->res, destUrl,
361e5aaf047SAppaRao Puli                                                    "Destination");
362e5aaf047SAppaRao Puli                 return;
363e5aaf047SAppaRao Puli             }
364a716aa74SEd Tanous             url->normalize();
365b07942e3SGeorge Liu 
366b07942e3SGeorge Liu             // port_number returns zero if it is not a valid representable port
367b07942e3SGeorge Liu             if (url->has_port() && url->port_number() == 0)
368b07942e3SGeorge Liu             {
369b07942e3SGeorge Liu                 BMCWEB_LOG_WARNING("{} is an invalid port in destination url",
370b07942e3SGeorge Liu                                    url->port());
371b07942e3SGeorge Liu                 messages::propertyValueFormatError(asyncResp->res, destUrl,
372b07942e3SGeorge Liu                                                    "Destination");
373b07942e3SGeorge Liu                 return;
374b07942e3SGeorge Liu             }
375b07942e3SGeorge Liu 
376a716aa74SEd Tanous             crow::utility::setProtocolDefaults(*url, protocol);
377a716aa74SEd Tanous             crow::utility::setPortDefaults(*url);
378a716aa74SEd Tanous 
379a716aa74SEd Tanous             if (url->path().empty())
380a716aa74SEd Tanous             {
381a716aa74SEd Tanous                 url->set_path("/");
382a716aa74SEd Tanous             }
383a716aa74SEd Tanous 
384a716aa74SEd Tanous             if (url->has_userinfo())
385a716aa74SEd Tanous             {
386a716aa74SEd Tanous                 messages::propertyValueFormatError(asyncResp->res, destUrl,
387a716aa74SEd Tanous                                                    "Destination");
388a716aa74SEd Tanous                 return;
389a716aa74SEd Tanous             }
390b52664e2SAppaRao Puli 
3913d30708fSChicago Duan             if (protocol == "SNMPv2c")
3923d30708fSChicago Duan             {
3933d30708fSChicago Duan                 if (context)
3943d30708fSChicago Duan                 {
3953d30708fSChicago Duan                     messages::propertyValueConflict(asyncResp->res, "Context",
3963d30708fSChicago Duan                                                     "Protocol");
3973d30708fSChicago Duan                     return;
3983d30708fSChicago Duan                 }
3993d30708fSChicago Duan                 if (eventFormatType2)
4003d30708fSChicago Duan                 {
401bd79bce8SPatrick Williams                     messages::propertyValueConflict(
402bd79bce8SPatrick Williams                         asyncResp->res, "EventFormatType", "Protocol");
4033d30708fSChicago Duan                     return;
4043d30708fSChicago Duan                 }
4053d30708fSChicago Duan                 if (retryPolicy)
4063d30708fSChicago Duan                 {
407bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
408bd79bce8SPatrick Williams                                                     "RetryPolicy", "Protocol");
4093d30708fSChicago Duan                     return;
4103d30708fSChicago Duan                 }
4115064a25bSMyung Bae                 if (sendHeartbeat)
4125064a25bSMyung Bae                 {
4135064a25bSMyung Bae                     messages::propertyValueConflict(
4145064a25bSMyung Bae                         asyncResp->res, "SendHeartbeat", "Protocol");
4155064a25bSMyung Bae                     return;
4165064a25bSMyung Bae                 }
4175064a25bSMyung Bae                 if (hbIntervalMinutes)
4185064a25bSMyung Bae                 {
4195064a25bSMyung Bae                     messages::propertyValueConflict(
4205064a25bSMyung Bae                         asyncResp->res, "HeartbeatIntervalMinutes", "Protocol");
4215064a25bSMyung Bae                     return;
4225064a25bSMyung Bae                 }
4233d30708fSChicago Duan                 if (msgIds)
4243d30708fSChicago Duan                 {
425bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
426bd79bce8SPatrick Williams                                                     "MessageIds", "Protocol");
4273d30708fSChicago Duan                     return;
4283d30708fSChicago Duan                 }
4293d30708fSChicago Duan                 if (regPrefixes)
4303d30708fSChicago Duan                 {
431bd79bce8SPatrick Williams                     messages::propertyValueConflict(
432bd79bce8SPatrick Williams                         asyncResp->res, "RegistryPrefixes", "Protocol");
4333d30708fSChicago Duan                     return;
4343d30708fSChicago Duan                 }
4353d30708fSChicago Duan                 if (resTypes)
4363d30708fSChicago Duan                 {
437bd79bce8SPatrick Williams                     messages::propertyValueConflict(
438bd79bce8SPatrick Williams                         asyncResp->res, "ResourceTypes", "Protocol");
4393d30708fSChicago Duan                     return;
4403d30708fSChicago Duan                 }
4413d30708fSChicago Duan                 if (headers)
4423d30708fSChicago Duan                 {
443bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
444bd79bce8SPatrick Williams                                                     "HttpHeaders", "Protocol");
4453d30708fSChicago Duan                     return;
4463d30708fSChicago Duan                 }
4473d30708fSChicago Duan                 if (mrdJsonArray)
4483d30708fSChicago Duan                 {
4493d30708fSChicago Duan                     messages::propertyValueConflict(
4503d30708fSChicago Duan                         asyncResp->res, "MetricReportDefinitions", "Protocol");
4513d30708fSChicago Duan                     return;
4523d30708fSChicago Duan                 }
453a716aa74SEd Tanous                 if (url->scheme() != "snmp")
454a716aa74SEd Tanous                 {
455bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
456bd79bce8SPatrick Williams                                                     "Destination", "Protocol");
4573d30708fSChicago Duan                     return;
4583d30708fSChicago Duan                 }
4593d30708fSChicago Duan 
460a716aa74SEd Tanous                 addSnmpTrapClient(asyncResp, url->host_address(),
461a716aa74SEd Tanous                                   url->port_number());
462a716aa74SEd Tanous                 return;
463b52664e2SAppaRao Puli             }
4643d30708fSChicago Duan 
465a716aa74SEd Tanous             std::shared_ptr<Subscription> subValue =
46621a94d5cSMyung Bae                 std::make_shared<Subscription>(
4675fe4ef35SMyung Bae                     std::make_shared<persistent_data::UserSubscription>(), *url,
4685fe4ef35SMyung Bae                     app.ioContext());
469e5aaf047SAppaRao Puli 
470e5aaf047SAppaRao Puli             if (subscriptionType)
471e5aaf047SAppaRao Puli             {
472e5aaf047SAppaRao Puli                 if (*subscriptionType != "RedfishEvent")
473e5aaf047SAppaRao Puli                 {
474fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
475fffb8c1fSEd Tanous                         asyncResp->res, *subscriptionType, "SubscriptionType");
476e5aaf047SAppaRao Puli                     return;
477e5aaf047SAppaRao Puli                 }
4785fe4ef35SMyung Bae                 subValue->userSub->subscriptionType = *subscriptionType;
479e5aaf047SAppaRao Puli             }
480e5aaf047SAppaRao Puli             else
481e5aaf047SAppaRao Puli             {
4824b712a29SEd Tanous                 // Default
4835fe4ef35SMyung Bae                 subValue->userSub->subscriptionType = "RedfishEvent";
484e5aaf047SAppaRao Puli             }
485e5aaf047SAppaRao Puli 
486e5aaf047SAppaRao Puli             if (protocol != "Redfish")
487e5aaf047SAppaRao Puli             {
488e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, protocol,
489e5aaf047SAppaRao Puli                                                  "Protocol");
490e5aaf047SAppaRao Puli                 return;
491e5aaf047SAppaRao Puli             }
4925fe4ef35SMyung Bae             subValue->userSub->protocol = protocol;
493e5aaf047SAppaRao Puli 
49419bb362bSEd Tanous             if (verifyCertificate)
49519bb362bSEd Tanous             {
4965fe4ef35SMyung Bae                 subValue->userSub->verifyCertificate = *verifyCertificate;
49719bb362bSEd Tanous             }
49819bb362bSEd Tanous 
49923a21a1cSEd Tanous             if (eventFormatType2)
500e5aaf047SAppaRao Puli             {
501bd79bce8SPatrick Williams                 if (std::ranges::find(supportedEvtFormatTypes,
502bd79bce8SPatrick Williams                                       *eventFormatType2) ==
5033544d2a7SEd Tanous                     supportedEvtFormatTypes.end())
504e5aaf047SAppaRao Puli                 {
505fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
506fffb8c1fSEd Tanous                         asyncResp->res, *eventFormatType2, "EventFormatType");
507e5aaf047SAppaRao Puli                     return;
508e5aaf047SAppaRao Puli                 }
5095fe4ef35SMyung Bae                 subValue->userSub->eventFormatType = *eventFormatType2;
510e5aaf047SAppaRao Puli             }
511e5aaf047SAppaRao Puli             else
512e5aaf047SAppaRao Puli             {
513e5aaf047SAppaRao Puli                 // If not specified, use default "Event"
5145fe4ef35SMyung Bae                 subValue->userSub->eventFormatType = "Event";
515e5aaf047SAppaRao Puli             }
516e5aaf047SAppaRao Puli 
517e5aaf047SAppaRao Puli             if (context)
518e5aaf047SAppaRao Puli             {
5198ece0e45SEd Tanous                 // This value is selected arbitrarily.
520600af5f1SAppaRao Puli                 constexpr const size_t maxContextSize = 256;
521600af5f1SAppaRao Puli                 if (context->size() > maxContextSize)
522600af5f1SAppaRao Puli                 {
523600af5f1SAppaRao Puli                     messages::stringValueTooLong(asyncResp->res, "Context",
524600af5f1SAppaRao Puli                                                  maxContextSize);
525600af5f1SAppaRao Puli                     return;
526600af5f1SAppaRao Puli                 }
5275fe4ef35SMyung Bae                 subValue->userSub->customText = *context;
528e5aaf047SAppaRao Puli             }
529e5aaf047SAppaRao Puli 
530e5aaf047SAppaRao Puli             if (headers)
531e5aaf047SAppaRao Puli             {
532600af5f1SAppaRao Puli                 size_t cumulativeLen = 0;
533600af5f1SAppaRao Puli 
53478d4ec4fSEd Tanous                 for (const nlohmann::json::object_t& headerChunk : *headers)
535601c71aeSEd Tanous                 {
53678d4ec4fSEd Tanous                     for (const auto& item : headerChunk)
53778d4ec4fSEd Tanous                     {
53878d4ec4fSEd Tanous                         const std::string* value =
53978d4ec4fSEd Tanous                             item.second.get_ptr<const std::string*>();
54078d4ec4fSEd Tanous                         if (value == nullptr)
54178d4ec4fSEd Tanous                         {
54278d4ec4fSEd Tanous                             messages::propertyValueFormatError(
54378d4ec4fSEd Tanous                                 asyncResp->res, item.second,
54478d4ec4fSEd Tanous                                 "HttpHeaders/" + item.first);
54578d4ec4fSEd Tanous                             return;
54678d4ec4fSEd Tanous                         }
54778d4ec4fSEd Tanous                         // Adding a new json value is the size of the key, +
54878d4ec4fSEd Tanous                         // the size of the value + 2 * 2 quotes for each, +
54978d4ec4fSEd Tanous                         // the colon and space between. example:
55078d4ec4fSEd Tanous                         // "key": "value"
55178d4ec4fSEd Tanous                         cumulativeLen += item.first.size() + value->size() + 6;
552600af5f1SAppaRao Puli                         // This value is selected to mirror http_connection.hpp
553600af5f1SAppaRao Puli                         constexpr const uint16_t maxHeaderSizeED = 8096;
554600af5f1SAppaRao Puli                         if (cumulativeLen > maxHeaderSizeED)
555600af5f1SAppaRao Puli                         {
55678d4ec4fSEd Tanous                             messages::arraySizeTooLong(
55778d4ec4fSEd Tanous                                 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
558600af5f1SAppaRao Puli                             return;
559600af5f1SAppaRao Puli                         }
5605fe4ef35SMyung Bae                         subValue->userSub->httpHeaders.set(item.first, *value);
561601c71aeSEd Tanous                     }
562601c71aeSEd Tanous                 }
563e5aaf047SAppaRao Puli             }
564e5aaf047SAppaRao Puli 
565e5aaf047SAppaRao Puli             if (regPrefixes)
566e5aaf047SAppaRao Puli             {
567e5aaf047SAppaRao Puli                 for (const std::string& it : *regPrefixes)
568e5aaf047SAppaRao Puli                 {
5693544d2a7SEd Tanous                     if (std::ranges::find(supportedRegPrefixes, it) ==
5703544d2a7SEd Tanous                         supportedRegPrefixes.end())
571e5aaf047SAppaRao Puli                     {
572fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
573fffb8c1fSEd Tanous                                                          "RegistryPrefixes");
574e5aaf047SAppaRao Puli                         return;
575e5aaf047SAppaRao Puli                     }
576e5aaf047SAppaRao Puli                 }
5775fe4ef35SMyung Bae                 subValue->userSub->registryPrefixes = *regPrefixes;
578e5aaf047SAppaRao Puli             }
579e5aaf047SAppaRao Puli 
580a14c9113SEd Tanous             if (originResources)
581a14c9113SEd Tanous             {
5825fe4ef35SMyung Bae                 subValue->userSub->originResources = *originResources;
583a14c9113SEd Tanous             }
584a14c9113SEd Tanous 
585e56f254cSSunitha Harish             if (resTypes)
586e56f254cSSunitha Harish             {
587e56f254cSSunitha Harish                 for (const std::string& it : *resTypes)
588e56f254cSSunitha Harish                 {
5893544d2a7SEd Tanous                     if (std::ranges::find(supportedResourceTypes, it) ==
5903544d2a7SEd Tanous                         supportedResourceTypes.end())
591e56f254cSSunitha Harish                     {
592e56f254cSSunitha Harish                         messages::propertyValueNotInList(asyncResp->res, it,
593e56f254cSSunitha Harish                                                          "ResourceTypes");
594e56f254cSSunitha Harish                         return;
595e56f254cSSunitha Harish                     }
596e56f254cSSunitha Harish                 }
5975fe4ef35SMyung Bae                 subValue->userSub->resourceTypes = *resTypes;
598e56f254cSSunitha Harish             }
599e56f254cSSunitha Harish 
600e5aaf047SAppaRao Puli             if (msgIds)
601e5aaf047SAppaRao Puli             {
602b304bd79SP Dheeraj Srujan Kumar                 std::vector<std::string> registryPrefix;
603b304bd79SP Dheeraj Srujan Kumar 
6047e860f15SJohn Edward Broadbent                 // If no registry prefixes are mentioned, consider all
6057e860f15SJohn Edward Broadbent                 // supported prefixes
6065fe4ef35SMyung Bae                 if (subValue->userSub->registryPrefixes.empty())
607b304bd79SP Dheeraj Srujan Kumar                 {
608b304bd79SP Dheeraj Srujan Kumar                     registryPrefix.assign(supportedRegPrefixes.begin(),
609b304bd79SP Dheeraj Srujan Kumar                                           supportedRegPrefixes.end());
610b304bd79SP Dheeraj Srujan Kumar                 }
611b304bd79SP Dheeraj Srujan Kumar                 else
612b304bd79SP Dheeraj Srujan Kumar                 {
6135fe4ef35SMyung Bae                     registryPrefix = subValue->userSub->registryPrefixes;
614b304bd79SP Dheeraj Srujan Kumar                 }
615b304bd79SP Dheeraj Srujan Kumar 
616b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& id : *msgIds)
617b304bd79SP Dheeraj Srujan Kumar                 {
618b304bd79SP Dheeraj Srujan Kumar                     bool validId = false;
619b304bd79SP Dheeraj Srujan Kumar 
620b304bd79SP Dheeraj Srujan Kumar                     // Check for Message ID in each of the selected Registry
621b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& it : registryPrefix)
622b304bd79SP Dheeraj Srujan Kumar                     {
623fffb8c1fSEd Tanous                         const std::span<const redfish::registries::MessageEntry>
624fffb8c1fSEd Tanous                             registry =
625fffb8c1fSEd Tanous                                 redfish::registries::getRegistryFromPrefix(it);
626b304bd79SP Dheeraj Srujan Kumar 
6273544d2a7SEd Tanous                         if (std::ranges::any_of(
6283544d2a7SEd Tanous                                 registry,
629fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
630fffb8c1fSEd Tanous                                           messageEntry) {
63155f79e6fSEd Tanous                                     return id == messageEntry.first;
632b304bd79SP Dheeraj Srujan Kumar                                 }))
633b304bd79SP Dheeraj Srujan Kumar                         {
634b304bd79SP Dheeraj Srujan Kumar                             validId = true;
635b304bd79SP Dheeraj Srujan Kumar                             break;
636b304bd79SP Dheeraj Srujan Kumar                         }
637b304bd79SP Dheeraj Srujan Kumar                     }
638b304bd79SP Dheeraj Srujan Kumar 
639b304bd79SP Dheeraj Srujan Kumar                     if (!validId)
640b304bd79SP Dheeraj Srujan Kumar                     {
641b304bd79SP Dheeraj Srujan Kumar                         messages::propertyValueNotInList(asyncResp->res, id,
642b304bd79SP Dheeraj Srujan Kumar                                                          "MessageIds");
643b304bd79SP Dheeraj Srujan Kumar                         return;
644b304bd79SP Dheeraj Srujan Kumar                     }
645b304bd79SP Dheeraj Srujan Kumar                 }
646b304bd79SP Dheeraj Srujan Kumar 
6475fe4ef35SMyung Bae                 subValue->userSub->registryMsgIds = *msgIds;
648e5aaf047SAppaRao Puli             }
649e5aaf047SAppaRao Puli 
650e5aaf047SAppaRao Puli             if (retryPolicy)
651e5aaf047SAppaRao Puli             {
6523544d2a7SEd Tanous                 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
6533544d2a7SEd Tanous                     supportedRetryPolicies.end())
654e5aaf047SAppaRao Puli                 {
655bd79bce8SPatrick Williams                     messages::propertyValueNotInList(
656bd79bce8SPatrick Williams                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
657e5aaf047SAppaRao Puli                     return;
658e5aaf047SAppaRao Puli                 }
6595fe4ef35SMyung Bae                 subValue->userSub->retryPolicy = *retryPolicy;
660e5aaf047SAppaRao Puli             }
661e5aaf047SAppaRao Puli             else
662e5aaf047SAppaRao Puli             {
663e5aaf047SAppaRao Puli                 // Default "TerminateAfterRetries"
6645fe4ef35SMyung Bae                 subValue->userSub->retryPolicy = "TerminateAfterRetries";
665e5aaf047SAppaRao Puli             }
6665064a25bSMyung Bae             if (sendHeartbeat)
6675064a25bSMyung Bae             {
6685064a25bSMyung Bae                 subValue->userSub->sendHeartbeat = *sendHeartbeat;
6695064a25bSMyung Bae             }
6705064a25bSMyung Bae             if (hbIntervalMinutes)
6715064a25bSMyung Bae             {
6725064a25bSMyung Bae                 if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535)
6735064a25bSMyung Bae                 {
6745064a25bSMyung Bae                     messages::propertyValueOutOfRange(
6755064a25bSMyung Bae                         asyncResp->res, *hbIntervalMinutes,
6765064a25bSMyung Bae                         "HeartbeatIntervalMinutes");
6775064a25bSMyung Bae                     return;
6785064a25bSMyung Bae                 }
6795064a25bSMyung Bae                 subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes;
6805064a25bSMyung Bae             }
681e5aaf047SAppaRao Puli 
682144b6318SAppaRao Puli             if (mrdJsonArray)
683156d6b00SAppaRao Puli             {
68478d4ec4fSEd Tanous                 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
685144b6318SAppaRao Puli                 {
686144b6318SAppaRao Puli                     std::string mrdUri;
687ea2e6eecSWilly Tu 
68878d4ec4fSEd Tanous                     if (!json_util::readJsonObject(mrdObj, asyncResp->res,
68978d4ec4fSEd Tanous                                                    "@odata.id", mrdUri))
690ea2e6eecSWilly Tu 
691144b6318SAppaRao Puli                     {
692144b6318SAppaRao Puli                         return;
693144b6318SAppaRao Puli                     }
6945fe4ef35SMyung Bae                     subValue->userSub->metricReportDefinitions.emplace_back(
6954b712a29SEd Tanous                         mrdUri);
696144b6318SAppaRao Puli                 }
697156d6b00SAppaRao Puli             }
698156d6b00SAppaRao Puli 
699b52664e2SAppaRao Puli             std::string id =
700bd79bce8SPatrick Williams                 EventServiceManager::getInstance().addPushSubscription(
701bd79bce8SPatrick Williams                     subValue);
702b52664e2SAppaRao Puli             if (id.empty())
703e5aaf047SAppaRao Puli             {
704e5aaf047SAppaRao Puli                 messages::internalError(asyncResp->res);
705e5aaf047SAppaRao Puli                 return;
706e5aaf047SAppaRao Puli             }
707e5aaf047SAppaRao Puli 
708e5aaf047SAppaRao Puli             messages::created(asyncResp->res);
709e5aaf047SAppaRao Puli             asyncResp->res.addHeader(
710e5aaf047SAppaRao Puli                 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
711*fb546105SMyung Bae 
712*fb546105SMyung Bae             // schedule a heartbeat
713*fb546105SMyung Bae             if (subValue->userSub->sendHeartbeat)
714*fb546105SMyung Bae             {
715*fb546105SMyung Bae                 subValue->scheduleNextHeartbeatEvent();
716*fb546105SMyung Bae             }
7177e860f15SJohn Edward Broadbent         });
718e5aaf047SAppaRao Puli }
719e5aaf047SAppaRao Puli 
7207e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
721e5aaf047SAppaRao Puli {
7229d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
723ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
7247e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
72545ca1b86SEd Tanous             [&app](const crow::Request& req,
7267e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7277e860f15SJohn Edward Broadbent                    const std::string& param) {
7283ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
72945ca1b86SEd Tanous                 {
73045ca1b86SEd Tanous                     return;
73145ca1b86SEd Tanous                 }
7323d30708fSChicago Duan 
7333d30708fSChicago Duan                 if (param.starts_with("snmp"))
7343d30708fSChicago Duan                 {
7353d30708fSChicago Duan                     getSnmpTrapClient(asyncResp, param);
7363d30708fSChicago Duan                     return;
7373d30708fSChicago Duan                 }
7383d30708fSChicago Duan 
739b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
7407e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
741b52664e2SAppaRao Puli                 if (subValue == nullptr)
742e5aaf047SAppaRao Puli                 {
743bd79bce8SPatrick Williams                     asyncResp->res.result(
744bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
745e5aaf047SAppaRao Puli                     return;
746e5aaf047SAppaRao Puli                 }
7477e860f15SJohn Edward Broadbent                 const std::string& id = param;
748e5aaf047SAppaRao Puli 
7494b712a29SEd Tanous                 const persistent_data::UserSubscription& userSub =
7505fe4ef35SMyung Bae                     *subValue->userSub;
751e56f254cSSunitha Harish 
7524b712a29SEd Tanous                 nlohmann::json& jVal = asyncResp->res.jsonValue;
7534b712a29SEd Tanous                 jVal["@odata.type"] =
7544b712a29SEd Tanous                     "#EventDestination.v1_14_1.EventDestination";
7554b712a29SEd Tanous                 jVal["Protocol"] =
7564b712a29SEd Tanous                     event_destination::EventDestinationProtocol::Redfish;
7574b712a29SEd Tanous                 jVal["@odata.id"] = boost::urls::format(
7584b712a29SEd Tanous                     "/redfish/v1/EventService/Subscriptions/{}", id);
7594b712a29SEd Tanous                 jVal["Id"] = id;
7604b712a29SEd Tanous                 jVal["Name"] = "Event Destination " + id;
7614b712a29SEd Tanous                 jVal["Destination"] = userSub.destinationUrl;
7624b712a29SEd Tanous                 jVal["Context"] = userSub.customText;
7634b712a29SEd Tanous                 jVal["SubscriptionType"] = userSub.subscriptionType;
7644b712a29SEd Tanous                 jVal["HttpHeaders"] = nlohmann::json::array();
7654b712a29SEd Tanous                 jVal["EventFormatType"] = userSub.eventFormatType;
7664b712a29SEd Tanous                 jVal["RegistryPrefixes"] = userSub.registryPrefixes;
7674b712a29SEd Tanous                 jVal["ResourceTypes"] = userSub.resourceTypes;
7684b712a29SEd Tanous 
7694b712a29SEd Tanous                 jVal["MessageIds"] = userSub.registryMsgIds;
7704b712a29SEd Tanous                 jVal["DeliveryRetryPolicy"] = userSub.retryPolicy;
7715064a25bSMyung Bae                 jVal["SendHeartbeat"] = userSub.sendHeartbeat;
7725064a25bSMyung Bae                 jVal["HeartbeatIntervalMinutes"] = userSub.hbIntervalMinutes;
7734b712a29SEd Tanous                 jVal["VerifyCertificate"] = userSub.verifyCertificate;
774144b6318SAppaRao Puli 
7751476687dSEd Tanous                 nlohmann::json::array_t mrdJsonArray;
7764b712a29SEd Tanous                 for (const auto& mdrUri : userSub.metricReportDefinitions)
777144b6318SAppaRao Puli                 {
7781476687dSEd Tanous                     nlohmann::json::object_t mdr;
7791476687dSEd Tanous                     mdr["@odata.id"] = mdrUri;
7801476687dSEd Tanous                     mrdJsonArray.emplace_back(std::move(mdr));
781144b6318SAppaRao Puli                 }
7824b712a29SEd Tanous                 jVal["MetricReportDefinitions"] = mrdJsonArray;
7837e860f15SJohn Edward Broadbent             });
7849d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
785ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
786ed398213SEd Tanous         // ConfigureSelf
7877eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
788ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
789432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
7907e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
79145ca1b86SEd Tanous             [&app](const crow::Request& req,
7927e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7937e860f15SJohn Edward Broadbent                    const std::string& param) {
7943ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
79545ca1b86SEd Tanous                 {
79645ca1b86SEd Tanous                     return;
79745ca1b86SEd Tanous                 }
798b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
7997e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
800b52664e2SAppaRao Puli                 if (subValue == nullptr)
801e5aaf047SAppaRao Puli                 {
802bd79bce8SPatrick Williams                     asyncResp->res.result(
803bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
804e5aaf047SAppaRao Puli                     return;
805e5aaf047SAppaRao Puli                 }
806e5aaf047SAppaRao Puli 
807e5aaf047SAppaRao Puli                 std::optional<std::string> context;
808e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
8095064a25bSMyung Bae                 std::optional<bool> sendHeartbeat;
8105064a25bSMyung Bae                 std::optional<uint64_t> hbIntervalMinutes;
81119bb362bSEd Tanous                 std::optional<bool> verifyCertificate;
81278d4ec4fSEd Tanous                 std::optional<std::vector<nlohmann::json::object_t>> headers;
813e5aaf047SAppaRao Puli 
814afc474aeSMyung Bae                 if (!json_util::readJsonPatch( //
815afc474aeSMyung Bae                         req, asyncResp->res, //
816afc474aeSMyung Bae                         "Context", context, //
817afc474aeSMyung Bae                         "DeliveryRetryPolicy", retryPolicy, //
8185064a25bSMyung Bae                         "HeartbeatIntervalMinutes", hbIntervalMinutes, //
819afc474aeSMyung Bae                         "HttpHeaders", headers, //
8205064a25bSMyung Bae                         "SendHeartbeat", sendHeartbeat, //
821afc474aeSMyung Bae                         "VerifyCertificate", verifyCertificate //
822afc474aeSMyung Bae                         ))
823e5aaf047SAppaRao Puli                 {
824e5aaf047SAppaRao Puli                     return;
825e5aaf047SAppaRao Puli                 }
826e5aaf047SAppaRao Puli 
827e5aaf047SAppaRao Puli                 if (context)
828e5aaf047SAppaRao Puli                 {
8295fe4ef35SMyung Bae                     subValue->userSub->customText = *context;
830e5aaf047SAppaRao Puli                 }
831e5aaf047SAppaRao Puli 
832e5aaf047SAppaRao Puli                 if (headers)
833e5aaf047SAppaRao Puli                 {
834601c71aeSEd Tanous                     boost::beast::http::fields fields;
83578d4ec4fSEd Tanous                     for (const nlohmann::json::object_t& headerChunk : *headers)
836601c71aeSEd Tanous                     {
83778d4ec4fSEd Tanous                         for (const auto& it : headerChunk)
838601c71aeSEd Tanous                         {
839601c71aeSEd Tanous                             const std::string* value =
84078d4ec4fSEd Tanous                                 it.second.get_ptr<const std::string*>();
841601c71aeSEd Tanous                             if (value == nullptr)
842601c71aeSEd Tanous                             {
843601c71aeSEd Tanous                                 messages::propertyValueFormatError(
84478d4ec4fSEd Tanous                                     asyncResp->res, it.second,
84578d4ec4fSEd Tanous                                     "HttpHeaders/" + it.first);
846601c71aeSEd Tanous                                 return;
847601c71aeSEd Tanous                             }
84878d4ec4fSEd Tanous                             fields.set(it.first, *value);
849601c71aeSEd Tanous                         }
850601c71aeSEd Tanous                     }
8515fe4ef35SMyung Bae                     subValue->userSub->httpHeaders = std::move(fields);
852e5aaf047SAppaRao Puli                 }
853e5aaf047SAppaRao Puli 
854e5aaf047SAppaRao Puli                 if (retryPolicy)
855e5aaf047SAppaRao Puli                 {
856bd79bce8SPatrick Williams                     if (std::ranges::find(supportedRetryPolicies,
857bd79bce8SPatrick Williams                                           *retryPolicy) ==
8583544d2a7SEd Tanous                         supportedRetryPolicies.end())
859e5aaf047SAppaRao Puli                     {
860bd79bce8SPatrick Williams                         messages::propertyValueNotInList(asyncResp->res,
861bd79bce8SPatrick Williams                                                          *retryPolicy,
862e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
863e5aaf047SAppaRao Puli                         return;
864e5aaf047SAppaRao Puli                     }
8655fe4ef35SMyung Bae                     subValue->userSub->retryPolicy = *retryPolicy;
866e5aaf047SAppaRao Puli                 }
867e5aaf047SAppaRao Puli 
8685064a25bSMyung Bae                 if (sendHeartbeat)
8695064a25bSMyung Bae                 {
8705064a25bSMyung Bae                     subValue->userSub->sendHeartbeat = *sendHeartbeat;
8715064a25bSMyung Bae                 }
8725064a25bSMyung Bae                 if (hbIntervalMinutes)
8735064a25bSMyung Bae                 {
8745064a25bSMyung Bae                     if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535)
8755064a25bSMyung Bae                     {
8765064a25bSMyung Bae                         messages::propertyValueOutOfRange(
8775064a25bSMyung Bae                             asyncResp->res, *hbIntervalMinutes,
8785064a25bSMyung Bae                             "HeartbeatIntervalMinutes");
8795064a25bSMyung Bae                         return;
8805064a25bSMyung Bae                     }
8815064a25bSMyung Bae                     subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes;
8825064a25bSMyung Bae                 }
8835064a25bSMyung Bae 
884*fb546105SMyung Bae                 if (hbIntervalMinutes || sendHeartbeat)
885*fb546105SMyung Bae                 {
886*fb546105SMyung Bae                     // if Heartbeat interval or send heart were changed, cancel
887*fb546105SMyung Bae                     // the heartbeat timer if running and start a new heartbeat
888*fb546105SMyung Bae                     // if needed
889*fb546105SMyung Bae                     subValue->heartbeatParametersChanged();
890*fb546105SMyung Bae                 }
891*fb546105SMyung Bae 
89219bb362bSEd Tanous                 if (verifyCertificate)
89319bb362bSEd Tanous                 {
8945fe4ef35SMyung Bae                     subValue->userSub->verifyCertificate = *verifyCertificate;
89519bb362bSEd Tanous                 }
89619bb362bSEd Tanous 
897b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
8987e860f15SJohn Edward Broadbent             });
8999d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
900ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
901ed398213SEd Tanous         // ConfigureSelf
9027eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
903ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
904432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
9057e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
90645ca1b86SEd Tanous             [&app](const crow::Request& req,
9077e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9087e860f15SJohn Edward Broadbent                    const std::string& param) {
9093ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
91045ca1b86SEd Tanous                 {
91145ca1b86SEd Tanous                     return;
91245ca1b86SEd Tanous                 }
9134b712a29SEd Tanous                 EventServiceManager& event = EventServiceManager::getInstance();
9143d30708fSChicago Duan                 if (param.starts_with("snmp"))
9153d30708fSChicago Duan                 {
9163d30708fSChicago Duan                     deleteSnmpTrapClient(asyncResp, param);
9174b712a29SEd Tanous                     event.deleteSubscription(param);
9183d30708fSChicago Duan                     return;
9193d30708fSChicago Duan                 }
9203d30708fSChicago Duan 
9214b712a29SEd Tanous                 if (!event.deleteSubscription(param))
922e5aaf047SAppaRao Puli                 {
9234b712a29SEd Tanous                     messages::resourceNotFound(asyncResp->res,
9244b712a29SEd Tanous                                                "EventDestination", param);
925e5aaf047SAppaRao Puli                     return;
926e5aaf047SAppaRao Puli                 }
9274b712a29SEd Tanous                 messages::success(asyncResp->res);
9287e860f15SJohn Edward Broadbent             });
929e5aaf047SAppaRao Puli }
930e5aaf047SAppaRao Puli 
931e5aaf047SAppaRao Puli } // namespace redfish
932