xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision 4a102cd48c588d32c0a4d6610b4a9ed616f255f3)
140e9b92eSEd Tanous // SPDX-License-Identifier: Apache-2.0
240e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright OpenBMC Authors
340e9b92eSEd Tanous // SPDX-FileCopyrightText: Copyright 2020 Intel Corporation
4e5aaf047SAppaRao Puli #pragma once
53ccb3adbSEd Tanous #include "app.hpp"
6d7857201SEd Tanous #include "async_resp.hpp"
7d7857201SEd Tanous #include "dbus_utility.hpp"
8d7857201SEd Tanous #include "error_messages.hpp"
9b52664e2SAppaRao Puli #include "event_service_manager.hpp"
10d7857201SEd Tanous #include "event_service_store.hpp"
11d7857201SEd Tanous #include "generated/enums/event_destination.hpp"
123ccb3adbSEd Tanous #include "http/utility.hpp"
13d7857201SEd Tanous #include "http_request.hpp"
149838eb20SEd Tanous #include "io_context_singleton.hpp"
153ccb3adbSEd Tanous #include "logging.hpp"
163ccb3adbSEd Tanous #include "query.hpp"
17d109e2b6SAlexander Hansen #include "registries.hpp"
183ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
193d30708fSChicago Duan #include "snmp_trap_event_clients.hpp"
20d7857201SEd Tanous #include "subscription.hpp"
21d109e2b6SAlexander Hansen #include "utils/json_utils.hpp"
22e5aaf047SAppaRao Puli 
23d7857201SEd Tanous #include <asm-generic/errno.h>
24ed398213SEd Tanous 
25d7857201SEd Tanous #include <boost/beast/http/fields.hpp>
26d7857201SEd Tanous #include <boost/beast/http/status.hpp>
27d7857201SEd Tanous #include <boost/beast/http/verb.hpp>
28d7857201SEd Tanous #include <boost/system/error_code.hpp>
29d7857201SEd Tanous #include <boost/system/result.hpp>
30d7857201SEd Tanous #include <boost/url/format.hpp>
31d7857201SEd Tanous #include <boost/url/parse.hpp>
32d7857201SEd Tanous #include <boost/url/url.hpp>
33d7857201SEd Tanous #include <sdbusplus/message/native_types.hpp>
34d7857201SEd Tanous 
35d7857201SEd Tanous #include <algorithm>
36d7857201SEd Tanous #include <array>
37d7857201SEd Tanous #include <cerrno>
38d7857201SEd Tanous #include <cstddef>
39d7857201SEd Tanous #include <cstdint>
403d30708fSChicago Duan #include <memory>
415064a25bSMyung Bae #include <optional>
423544d2a7SEd Tanous #include <ranges>
433d30708fSChicago Duan #include <string>
44d7857201SEd Tanous #include <utility>
45a14c9113SEd Tanous #include <vector>
461e270c5fSPatrick Williams 
47e5aaf047SAppaRao Puli namespace redfish
48e5aaf047SAppaRao Puli {
49e5aaf047SAppaRao Puli 
50156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
51156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
52fb546105SMyung Bae static constexpr const std::array<const char*, 4> supportedRegPrefixes = {
53fb546105SMyung Bae     "Base", "OpenBMC", "TaskEvent", "HeartbeatEvent"};
54e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
55e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
56e5aaf047SAppaRao Puli 
57fb546105SMyung Bae static constexpr const std::array<const char*, 2> supportedResourceTypes = {
58fb546105SMyung Bae     "Task", "Heartbeat"};
59e56f254cSSunitha Harish 
607e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app)
61e5aaf047SAppaRao Puli {
627e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
63ed398213SEd Tanous         .privileges(redfish::privileges::getEventService)
64bd79bce8SPatrick Williams         .methods(
65bd79bce8SPatrick Williams             boost::beast::http::verb::
66bd79bce8SPatrick Williams                 get)([&app](
67bd79bce8SPatrick Williams                          const crow::Request& req,
68002d39b4SEd Tanous                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
693ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
7045ca1b86SEd Tanous             {
7145ca1b86SEd Tanous                 return;
7245ca1b86SEd Tanous             }
731476687dSEd Tanous 
741476687dSEd Tanous             asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
751476687dSEd Tanous             asyncResp->res.jsonValue["@odata.type"] =
761476687dSEd Tanous                 "#EventService.v1_5_0.EventService";
771476687dSEd Tanous             asyncResp->res.jsonValue["Id"] = "EventService";
781476687dSEd Tanous             asyncResp->res.jsonValue["Name"] = "Event Service";
795e44e3d8SAppaRao Puli             asyncResp->res.jsonValue["ServerSentEventUri"] =
805e44e3d8SAppaRao Puli                 "/redfish/v1/EventService/SSE";
815e44e3d8SAppaRao Puli 
821476687dSEd Tanous             asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
831476687dSEd Tanous                 "/redfish/v1/EventService/Subscriptions";
84bd79bce8SPatrick Williams             asyncResp->res.jsonValue["Actions"]["#EventService.SubmitTestEvent"]
85bd79bce8SPatrick Williams                                     ["target"] =
861476687dSEd Tanous                 "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
87e5aaf047SAppaRao Puli 
8828afb49cSJunLin Chen             const persistent_data::EventServiceConfig eventServiceConfig =
8928afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
9028afb49cSJunLin Chen                     .getEventServiceConfig();
917d1cc387SAppaRao Puli 
927d1cc387SAppaRao Puli             asyncResp->res.jsonValue["Status"]["State"] =
9328afb49cSJunLin Chen                 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
94bd79bce8SPatrick Williams             asyncResp->res.jsonValue["ServiceEnabled"] =
95bd79bce8SPatrick Williams                 eventServiceConfig.enabled;
967e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
9728afb49cSJunLin Chen                 eventServiceConfig.retryAttempts;
98e5aaf047SAppaRao Puli             asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
9928afb49cSJunLin Chen                 eventServiceConfig.retryTimeoutInterval;
100bd79bce8SPatrick Williams             asyncResp->res.jsonValue["EventFormatTypes"] =
101bd79bce8SPatrick Williams                 supportedEvtFormatTypes;
1020fda0f12SGeorge Liu             asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
1030fda0f12SGeorge Liu             asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
10407941a88SAyushi Smriti 
105613dabeaSEd Tanous             nlohmann::json::object_t supportedSSEFilters;
106613dabeaSEd Tanous             supportedSSEFilters["EventFormatType"] = true;
107613dabeaSEd Tanous             supportedSSEFilters["MessageId"] = true;
108613dabeaSEd Tanous             supportedSSEFilters["MetricReportDefinition"] = true;
109613dabeaSEd Tanous             supportedSSEFilters["RegistryPrefix"] = true;
110613dabeaSEd Tanous             supportedSSEFilters["OriginResource"] = false;
111613dabeaSEd Tanous             supportedSSEFilters["ResourceType"] = false;
11207941a88SAyushi Smriti 
11307941a88SAyushi Smriti             asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
114613dabeaSEd Tanous                 std::move(supportedSSEFilters);
1157e860f15SJohn Edward Broadbent         });
116e5aaf047SAppaRao Puli 
1177e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
118ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
1197e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
12045ca1b86SEd Tanous             [&app](const crow::Request& req,
12145ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1223ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
123e5aaf047SAppaRao Puli                 {
12445ca1b86SEd Tanous                     return;
12545ca1b86SEd Tanous                 }
126e5aaf047SAppaRao Puli                 std::optional<bool> serviceEnabled;
127e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryAttemps;
128e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryInterval;
129afc474aeSMyung Bae                 if (!json_util::readJsonPatch(                         //
130afc474aeSMyung Bae                         req, asyncResp->res,                           //
131afc474aeSMyung Bae                         "DeliveryRetryAttempts", retryAttemps,         //
132afc474aeSMyung Bae                         "DeliveryRetryIntervalSeconds", retryInterval, //
133afc474aeSMyung Bae                         "ServiceEnabled", serviceEnabled               //
134afc474aeSMyung Bae                         ))
135e5aaf047SAppaRao Puli                 {
136e5aaf047SAppaRao Puli                     return;
137e5aaf047SAppaRao Puli                 }
138e5aaf047SAppaRao Puli 
13928afb49cSJunLin Chen                 persistent_data::EventServiceConfig eventServiceConfig =
14028afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
14128afb49cSJunLin Chen                         .getEventServiceConfig();
1427d1cc387SAppaRao Puli 
143e5aaf047SAppaRao Puli                 if (serviceEnabled)
144e5aaf047SAppaRao Puli                 {
14528afb49cSJunLin Chen                     eventServiceConfig.enabled = *serviceEnabled;
146e5aaf047SAppaRao Puli                 }
147e5aaf047SAppaRao Puli 
148e5aaf047SAppaRao Puli                 if (retryAttemps)
149e5aaf047SAppaRao Puli                 {
150e5aaf047SAppaRao Puli                     // Supported range [1-3]
151e5aaf047SAppaRao Puli                     if ((*retryAttemps < 1) || (*retryAttemps > 3))
152e5aaf047SAppaRao Puli                     {
153e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
154e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryAttemps),
155e5aaf047SAppaRao Puli                             "DeliveryRetryAttempts", "[1-3]");
156e5aaf047SAppaRao Puli                     }
157e5aaf047SAppaRao Puli                     else
158e5aaf047SAppaRao Puli                     {
15928afb49cSJunLin Chen                         eventServiceConfig.retryAttempts = *retryAttemps;
160e5aaf047SAppaRao Puli                     }
161e5aaf047SAppaRao Puli                 }
162e5aaf047SAppaRao Puli 
163e5aaf047SAppaRao Puli                 if (retryInterval)
164e5aaf047SAppaRao Puli                 {
16533a32b34SGunnar Mills                     // Supported range [5 - 180]
16633a32b34SGunnar Mills                     if ((*retryInterval < 5) || (*retryInterval > 180))
167e5aaf047SAppaRao Puli                     {
168e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
169e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryInterval),
17033a32b34SGunnar Mills                             "DeliveryRetryIntervalSeconds", "[5-180]");
171e5aaf047SAppaRao Puli                     }
172e5aaf047SAppaRao Puli                     else
173e5aaf047SAppaRao Puli                     {
174bd79bce8SPatrick Williams                         eventServiceConfig.retryTimeoutInterval =
175bd79bce8SPatrick Williams                             *retryInterval;
176e5aaf047SAppaRao Puli                     }
177e5aaf047SAppaRao Puli                 }
178e5aaf047SAppaRao Puli 
1797d1cc387SAppaRao Puli                 EventServiceManager::getInstance().setEventServiceConfig(
18028afb49cSJunLin Chen                     eventServiceConfig);
1817e860f15SJohn Edward Broadbent             });
1820b4bdd93SAppaRao Puli }
1830b4bdd93SAppaRao Puli 
1847e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1850b4bdd93SAppaRao Puli {
1867e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1877e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
188ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1897e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
19045ca1b86SEd Tanous             [&app](const crow::Request& req,
1917e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1923ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
19345ca1b86SEd Tanous                 {
19445ca1b86SEd Tanous                     return;
19545ca1b86SEd Tanous                 }
19681ee0e74SChandramohan Harkude 
1974a19a7b5SEd Tanous                 // From the Redfish spec on EventId
1984a19a7b5SEd Tanous                 // A service can ignore this value and replace it with its own.
1994a19a7b5SEd Tanous                 // note that this parameter is intentionally ignored
2004a19a7b5SEd Tanous 
2014a19a7b5SEd Tanous                 std::optional<std::string> eventId;
20281ee0e74SChandramohan Harkude                 TestEvent testEvent;
20381ee0e74SChandramohan Harkude                 // clang-format off
20481ee0e74SChandramohan Harkude                 if (!json_util::readJsonAction(
20581ee0e74SChandramohan Harkude                         req, asyncResp->res,
20681ee0e74SChandramohan Harkude                         "EventGroupId", testEvent.eventGroupId,
2074a19a7b5SEd Tanous                         "EventId", eventId,
20881ee0e74SChandramohan Harkude                         "EventTimestamp", testEvent.eventTimestamp,
20981ee0e74SChandramohan Harkude                         "Message", testEvent.message,
21081ee0e74SChandramohan Harkude                         "MessageArgs", testEvent.messageArgs,
21181ee0e74SChandramohan Harkude                         "MessageId", testEvent.messageId,
21281ee0e74SChandramohan Harkude                         "OriginOfCondition", testEvent.originOfCondition,
21381ee0e74SChandramohan Harkude                         "Resolution", testEvent.resolution,
21481ee0e74SChandramohan Harkude                         "Severity", testEvent.severity))
21581ee0e74SChandramohan Harkude                 {
21681ee0e74SChandramohan Harkude                     return;
21781ee0e74SChandramohan Harkude                 }
21881ee0e74SChandramohan Harkude                 // clang-format on
21981ee0e74SChandramohan Harkude 
22081ee0e74SChandramohan Harkude                 if (!EventServiceManager::getInstance().sendTestEventLog(
22181ee0e74SChandramohan Harkude                         testEvent))
2226ba8c82eSsunharis_in                 {
2236ba8c82eSsunharis_in                     messages::serviceDisabled(asyncResp->res,
2246ba8c82eSsunharis_in                                               "/redfish/v1/EventService/");
2256ba8c82eSsunharis_in                     return;
2266ba8c82eSsunharis_in                 }
2278d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
2287e860f15SJohn Edward Broadbent             });
229e5aaf047SAppaRao Puli }
230e5aaf047SAppaRao Puli 
2313d30708fSChicago Duan inline void doSubscriptionCollection(
232e81de512SEd Tanous     const boost::system::error_code& ec,
2333d30708fSChicago Duan     const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
2343d30708fSChicago Duan     const dbus::utility::ManagedObjectType& resp)
2353d30708fSChicago Duan {
2363d30708fSChicago Duan     if (ec)
2373d30708fSChicago Duan     {
2381306101eSEd Tanous         if (ec.value() == EBADR || ec.value() == EHOSTUNREACH)
2393d30708fSChicago Duan         {
2403d30708fSChicago Duan             // This is an optional process so just return if it isn't there
2413d30708fSChicago Duan             return;
2423d30708fSChicago Duan         }
2433d30708fSChicago Duan 
24462598e31SEd Tanous         BMCWEB_LOG_ERROR("D-Bus response error on GetManagedObjects {}", ec);
2453d30708fSChicago Duan         messages::internalError(asyncResp->res);
2463d30708fSChicago Duan         return;
2473d30708fSChicago Duan     }
2483d30708fSChicago Duan     nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
2493d30708fSChicago Duan     for (const auto& objpath : resp)
2503d30708fSChicago Duan     {
2513d30708fSChicago Duan         sdbusplus::message::object_path path(objpath.first);
2523d30708fSChicago Duan         const std::string snmpId = path.filename();
2533d30708fSChicago Duan         if (snmpId.empty())
2543d30708fSChicago Duan         {
25562598e31SEd Tanous             BMCWEB_LOG_ERROR("The SNMP client ID is wrong");
2563d30708fSChicago Duan             messages::internalError(asyncResp->res);
2573d30708fSChicago Duan             return;
2583d30708fSChicago Duan         }
2593d30708fSChicago Duan 
2603d30708fSChicago Duan         getSnmpSubscriptionList(asyncResp, snmpId, memberArray);
2613d30708fSChicago Duan     }
2623d30708fSChicago Duan }
2633d30708fSChicago Duan 
2647e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
265e5aaf047SAppaRao Puli {
2661ebe3e41SGayathri Leburu     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
267ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
2687e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
26945ca1b86SEd Tanous             [&app](const crow::Request& req,
2707e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2713ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
27245ca1b86SEd Tanous                 {
27345ca1b86SEd Tanous                     return;
27445ca1b86SEd Tanous                 }
2751476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.type"] =
2761476687dSEd Tanous                     "#EventDestinationCollection.EventDestinationCollection";
2771476687dSEd Tanous                 asyncResp->res.jsonValue["@odata.id"] =
2781476687dSEd Tanous                     "/redfish/v1/EventService/Subscriptions";
279bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Name"] =
280bd79bce8SPatrick Williams                     "Event Destination Collections";
281e5aaf047SAppaRao Puli 
282bd79bce8SPatrick Williams                 nlohmann::json& memberArray =
283bd79bce8SPatrick Williams                     asyncResp->res.jsonValue["Members"];
284e5aaf047SAppaRao Puli 
285b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
286b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
287b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
288bd79bce8SPatrick Williams                 asyncResp->res.jsonValue["Members@odata.count"] =
289bd79bce8SPatrick Williams                     subscripIds.size();
290b52664e2SAppaRao Puli 
291b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
292e5aaf047SAppaRao Puli                 {
2931476687dSEd Tanous                     nlohmann::json::object_t member;
2943d30708fSChicago Duan                     member["@odata.id"] = boost::urls::format(
2953d30708fSChicago Duan                         "/redfish/v1/EventService/Subscriptions/{}" + id);
296b2ba3072SPatrick Williams                     memberArray.emplace_back(std::move(member));
297e5aaf047SAppaRao Puli                 }
298177612aaSEd Tanous                 dbus::utility::async_method_call(
299177612aaSEd Tanous                     asyncResp,
300e81de512SEd Tanous                     [asyncResp](const boost::system::error_code& ec,
3013d30708fSChicago Duan                                 const dbus::utility::ManagedObjectType& resp) {
3023d30708fSChicago Duan                         doSubscriptionCollection(ec, asyncResp, resp);
3033d30708fSChicago Duan                     },
3043d30708fSChicago Duan                     "xyz.openbmc_project.Network.SNMP",
3053d30708fSChicago Duan                     "/xyz/openbmc_project/network/snmp/manager",
3063d30708fSChicago Duan                     "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
3077e860f15SJohn Edward Broadbent             });
3083d30708fSChicago Duan 
3097e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
3107eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
311bd79bce8SPatrick Williams         .methods(
312bd79bce8SPatrick Williams             boost::beast::http::verb::
313bd79bce8SPatrick Williams                 post)([&app](
314bd79bce8SPatrick Williams                           const crow::Request& req,
3157e860f15SJohn Edward Broadbent                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
3163ba00073SCarson Labrado             if (!redfish::setUpRedfishRoute(app, req, asyncResp))
31745ca1b86SEd Tanous             {
31845ca1b86SEd Tanous                 return;
31945ca1b86SEd Tanous             }
320fffb8c1fSEd Tanous             if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
321fffb8c1fSEd Tanous                 maxNoOfSubscriptions)
322e5aaf047SAppaRao Puli             {
323e5aaf047SAppaRao Puli                 messages::eventSubscriptionLimitExceeded(asyncResp->res);
324e5aaf047SAppaRao Puli                 return;
325e5aaf047SAppaRao Puli             }
326e5aaf047SAppaRao Puli             std::string destUrl;
327e5aaf047SAppaRao Puli             std::string protocol;
32819bb362bSEd Tanous             std::optional<bool> verifyCertificate;
329e5aaf047SAppaRao Puli             std::optional<std::string> context;
330e5aaf047SAppaRao Puli             std::optional<std::string> subscriptionType;
33123a21a1cSEd Tanous             std::optional<std::string> eventFormatType2;
332e5aaf047SAppaRao Puli             std::optional<std::string> retryPolicy;
3335064a25bSMyung Bae             std::optional<bool> sendHeartbeat;
3345064a25bSMyung Bae             std::optional<uint64_t> hbIntervalMinutes;
335e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> msgIds;
336e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> regPrefixes;
337a14c9113SEd Tanous             std::optional<std::vector<std::string>> originResources;
338e56f254cSSunitha Harish             std::optional<std::vector<std::string>> resTypes;
33978d4ec4fSEd Tanous             std::optional<std::vector<nlohmann::json::object_t>> headers;
34078d4ec4fSEd Tanous             std::optional<std::vector<nlohmann::json::object_t>> mrdJsonArray;
341e5aaf047SAppaRao Puli 
342afc474aeSMyung Bae             if (!json_util::readJsonPatch(                         //
343afc474aeSMyung Bae                     req, asyncResp->res,                           //
344afc474aeSMyung Bae                     "Context", context,                            //
345afc474aeSMyung Bae                     "DeliveryRetryPolicy", retryPolicy,            //
346afc474aeSMyung Bae                     "Destination", destUrl,                        //
347afc474aeSMyung Bae                     "EventFormatType", eventFormatType2,           //
3485064a25bSMyung Bae                     "HeartbeatIntervalMinutes", hbIntervalMinutes, //
349afc474aeSMyung Bae                     "HttpHeaders", headers,                        //
350afc474aeSMyung Bae                     "MessageIds", msgIds,                          //
351afc474aeSMyung Bae                     "MetricReportDefinitions", mrdJsonArray,       //
352afc474aeSMyung Bae                     "OriginResources", originResources,            //
353afc474aeSMyung Bae                     "Protocol", protocol,                          //
354afc474aeSMyung Bae                     "RegistryPrefixes", regPrefixes,               //
355afc474aeSMyung Bae                     "ResourceTypes", resTypes,                     //
3565064a25bSMyung Bae                     "SendHeartbeat", sendHeartbeat,                //
357afc474aeSMyung Bae                     "SubscriptionType", subscriptionType,          //
358afc474aeSMyung Bae                     "VerifyCertificate", verifyCertificate         //
3594b712a29SEd Tanous                     ))
360e5aaf047SAppaRao Puli             {
361e5aaf047SAppaRao Puli                 return;
362e5aaf047SAppaRao Puli             }
3634b712a29SEd Tanous             // clang-format on
364e5aaf047SAppaRao Puli 
365600af5f1SAppaRao Puli             // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
366600af5f1SAppaRao Puli             static constexpr const uint16_t maxDestinationSize = 2000;
367600af5f1SAppaRao Puli             if (destUrl.size() > maxDestinationSize)
368600af5f1SAppaRao Puli             {
369600af5f1SAppaRao Puli                 messages::stringValueTooLong(asyncResp->res, "Destination",
370600af5f1SAppaRao Puli                                              maxDestinationSize);
371600af5f1SAppaRao Puli                 return;
372600af5f1SAppaRao Puli             }
373600af5f1SAppaRao Puli 
374dd28ba82SAppaRao Puli             if (regPrefixes && msgIds)
375dd28ba82SAppaRao Puli             {
37626f6976fSEd Tanous                 if (!regPrefixes->empty() && !msgIds->empty())
377dd28ba82SAppaRao Puli                 {
378bd79bce8SPatrick Williams                     messages::propertyValueConflict(
379bd79bce8SPatrick Williams                         asyncResp->res, "MessageIds", "RegistryPrefixes");
380dd28ba82SAppaRao Puli                     return;
381dd28ba82SAppaRao Puli                 }
382dd28ba82SAppaRao Puli             }
383dd28ba82SAppaRao Puli 
3846fd29553SEd Tanous             boost::system::result<boost::urls::url> url =
385a716aa74SEd Tanous                 boost::urls::parse_absolute_uri(destUrl);
386a716aa74SEd Tanous             if (!url)
387e5aaf047SAppaRao Puli             {
388bd79bce8SPatrick Williams                 BMCWEB_LOG_WARNING(
389bd79bce8SPatrick Williams                     "Failed to validate and split destination url");
390e5aaf047SAppaRao Puli                 messages::propertyValueFormatError(asyncResp->res, destUrl,
391e5aaf047SAppaRao Puli                                                    "Destination");
392e5aaf047SAppaRao Puli                 return;
393e5aaf047SAppaRao Puli             }
394a716aa74SEd Tanous             url->normalize();
395b07942e3SGeorge Liu 
396b07942e3SGeorge Liu             // port_number returns zero if it is not a valid representable port
397b07942e3SGeorge Liu             if (url->has_port() && url->port_number() == 0)
398b07942e3SGeorge Liu             {
399b07942e3SGeorge Liu                 BMCWEB_LOG_WARNING("{} is an invalid port in destination url",
400b07942e3SGeorge Liu                                    url->port());
401b07942e3SGeorge Liu                 messages::propertyValueFormatError(asyncResp->res, destUrl,
402b07942e3SGeorge Liu                                                    "Destination");
403b07942e3SGeorge Liu                 return;
404b07942e3SGeorge Liu             }
405b07942e3SGeorge Liu 
406a716aa74SEd Tanous             crow::utility::setProtocolDefaults(*url, protocol);
407a716aa74SEd Tanous             crow::utility::setPortDefaults(*url);
408a716aa74SEd Tanous 
409a716aa74SEd Tanous             if (url->path().empty())
410a716aa74SEd Tanous             {
411a716aa74SEd Tanous                 url->set_path("/");
412a716aa74SEd Tanous             }
413a716aa74SEd Tanous 
414a716aa74SEd Tanous             if (url->has_userinfo())
415a716aa74SEd Tanous             {
416a716aa74SEd Tanous                 messages::propertyValueFormatError(asyncResp->res, destUrl,
417a716aa74SEd Tanous                                                    "Destination");
418a716aa74SEd Tanous                 return;
419a716aa74SEd Tanous             }
420b52664e2SAppaRao Puli 
4213d30708fSChicago Duan             if (protocol == "SNMPv2c")
4223d30708fSChicago Duan             {
4233d30708fSChicago Duan                 if (context)
4243d30708fSChicago Duan                 {
4253d30708fSChicago Duan                     messages::propertyValueConflict(asyncResp->res, "Context",
4263d30708fSChicago Duan                                                     "Protocol");
4273d30708fSChicago Duan                     return;
4283d30708fSChicago Duan                 }
4293d30708fSChicago Duan                 if (eventFormatType2)
4303d30708fSChicago Duan                 {
431bd79bce8SPatrick Williams                     messages::propertyValueConflict(
432bd79bce8SPatrick Williams                         asyncResp->res, "EventFormatType", "Protocol");
4333d30708fSChicago Duan                     return;
4343d30708fSChicago Duan                 }
4353d30708fSChicago Duan                 if (retryPolicy)
4363d30708fSChicago Duan                 {
437bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
438bd79bce8SPatrick Williams                                                     "RetryPolicy", "Protocol");
4393d30708fSChicago Duan                     return;
4403d30708fSChicago Duan                 }
4415064a25bSMyung Bae                 if (sendHeartbeat)
4425064a25bSMyung Bae                 {
4435064a25bSMyung Bae                     messages::propertyValueConflict(
4445064a25bSMyung Bae                         asyncResp->res, "SendHeartbeat", "Protocol");
4455064a25bSMyung Bae                     return;
4465064a25bSMyung Bae                 }
4475064a25bSMyung Bae                 if (hbIntervalMinutes)
4485064a25bSMyung Bae                 {
4495064a25bSMyung Bae                     messages::propertyValueConflict(
4505064a25bSMyung Bae                         asyncResp->res, "HeartbeatIntervalMinutes", "Protocol");
4515064a25bSMyung Bae                     return;
4525064a25bSMyung Bae                 }
4533d30708fSChicago Duan                 if (msgIds)
4543d30708fSChicago Duan                 {
455bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
456bd79bce8SPatrick Williams                                                     "MessageIds", "Protocol");
4573d30708fSChicago Duan                     return;
4583d30708fSChicago Duan                 }
4593d30708fSChicago Duan                 if (regPrefixes)
4603d30708fSChicago Duan                 {
461bd79bce8SPatrick Williams                     messages::propertyValueConflict(
462bd79bce8SPatrick Williams                         asyncResp->res, "RegistryPrefixes", "Protocol");
4633d30708fSChicago Duan                     return;
4643d30708fSChicago Duan                 }
4653d30708fSChicago Duan                 if (resTypes)
4663d30708fSChicago Duan                 {
467bd79bce8SPatrick Williams                     messages::propertyValueConflict(
468bd79bce8SPatrick Williams                         asyncResp->res, "ResourceTypes", "Protocol");
4693d30708fSChicago Duan                     return;
4703d30708fSChicago Duan                 }
4713d30708fSChicago Duan                 if (headers)
4723d30708fSChicago Duan                 {
473bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
474bd79bce8SPatrick Williams                                                     "HttpHeaders", "Protocol");
4753d30708fSChicago Duan                     return;
4763d30708fSChicago Duan                 }
4773d30708fSChicago Duan                 if (mrdJsonArray)
4783d30708fSChicago Duan                 {
4793d30708fSChicago Duan                     messages::propertyValueConflict(
4803d30708fSChicago Duan                         asyncResp->res, "MetricReportDefinitions", "Protocol");
4813d30708fSChicago Duan                     return;
4823d30708fSChicago Duan                 }
483a716aa74SEd Tanous                 if (url->scheme() != "snmp")
484a716aa74SEd Tanous                 {
485bd79bce8SPatrick Williams                     messages::propertyValueConflict(asyncResp->res,
486bd79bce8SPatrick Williams                                                     "Destination", "Protocol");
4873d30708fSChicago Duan                     return;
4883d30708fSChicago Duan                 }
4893d30708fSChicago Duan 
490a716aa74SEd Tanous                 addSnmpTrapClient(asyncResp, url->host_address(),
491a716aa74SEd Tanous                                   url->port_number());
492a716aa74SEd Tanous                 return;
493b52664e2SAppaRao Puli             }
4943d30708fSChicago Duan 
495a716aa74SEd Tanous             std::shared_ptr<Subscription> subValue =
49621a94d5cSMyung Bae                 std::make_shared<Subscription>(
4975fe4ef35SMyung Bae                     std::make_shared<persistent_data::UserSubscription>(), *url,
4989838eb20SEd Tanous                     getIoContext());
499e5aaf047SAppaRao Puli 
500e5aaf047SAppaRao Puli             if (subscriptionType)
501e5aaf047SAppaRao Puli             {
502e5aaf047SAppaRao Puli                 if (*subscriptionType != "RedfishEvent")
503e5aaf047SAppaRao Puli                 {
504fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
505fffb8c1fSEd Tanous                         asyncResp->res, *subscriptionType, "SubscriptionType");
506e5aaf047SAppaRao Puli                     return;
507e5aaf047SAppaRao Puli                 }
5085fe4ef35SMyung Bae                 subValue->userSub->subscriptionType = *subscriptionType;
509e5aaf047SAppaRao Puli             }
510e5aaf047SAppaRao Puli             else
511e5aaf047SAppaRao Puli             {
5124b712a29SEd Tanous                 // Default
5135fe4ef35SMyung Bae                 subValue->userSub->subscriptionType = "RedfishEvent";
514e5aaf047SAppaRao Puli             }
515e5aaf047SAppaRao Puli 
516e5aaf047SAppaRao Puli             if (protocol != "Redfish")
517e5aaf047SAppaRao Puli             {
518e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, protocol,
519e5aaf047SAppaRao Puli                                                  "Protocol");
520e5aaf047SAppaRao Puli                 return;
521e5aaf047SAppaRao Puli             }
5225fe4ef35SMyung Bae             subValue->userSub->protocol = protocol;
523e5aaf047SAppaRao Puli 
52419bb362bSEd Tanous             if (verifyCertificate)
52519bb362bSEd Tanous             {
5265fe4ef35SMyung Bae                 subValue->userSub->verifyCertificate = *verifyCertificate;
52719bb362bSEd Tanous             }
52819bb362bSEd Tanous 
52923a21a1cSEd Tanous             if (eventFormatType2)
530e5aaf047SAppaRao Puli             {
531bd79bce8SPatrick Williams                 if (std::ranges::find(supportedEvtFormatTypes,
532bd79bce8SPatrick Williams                                       *eventFormatType2) ==
5333544d2a7SEd Tanous                     supportedEvtFormatTypes.end())
534e5aaf047SAppaRao Puli                 {
535fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
536fffb8c1fSEd Tanous                         asyncResp->res, *eventFormatType2, "EventFormatType");
537e5aaf047SAppaRao Puli                     return;
538e5aaf047SAppaRao Puli                 }
5395fe4ef35SMyung Bae                 subValue->userSub->eventFormatType = *eventFormatType2;
540e5aaf047SAppaRao Puli             }
541e5aaf047SAppaRao Puli             else
542e5aaf047SAppaRao Puli             {
543e5aaf047SAppaRao Puli                 // If not specified, use default "Event"
5445fe4ef35SMyung Bae                 subValue->userSub->eventFormatType = "Event";
545e5aaf047SAppaRao Puli             }
546e5aaf047SAppaRao Puli 
547e5aaf047SAppaRao Puli             if (context)
548e5aaf047SAppaRao Puli             {
5498ece0e45SEd Tanous                 // This value is selected arbitrarily.
550600af5f1SAppaRao Puli                 constexpr const size_t maxContextSize = 256;
551600af5f1SAppaRao Puli                 if (context->size() > maxContextSize)
552600af5f1SAppaRao Puli                 {
553600af5f1SAppaRao Puli                     messages::stringValueTooLong(asyncResp->res, "Context",
554600af5f1SAppaRao Puli                                                  maxContextSize);
555600af5f1SAppaRao Puli                     return;
556600af5f1SAppaRao Puli                 }
5575fe4ef35SMyung Bae                 subValue->userSub->customText = *context;
558e5aaf047SAppaRao Puli             }
559e5aaf047SAppaRao Puli 
560e5aaf047SAppaRao Puli             if (headers)
561e5aaf047SAppaRao Puli             {
562600af5f1SAppaRao Puli                 size_t cumulativeLen = 0;
563600af5f1SAppaRao Puli 
56478d4ec4fSEd Tanous                 for (const nlohmann::json::object_t& headerChunk : *headers)
565601c71aeSEd Tanous                 {
56678d4ec4fSEd Tanous                     for (const auto& item : headerChunk)
56778d4ec4fSEd Tanous                     {
56878d4ec4fSEd Tanous                         const std::string* value =
56978d4ec4fSEd Tanous                             item.second.get_ptr<const std::string*>();
57078d4ec4fSEd Tanous                         if (value == nullptr)
57178d4ec4fSEd Tanous                         {
57278d4ec4fSEd Tanous                             messages::propertyValueFormatError(
57378d4ec4fSEd Tanous                                 asyncResp->res, item.second,
57478d4ec4fSEd Tanous                                 "HttpHeaders/" + item.first);
57578d4ec4fSEd Tanous                             return;
57678d4ec4fSEd Tanous                         }
57778d4ec4fSEd Tanous                         // Adding a new json value is the size of the key, +
57878d4ec4fSEd Tanous                         // the size of the value + 2 * 2 quotes for each, +
57978d4ec4fSEd Tanous                         // the colon and space between. example:
58078d4ec4fSEd Tanous                         // "key": "value"
58178d4ec4fSEd Tanous                         cumulativeLen += item.first.size() + value->size() + 6;
582600af5f1SAppaRao Puli                         // This value is selected to mirror http_connection.hpp
583600af5f1SAppaRao Puli                         constexpr const uint16_t maxHeaderSizeED = 8096;
584600af5f1SAppaRao Puli                         if (cumulativeLen > maxHeaderSizeED)
585600af5f1SAppaRao Puli                         {
58678d4ec4fSEd Tanous                             messages::arraySizeTooLong(
58778d4ec4fSEd Tanous                                 asyncResp->res, "HttpHeaders", maxHeaderSizeED);
588600af5f1SAppaRao Puli                             return;
589600af5f1SAppaRao Puli                         }
5905fe4ef35SMyung Bae                         subValue->userSub->httpHeaders.set(item.first, *value);
591601c71aeSEd Tanous                     }
592601c71aeSEd Tanous                 }
593e5aaf047SAppaRao Puli             }
594e5aaf047SAppaRao Puli 
595e5aaf047SAppaRao Puli             if (regPrefixes)
596e5aaf047SAppaRao Puli             {
597e5aaf047SAppaRao Puli                 for (const std::string& it : *regPrefixes)
598e5aaf047SAppaRao Puli                 {
5993544d2a7SEd Tanous                     if (std::ranges::find(supportedRegPrefixes, it) ==
6003544d2a7SEd Tanous                         supportedRegPrefixes.end())
601e5aaf047SAppaRao Puli                     {
602fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
603fffb8c1fSEd Tanous                                                          "RegistryPrefixes");
604e5aaf047SAppaRao Puli                         return;
605e5aaf047SAppaRao Puli                     }
606e5aaf047SAppaRao Puli                 }
6075fe4ef35SMyung Bae                 subValue->userSub->registryPrefixes = *regPrefixes;
608e5aaf047SAppaRao Puli             }
609e5aaf047SAppaRao Puli 
610a14c9113SEd Tanous             if (originResources)
611a14c9113SEd Tanous             {
6125fe4ef35SMyung Bae                 subValue->userSub->originResources = *originResources;
613a14c9113SEd Tanous             }
614a14c9113SEd Tanous 
615e56f254cSSunitha Harish             if (resTypes)
616e56f254cSSunitha Harish             {
617e56f254cSSunitha Harish                 for (const std::string& it : *resTypes)
618e56f254cSSunitha Harish                 {
6193544d2a7SEd Tanous                     if (std::ranges::find(supportedResourceTypes, it) ==
6203544d2a7SEd Tanous                         supportedResourceTypes.end())
621e56f254cSSunitha Harish                     {
622e56f254cSSunitha Harish                         messages::propertyValueNotInList(asyncResp->res, it,
623e56f254cSSunitha Harish                                                          "ResourceTypes");
624e56f254cSSunitha Harish                         return;
625e56f254cSSunitha Harish                     }
626e56f254cSSunitha Harish                 }
6275fe4ef35SMyung Bae                 subValue->userSub->resourceTypes = *resTypes;
628e56f254cSSunitha Harish             }
629e56f254cSSunitha Harish 
630e5aaf047SAppaRao Puli             if (msgIds)
631e5aaf047SAppaRao Puli             {
632b304bd79SP Dheeraj Srujan Kumar                 std::vector<std::string> registryPrefix;
633b304bd79SP Dheeraj Srujan Kumar 
6347e860f15SJohn Edward Broadbent                 // If no registry prefixes are mentioned, consider all
6357e860f15SJohn Edward Broadbent                 // supported prefixes
6365fe4ef35SMyung Bae                 if (subValue->userSub->registryPrefixes.empty())
637b304bd79SP Dheeraj Srujan Kumar                 {
638b304bd79SP Dheeraj Srujan Kumar                     registryPrefix.assign(supportedRegPrefixes.begin(),
639b304bd79SP Dheeraj Srujan Kumar                                           supportedRegPrefixes.end());
640b304bd79SP Dheeraj Srujan Kumar                 }
641b304bd79SP Dheeraj Srujan Kumar                 else
642b304bd79SP Dheeraj Srujan Kumar                 {
6435fe4ef35SMyung Bae                     registryPrefix = subValue->userSub->registryPrefixes;
644b304bd79SP Dheeraj Srujan Kumar                 }
645b304bd79SP Dheeraj Srujan Kumar 
646b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& id : *msgIds)
647b304bd79SP Dheeraj Srujan Kumar                 {
648b304bd79SP Dheeraj Srujan Kumar                     bool validId = false;
649b304bd79SP Dheeraj Srujan Kumar 
650b304bd79SP Dheeraj Srujan Kumar                     // Check for Message ID in each of the selected Registry
651b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& it : registryPrefix)
652b304bd79SP Dheeraj Srujan Kumar                     {
653*4a102cd4SPatrick Williams                         const registries::MessageEntries registry =
654*4a102cd4SPatrick Williams                             redfish::registries::getRegistryMessagesFromPrefix(
655*4a102cd4SPatrick Williams                                 it);
656b304bd79SP Dheeraj Srujan Kumar 
6573544d2a7SEd Tanous                         if (std::ranges::any_of(
6583544d2a7SEd Tanous                                 registry,
659fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
660fffb8c1fSEd Tanous                                           messageEntry) {
66155f79e6fSEd Tanous                                     return id == messageEntry.first;
662b304bd79SP Dheeraj Srujan Kumar                                 }))
663b304bd79SP Dheeraj Srujan Kumar                         {
664b304bd79SP Dheeraj Srujan Kumar                             validId = true;
665b304bd79SP Dheeraj Srujan Kumar                             break;
666b304bd79SP Dheeraj Srujan Kumar                         }
667b304bd79SP Dheeraj Srujan Kumar                     }
668b304bd79SP Dheeraj Srujan Kumar 
669b304bd79SP Dheeraj Srujan Kumar                     if (!validId)
670b304bd79SP Dheeraj Srujan Kumar                     {
671b304bd79SP Dheeraj Srujan Kumar                         messages::propertyValueNotInList(asyncResp->res, id,
672b304bd79SP Dheeraj Srujan Kumar                                                          "MessageIds");
673b304bd79SP Dheeraj Srujan Kumar                         return;
674b304bd79SP Dheeraj Srujan Kumar                     }
675b304bd79SP Dheeraj Srujan Kumar                 }
676b304bd79SP Dheeraj Srujan Kumar 
6775fe4ef35SMyung Bae                 subValue->userSub->registryMsgIds = *msgIds;
678e5aaf047SAppaRao Puli             }
679e5aaf047SAppaRao Puli 
680e5aaf047SAppaRao Puli             if (retryPolicy)
681e5aaf047SAppaRao Puli             {
6823544d2a7SEd Tanous                 if (std::ranges::find(supportedRetryPolicies, *retryPolicy) ==
6833544d2a7SEd Tanous                     supportedRetryPolicies.end())
684e5aaf047SAppaRao Puli                 {
685bd79bce8SPatrick Williams                     messages::propertyValueNotInList(
686bd79bce8SPatrick Williams                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
687e5aaf047SAppaRao Puli                     return;
688e5aaf047SAppaRao Puli                 }
6895fe4ef35SMyung Bae                 subValue->userSub->retryPolicy = *retryPolicy;
690e5aaf047SAppaRao Puli             }
691e5aaf047SAppaRao Puli             else
692e5aaf047SAppaRao Puli             {
693e5aaf047SAppaRao Puli                 // Default "TerminateAfterRetries"
6945fe4ef35SMyung Bae                 subValue->userSub->retryPolicy = "TerminateAfterRetries";
695e5aaf047SAppaRao Puli             }
6965064a25bSMyung Bae             if (sendHeartbeat)
6975064a25bSMyung Bae             {
6985064a25bSMyung Bae                 subValue->userSub->sendHeartbeat = *sendHeartbeat;
6995064a25bSMyung Bae             }
7005064a25bSMyung Bae             if (hbIntervalMinutes)
7015064a25bSMyung Bae             {
7025064a25bSMyung Bae                 if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535)
7035064a25bSMyung Bae                 {
7045064a25bSMyung Bae                     messages::propertyValueOutOfRange(
7055064a25bSMyung Bae                         asyncResp->res, *hbIntervalMinutes,
7065064a25bSMyung Bae                         "HeartbeatIntervalMinutes");
7075064a25bSMyung Bae                     return;
7085064a25bSMyung Bae                 }
7095064a25bSMyung Bae                 subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes;
7105064a25bSMyung Bae             }
711e5aaf047SAppaRao Puli 
712144b6318SAppaRao Puli             if (mrdJsonArray)
713156d6b00SAppaRao Puli             {
71478d4ec4fSEd Tanous                 for (nlohmann::json::object_t& mrdObj : *mrdJsonArray)
715144b6318SAppaRao Puli                 {
716144b6318SAppaRao Puli                     std::string mrdUri;
717ea2e6eecSWilly Tu 
71878d4ec4fSEd Tanous                     if (!json_util::readJsonObject(mrdObj, asyncResp->res,
71978d4ec4fSEd Tanous                                                    "@odata.id", mrdUri))
720ea2e6eecSWilly Tu 
721144b6318SAppaRao Puli                     {
722144b6318SAppaRao Puli                         return;
723144b6318SAppaRao Puli                     }
7245fe4ef35SMyung Bae                     subValue->userSub->metricReportDefinitions.emplace_back(
7254b712a29SEd Tanous                         mrdUri);
726144b6318SAppaRao Puli                 }
727156d6b00SAppaRao Puli             }
728156d6b00SAppaRao Puli 
729b52664e2SAppaRao Puli             std::string id =
730bd79bce8SPatrick Williams                 EventServiceManager::getInstance().addPushSubscription(
731bd79bce8SPatrick Williams                     subValue);
732b52664e2SAppaRao Puli             if (id.empty())
733e5aaf047SAppaRao Puli             {
734e5aaf047SAppaRao Puli                 messages::internalError(asyncResp->res);
735e5aaf047SAppaRao Puli                 return;
736e5aaf047SAppaRao Puli             }
737e5aaf047SAppaRao Puli 
738e5aaf047SAppaRao Puli             messages::created(asyncResp->res);
739e5aaf047SAppaRao Puli             asyncResp->res.addHeader(
740e5aaf047SAppaRao Puli                 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
741fb546105SMyung Bae 
742fb546105SMyung Bae             // schedule a heartbeat
743fb546105SMyung Bae             if (subValue->userSub->sendHeartbeat)
744fb546105SMyung Bae             {
745fb546105SMyung Bae                 subValue->scheduleNextHeartbeatEvent();
746fb546105SMyung Bae             }
7477e860f15SJohn Edward Broadbent         });
748e5aaf047SAppaRao Puli }
749e5aaf047SAppaRao Puli 
7507e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
751e5aaf047SAppaRao Puli {
7529d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
753ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
7547e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
75545ca1b86SEd Tanous             [&app](const crow::Request& req,
7567e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
7577e860f15SJohn Edward Broadbent                    const std::string& param) {
7583ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
75945ca1b86SEd Tanous                 {
76045ca1b86SEd Tanous                     return;
76145ca1b86SEd Tanous                 }
7623d30708fSChicago Duan 
7633d30708fSChicago Duan                 if (param.starts_with("snmp"))
7643d30708fSChicago Duan                 {
7653d30708fSChicago Duan                     getSnmpTrapClient(asyncResp, param);
7663d30708fSChicago Duan                     return;
7673d30708fSChicago Duan                 }
7683d30708fSChicago Duan 
769b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
7707e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
771b52664e2SAppaRao Puli                 if (subValue == nullptr)
772e5aaf047SAppaRao Puli                 {
773bd79bce8SPatrick Williams                     asyncResp->res.result(
774bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
775e5aaf047SAppaRao Puli                     return;
776e5aaf047SAppaRao Puli                 }
7777e860f15SJohn Edward Broadbent                 const std::string& id = param;
778e5aaf047SAppaRao Puli 
7794b712a29SEd Tanous                 const persistent_data::UserSubscription& userSub =
7805fe4ef35SMyung Bae                     *subValue->userSub;
781e56f254cSSunitha Harish 
7824b712a29SEd Tanous                 nlohmann::json& jVal = asyncResp->res.jsonValue;
7834b712a29SEd Tanous                 jVal["@odata.type"] =
7844b712a29SEd Tanous                     "#EventDestination.v1_14_1.EventDestination";
7854b712a29SEd Tanous                 jVal["Protocol"] =
7864b712a29SEd Tanous                     event_destination::EventDestinationProtocol::Redfish;
7874b712a29SEd Tanous                 jVal["@odata.id"] = boost::urls::format(
7884b712a29SEd Tanous                     "/redfish/v1/EventService/Subscriptions/{}", id);
7894b712a29SEd Tanous                 jVal["Id"] = id;
7904b712a29SEd Tanous                 jVal["Name"] = "Event Destination " + id;
7914b712a29SEd Tanous                 jVal["Destination"] = userSub.destinationUrl;
7924b712a29SEd Tanous                 jVal["Context"] = userSub.customText;
7934b712a29SEd Tanous                 jVal["SubscriptionType"] = userSub.subscriptionType;
7944b712a29SEd Tanous                 jVal["HttpHeaders"] = nlohmann::json::array();
7954b712a29SEd Tanous                 jVal["EventFormatType"] = userSub.eventFormatType;
7964b712a29SEd Tanous                 jVal["RegistryPrefixes"] = userSub.registryPrefixes;
7974b712a29SEd Tanous                 jVal["ResourceTypes"] = userSub.resourceTypes;
7984b712a29SEd Tanous 
7994b712a29SEd Tanous                 jVal["MessageIds"] = userSub.registryMsgIds;
8004b712a29SEd Tanous                 jVal["DeliveryRetryPolicy"] = userSub.retryPolicy;
8015064a25bSMyung Bae                 jVal["SendHeartbeat"] = userSub.sendHeartbeat;
8025064a25bSMyung Bae                 jVal["HeartbeatIntervalMinutes"] = userSub.hbIntervalMinutes;
8034b712a29SEd Tanous                 jVal["VerifyCertificate"] = userSub.verifyCertificate;
804144b6318SAppaRao Puli 
8051476687dSEd Tanous                 nlohmann::json::array_t mrdJsonArray;
8064b712a29SEd Tanous                 for (const auto& mdrUri : userSub.metricReportDefinitions)
807144b6318SAppaRao Puli                 {
8081476687dSEd Tanous                     nlohmann::json::object_t mdr;
8091476687dSEd Tanous                     mdr["@odata.id"] = mdrUri;
8101476687dSEd Tanous                     mrdJsonArray.emplace_back(std::move(mdr));
811144b6318SAppaRao Puli                 }
8124b712a29SEd Tanous                 jVal["MetricReportDefinitions"] = mrdJsonArray;
8137e860f15SJohn Edward Broadbent             });
8149d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
815ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
816ed398213SEd Tanous         // ConfigureSelf
8177eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
818ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
819432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
8207e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
82145ca1b86SEd Tanous             [&app](const crow::Request& req,
8227e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
8237e860f15SJohn Edward Broadbent                    const std::string& param) {
8243ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
82545ca1b86SEd Tanous                 {
82645ca1b86SEd Tanous                     return;
82745ca1b86SEd Tanous                 }
828b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
8297e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
830b52664e2SAppaRao Puli                 if (subValue == nullptr)
831e5aaf047SAppaRao Puli                 {
832bd79bce8SPatrick Williams                     asyncResp->res.result(
833bd79bce8SPatrick Williams                         boost::beast::http::status::not_found);
834e5aaf047SAppaRao Puli                     return;
835e5aaf047SAppaRao Puli                 }
836e5aaf047SAppaRao Puli 
837e5aaf047SAppaRao Puli                 std::optional<std::string> context;
838e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
8395064a25bSMyung Bae                 std::optional<bool> sendHeartbeat;
8405064a25bSMyung Bae                 std::optional<uint64_t> hbIntervalMinutes;
84119bb362bSEd Tanous                 std::optional<bool> verifyCertificate;
84278d4ec4fSEd Tanous                 std::optional<std::vector<nlohmann::json::object_t>> headers;
843e5aaf047SAppaRao Puli 
844afc474aeSMyung Bae                 if (!json_util::readJsonPatch(                         //
845afc474aeSMyung Bae                         req, asyncResp->res,                           //
846afc474aeSMyung Bae                         "Context", context,                            //
847afc474aeSMyung Bae                         "DeliveryRetryPolicy", retryPolicy,            //
8485064a25bSMyung Bae                         "HeartbeatIntervalMinutes", hbIntervalMinutes, //
849afc474aeSMyung Bae                         "HttpHeaders", headers,                        //
8505064a25bSMyung Bae                         "SendHeartbeat", sendHeartbeat,                //
851afc474aeSMyung Bae                         "VerifyCertificate", verifyCertificate         //
852afc474aeSMyung Bae                         ))
853e5aaf047SAppaRao Puli                 {
854e5aaf047SAppaRao Puli                     return;
855e5aaf047SAppaRao Puli                 }
856e5aaf047SAppaRao Puli 
857e5aaf047SAppaRao Puli                 if (context)
858e5aaf047SAppaRao Puli                 {
8595fe4ef35SMyung Bae                     subValue->userSub->customText = *context;
860e5aaf047SAppaRao Puli                 }
861e5aaf047SAppaRao Puli 
862e5aaf047SAppaRao Puli                 if (headers)
863e5aaf047SAppaRao Puli                 {
864601c71aeSEd Tanous                     boost::beast::http::fields fields;
86578d4ec4fSEd Tanous                     for (const nlohmann::json::object_t& headerChunk : *headers)
866601c71aeSEd Tanous                     {
86778d4ec4fSEd Tanous                         for (const auto& it : headerChunk)
868601c71aeSEd Tanous                         {
869601c71aeSEd Tanous                             const std::string* value =
87078d4ec4fSEd Tanous                                 it.second.get_ptr<const std::string*>();
871601c71aeSEd Tanous                             if (value == nullptr)
872601c71aeSEd Tanous                             {
873601c71aeSEd Tanous                                 messages::propertyValueFormatError(
87478d4ec4fSEd Tanous                                     asyncResp->res, it.second,
87578d4ec4fSEd Tanous                                     "HttpHeaders/" + it.first);
876601c71aeSEd Tanous                                 return;
877601c71aeSEd Tanous                             }
87878d4ec4fSEd Tanous                             fields.set(it.first, *value);
879601c71aeSEd Tanous                         }
880601c71aeSEd Tanous                     }
8815fe4ef35SMyung Bae                     subValue->userSub->httpHeaders = std::move(fields);
882e5aaf047SAppaRao Puli                 }
883e5aaf047SAppaRao Puli 
884e5aaf047SAppaRao Puli                 if (retryPolicy)
885e5aaf047SAppaRao Puli                 {
886bd79bce8SPatrick Williams                     if (std::ranges::find(supportedRetryPolicies,
887bd79bce8SPatrick Williams                                           *retryPolicy) ==
8883544d2a7SEd Tanous                         supportedRetryPolicies.end())
889e5aaf047SAppaRao Puli                     {
890bd79bce8SPatrick Williams                         messages::propertyValueNotInList(asyncResp->res,
891bd79bce8SPatrick Williams                                                          *retryPolicy,
892e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
893e5aaf047SAppaRao Puli                         return;
894e5aaf047SAppaRao Puli                     }
8955fe4ef35SMyung Bae                     subValue->userSub->retryPolicy = *retryPolicy;
896e5aaf047SAppaRao Puli                 }
897e5aaf047SAppaRao Puli 
8985064a25bSMyung Bae                 if (sendHeartbeat)
8995064a25bSMyung Bae                 {
9005064a25bSMyung Bae                     subValue->userSub->sendHeartbeat = *sendHeartbeat;
9015064a25bSMyung Bae                 }
9025064a25bSMyung Bae                 if (hbIntervalMinutes)
9035064a25bSMyung Bae                 {
9045064a25bSMyung Bae                     if (*hbIntervalMinutes < 1 || *hbIntervalMinutes > 65535)
9055064a25bSMyung Bae                     {
9065064a25bSMyung Bae                         messages::propertyValueOutOfRange(
9075064a25bSMyung Bae                             asyncResp->res, *hbIntervalMinutes,
9085064a25bSMyung Bae                             "HeartbeatIntervalMinutes");
9095064a25bSMyung Bae                         return;
9105064a25bSMyung Bae                     }
9115064a25bSMyung Bae                     subValue->userSub->hbIntervalMinutes = *hbIntervalMinutes;
9125064a25bSMyung Bae                 }
9135064a25bSMyung Bae 
914fb546105SMyung Bae                 if (hbIntervalMinutes || sendHeartbeat)
915fb546105SMyung Bae                 {
916fb546105SMyung Bae                     // if Heartbeat interval or send heart were changed, cancel
917fb546105SMyung Bae                     // the heartbeat timer if running and start a new heartbeat
918fb546105SMyung Bae                     // if needed
919fb546105SMyung Bae                     subValue->heartbeatParametersChanged();
920fb546105SMyung Bae                 }
921fb546105SMyung Bae 
92219bb362bSEd Tanous                 if (verifyCertificate)
92319bb362bSEd Tanous                 {
9245fe4ef35SMyung Bae                     subValue->userSub->verifyCertificate = *verifyCertificate;
92519bb362bSEd Tanous                 }
92619bb362bSEd Tanous 
927b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
9287e860f15SJohn Edward Broadbent             });
9299d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
930ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
931ed398213SEd Tanous         // ConfigureSelf
9327eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
933ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
934432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
9357e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
93645ca1b86SEd Tanous             [&app](const crow::Request& req,
9377e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
9387e860f15SJohn Edward Broadbent                    const std::string& param) {
9393ba00073SCarson Labrado                 if (!redfish::setUpRedfishRoute(app, req, asyncResp))
94045ca1b86SEd Tanous                 {
94145ca1b86SEd Tanous                     return;
94245ca1b86SEd Tanous                 }
9434b712a29SEd Tanous                 EventServiceManager& event = EventServiceManager::getInstance();
9443d30708fSChicago Duan                 if (param.starts_with("snmp"))
9453d30708fSChicago Duan                 {
9463d30708fSChicago Duan                     deleteSnmpTrapClient(asyncResp, param);
9474b712a29SEd Tanous                     event.deleteSubscription(param);
9483d30708fSChicago Duan                     return;
9493d30708fSChicago Duan                 }
9503d30708fSChicago Duan 
9514b712a29SEd Tanous                 if (!event.deleteSubscription(param))
952e5aaf047SAppaRao Puli                 {
9534b712a29SEd Tanous                     messages::resourceNotFound(asyncResp->res,
9544b712a29SEd Tanous                                                "EventDestination", param);
955e5aaf047SAppaRao Puli                     return;
956e5aaf047SAppaRao Puli                 }
9574b712a29SEd Tanous                 messages::success(asyncResp->res);
9587e860f15SJohn Edward Broadbent             });
959e5aaf047SAppaRao Puli }
960e5aaf047SAppaRao Puli 
961e5aaf047SAppaRao Puli } // namespace redfish
962