1e5aaf047SAppaRao Puli /*
2e5aaf047SAppaRao Puli // Copyright (c) 2020 Intel Corporation
3e5aaf047SAppaRao Puli //
4e5aaf047SAppaRao Puli // Licensed under the Apache License, Version 2.0 (the "License");
5e5aaf047SAppaRao Puli // you may not use this file except in compliance with the License.
6e5aaf047SAppaRao Puli // You may obtain a copy of the License at
7e5aaf047SAppaRao Puli //
8e5aaf047SAppaRao Puli //      http://www.apache.org/licenses/LICENSE-2.0
9e5aaf047SAppaRao Puli //
10e5aaf047SAppaRao Puli // Unless required by applicable law or agreed to in writing, software
11e5aaf047SAppaRao Puli // distributed under the License is distributed on an "AS IS" BASIS,
12e5aaf047SAppaRao Puli // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13e5aaf047SAppaRao Puli // See the License for the specific language governing permissions and
14e5aaf047SAppaRao Puli // limitations under the License.
15e5aaf047SAppaRao Puli */
16e5aaf047SAppaRao Puli #pragma once
173ccb3adbSEd Tanous #include "app.hpp"
18b52664e2SAppaRao Puli #include "event_service_manager.hpp"
193ccb3adbSEd Tanous #include "http/utility.hpp"
203ccb3adbSEd Tanous #include "logging.hpp"
213ccb3adbSEd Tanous #include "query.hpp"
223ccb3adbSEd Tanous #include "registries/privilege_registry.hpp"
23e5aaf047SAppaRao Puli 
24601c71aeSEd Tanous #include <boost/beast/http/fields.hpp>
25ed398213SEd Tanous 
261e270c5fSPatrick Williams #include <span>
271e270c5fSPatrick Williams 
28e5aaf047SAppaRao Puli namespace redfish
29e5aaf047SAppaRao Puli {
30e5aaf047SAppaRao Puli 
31156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
32156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
33e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
34b304bd79SP Dheeraj Srujan Kumar     "Base", "OpenBMC", "TaskEvent"};
35e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
36e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
37e5aaf047SAppaRao Puli 
38e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
39e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = {
40e56f254cSSunitha Harish     "IBMConfigFile", "Task"};
41e56f254cSSunitha Harish #else
42e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = {
43e56f254cSSunitha Harish     "Task"};
44e56f254cSSunitha Harish #endif
45e56f254cSSunitha Harish 
467e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app)
47e5aaf047SAppaRao Puli {
487e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
49ed398213SEd Tanous         .privileges(redfish::privileges::getEventService)
50002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
51002d39b4SEd Tanous             [&app](const crow::Request& req,
52002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
533ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
5445ca1b86SEd Tanous         {
5545ca1b86SEd Tanous             return;
5645ca1b86SEd Tanous         }
571476687dSEd Tanous 
581476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
591476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
601476687dSEd Tanous             "#EventService.v1_5_0.EventService";
611476687dSEd Tanous         asyncResp->res.jsonValue["Id"] = "EventService";
621476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "Event Service";
63*5e44e3d8SAppaRao Puli         asyncResp->res.jsonValue["ServerSentEventUri"] =
64*5e44e3d8SAppaRao Puli             "/redfish/v1/EventService/SSE";
65*5e44e3d8SAppaRao Puli 
661476687dSEd Tanous         asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
671476687dSEd Tanous             "/redfish/v1/EventService/Subscriptions";
68002d39b4SEd Tanous         asyncResp->res
69002d39b4SEd Tanous             .jsonValue["Actions"]["#EventService.SubmitTestEvent"]["target"] =
701476687dSEd Tanous             "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
71e5aaf047SAppaRao Puli 
7228afb49cSJunLin Chen         const persistent_data::EventServiceConfig eventServiceConfig =
7328afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
7428afb49cSJunLin Chen                 .getEventServiceConfig();
757d1cc387SAppaRao Puli 
767d1cc387SAppaRao Puli         asyncResp->res.jsonValue["Status"]["State"] =
7728afb49cSJunLin Chen             (eventServiceConfig.enabled ? "Enabled" : "Disabled");
78002d39b4SEd Tanous         asyncResp->res.jsonValue["ServiceEnabled"] = eventServiceConfig.enabled;
797e860f15SJohn Edward Broadbent         asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
8028afb49cSJunLin Chen             eventServiceConfig.retryAttempts;
81e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
8228afb49cSJunLin Chen             eventServiceConfig.retryTimeoutInterval;
83002d39b4SEd Tanous         asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
840fda0f12SGeorge Liu         asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
850fda0f12SGeorge Liu         asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
8607941a88SAyushi Smriti 
87613dabeaSEd Tanous         nlohmann::json::object_t supportedSSEFilters;
88613dabeaSEd Tanous         supportedSSEFilters["EventFormatType"] = true;
89613dabeaSEd Tanous         supportedSSEFilters["MessageId"] = true;
90613dabeaSEd Tanous         supportedSSEFilters["MetricReportDefinition"] = true;
91613dabeaSEd Tanous         supportedSSEFilters["RegistryPrefix"] = true;
92613dabeaSEd Tanous         supportedSSEFilters["OriginResource"] = false;
93613dabeaSEd Tanous         supportedSSEFilters["ResourceType"] = false;
9407941a88SAyushi Smriti 
9507941a88SAyushi Smriti         asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
96613dabeaSEd Tanous             std::move(supportedSSEFilters);
977e860f15SJohn Edward Broadbent         });
98e5aaf047SAppaRao Puli 
997e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
100ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
1017e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
10245ca1b86SEd Tanous             [&app](const crow::Request& req,
10345ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1043ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
105e5aaf047SAppaRao Puli         {
10645ca1b86SEd Tanous             return;
10745ca1b86SEd Tanous         }
108e5aaf047SAppaRao Puli         std::optional<bool> serviceEnabled;
109e5aaf047SAppaRao Puli         std::optional<uint32_t> retryAttemps;
110e5aaf047SAppaRao Puli         std::optional<uint32_t> retryInterval;
111e5aaf047SAppaRao Puli 
11215ed6780SWilly Tu         if (!json_util::readJsonPatch(
1137e860f15SJohn Edward Broadbent                 req, asyncResp->res, "ServiceEnabled", serviceEnabled,
1147e860f15SJohn Edward Broadbent                 "DeliveryRetryAttempts", retryAttemps,
1157e860f15SJohn Edward Broadbent                 "DeliveryRetryIntervalSeconds", retryInterval))
116e5aaf047SAppaRao Puli         {
117e5aaf047SAppaRao Puli             return;
118e5aaf047SAppaRao Puli         }
119e5aaf047SAppaRao Puli 
12028afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
12128afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
12228afb49cSJunLin Chen                 .getEventServiceConfig();
1237d1cc387SAppaRao Puli 
124e5aaf047SAppaRao Puli         if (serviceEnabled)
125e5aaf047SAppaRao Puli         {
12628afb49cSJunLin Chen             eventServiceConfig.enabled = *serviceEnabled;
127e5aaf047SAppaRao Puli         }
128e5aaf047SAppaRao Puli 
129e5aaf047SAppaRao Puli         if (retryAttemps)
130e5aaf047SAppaRao Puli         {
131e5aaf047SAppaRao Puli             // Supported range [1-3]
132e5aaf047SAppaRao Puli             if ((*retryAttemps < 1) || (*retryAttemps > 3))
133e5aaf047SAppaRao Puli             {
134e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
135e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryAttemps),
136e5aaf047SAppaRao Puli                     "DeliveryRetryAttempts", "[1-3]");
137e5aaf047SAppaRao Puli             }
138e5aaf047SAppaRao Puli             else
139e5aaf047SAppaRao Puli             {
14028afb49cSJunLin Chen                 eventServiceConfig.retryAttempts = *retryAttemps;
141e5aaf047SAppaRao Puli             }
142e5aaf047SAppaRao Puli         }
143e5aaf047SAppaRao Puli 
144e5aaf047SAppaRao Puli         if (retryInterval)
145e5aaf047SAppaRao Puli         {
14633a32b34SGunnar Mills             // Supported range [5 - 180]
14733a32b34SGunnar Mills             if ((*retryInterval < 5) || (*retryInterval > 180))
148e5aaf047SAppaRao Puli             {
149e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
150e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryInterval),
15133a32b34SGunnar Mills                     "DeliveryRetryIntervalSeconds", "[5-180]");
152e5aaf047SAppaRao Puli             }
153e5aaf047SAppaRao Puli             else
154e5aaf047SAppaRao Puli             {
155002d39b4SEd Tanous                 eventServiceConfig.retryTimeoutInterval = *retryInterval;
156e5aaf047SAppaRao Puli             }
157e5aaf047SAppaRao Puli         }
158e5aaf047SAppaRao Puli 
1597d1cc387SAppaRao Puli         EventServiceManager::getInstance().setEventServiceConfig(
16028afb49cSJunLin Chen             eventServiceConfig);
1617e860f15SJohn Edward Broadbent         });
1620b4bdd93SAppaRao Puli }
1630b4bdd93SAppaRao Puli 
1647e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1650b4bdd93SAppaRao Puli {
1667e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1677e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
168ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1697e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
17045ca1b86SEd Tanous             [&app](const crow::Request& req,
1717e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1723ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
17345ca1b86SEd Tanous         {
17445ca1b86SEd Tanous             return;
17545ca1b86SEd Tanous         }
1766ba8c82eSsunharis_in         if (!EventServiceManager::getInstance().sendTestEventLog())
1776ba8c82eSsunharis_in         {
1786ba8c82eSsunharis_in             messages::serviceDisabled(asyncResp->res,
1796ba8c82eSsunharis_in                                       "/redfish/v1/EventService/");
1806ba8c82eSsunharis_in             return;
1816ba8c82eSsunharis_in         }
1828d1b46d7Szhanghch05         asyncResp->res.result(boost::beast::http::status::no_content);
1837e860f15SJohn Edward Broadbent         });
184e5aaf047SAppaRao Puli }
185e5aaf047SAppaRao Puli 
1867e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
187e5aaf047SAppaRao Puli {
1881ebe3e41SGayathri Leburu     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
189ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
1907e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
19145ca1b86SEd Tanous             [&app](const crow::Request& req,
1927e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1933ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
19445ca1b86SEd Tanous         {
19545ca1b86SEd Tanous             return;
19645ca1b86SEd Tanous         }
1971476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
1981476687dSEd Tanous             "#EventDestinationCollection.EventDestinationCollection";
1991476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
2001476687dSEd Tanous             "/redfish/v1/EventService/Subscriptions";
201002d39b4SEd Tanous         asyncResp->res.jsonValue["Name"] = "Event Destination Collections";
202e5aaf047SAppaRao Puli 
203002d39b4SEd Tanous         nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
204e5aaf047SAppaRao Puli 
205b52664e2SAppaRao Puli         std::vector<std::string> subscripIds =
206b52664e2SAppaRao Puli             EventServiceManager::getInstance().getAllIDs();
207b52664e2SAppaRao Puli         memberArray = nlohmann::json::array();
208002d39b4SEd Tanous         asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
209b52664e2SAppaRao Puli 
210b52664e2SAppaRao Puli         for (const std::string& id : subscripIds)
211e5aaf047SAppaRao Puli         {
2121476687dSEd Tanous             nlohmann::json::object_t member;
21389492a15SPatrick Williams             member["@odata.id"] = "/redfish/v1/EventService/Subscriptions/" +
21489492a15SPatrick Williams                                   id;
215b2ba3072SPatrick Williams             memberArray.emplace_back(std::move(member));
216e5aaf047SAppaRao Puli         }
2177e860f15SJohn Edward Broadbent         });
2187e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
2197eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
220002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
221002d39b4SEd Tanous             [&app](const crow::Request& req,
2227e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2233ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
22445ca1b86SEd Tanous         {
22545ca1b86SEd Tanous             return;
22645ca1b86SEd Tanous         }
227fffb8c1fSEd Tanous         if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
228fffb8c1fSEd Tanous             maxNoOfSubscriptions)
229e5aaf047SAppaRao Puli         {
230e5aaf047SAppaRao Puli             messages::eventSubscriptionLimitExceeded(asyncResp->res);
231e5aaf047SAppaRao Puli             return;
232e5aaf047SAppaRao Puli         }
233e5aaf047SAppaRao Puli         std::string destUrl;
234e5aaf047SAppaRao Puli         std::string protocol;
235e5aaf047SAppaRao Puli         std::optional<std::string> context;
236e5aaf047SAppaRao Puli         std::optional<std::string> subscriptionType;
23723a21a1cSEd Tanous         std::optional<std::string> eventFormatType2;
238e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
239e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> msgIds;
240e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> regPrefixes;
241e56f254cSSunitha Harish         std::optional<std::vector<std::string>> resTypes;
242e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
243144b6318SAppaRao Puli         std::optional<std::vector<nlohmann::json>> mrdJsonArray;
244e5aaf047SAppaRao Puli 
24515ed6780SWilly Tu         if (!json_util::readJsonPatch(
246002d39b4SEd Tanous                 req, asyncResp->res, "Destination", destUrl, "Context", context,
247002d39b4SEd Tanous                 "Protocol", protocol, "SubscriptionType", subscriptionType,
248002d39b4SEd Tanous                 "EventFormatType", eventFormatType2, "HttpHeaders", headers,
249002d39b4SEd Tanous                 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
250002d39b4SEd Tanous                 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
251002d39b4SEd Tanous                 mrdJsonArray, "ResourceTypes", resTypes))
252e5aaf047SAppaRao Puli         {
253e5aaf047SAppaRao Puli             return;
254e5aaf047SAppaRao Puli         }
255e5aaf047SAppaRao Puli 
256600af5f1SAppaRao Puli         // https://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers
257600af5f1SAppaRao Puli         static constexpr const uint16_t maxDestinationSize = 2000;
258600af5f1SAppaRao Puli         if (destUrl.size() > maxDestinationSize)
259600af5f1SAppaRao Puli         {
260600af5f1SAppaRao Puli             messages::stringValueTooLong(asyncResp->res, "Destination",
261600af5f1SAppaRao Puli                                          maxDestinationSize);
262600af5f1SAppaRao Puli             return;
263600af5f1SAppaRao Puli         }
264600af5f1SAppaRao Puli 
265dd28ba82SAppaRao Puli         if (regPrefixes && msgIds)
266dd28ba82SAppaRao Puli         {
26726f6976fSEd Tanous             if (!regPrefixes->empty() && !msgIds->empty())
268dd28ba82SAppaRao Puli             {
269002d39b4SEd Tanous                 messages::propertyValueConflict(asyncResp->res, "MessageIds",
270002d39b4SEd Tanous                                                 "RegistryPrefixes");
271dd28ba82SAppaRao Puli                 return;
272dd28ba82SAppaRao Puli             }
273dd28ba82SAppaRao Puli         }
274dd28ba82SAppaRao Puli 
275eb1c47d3SEd Tanous         std::string host;
276eb1c47d3SEd Tanous         std::string urlProto;
277eb1c47d3SEd Tanous         uint16_t port = 0;
278eb1c47d3SEd Tanous         std::string path;
279eb1c47d3SEd Tanous 
280002d39b4SEd Tanous         if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host, port,
281002d39b4SEd Tanous                                                 path))
282e5aaf047SAppaRao Puli         {
283eb1c47d3SEd Tanous             BMCWEB_LOG_WARNING
284eb1c47d3SEd Tanous                 << "Failed to validate and split destination url";
285e5aaf047SAppaRao Puli             messages::propertyValueFormatError(asyncResp->res, destUrl,
286e5aaf047SAppaRao Puli                                                "Destination");
287e5aaf047SAppaRao Puli             return;
288e5aaf047SAppaRao Puli         }
289b52664e2SAppaRao Puli 
290b52664e2SAppaRao Puli         if (path.empty())
291b52664e2SAppaRao Puli         {
292b52664e2SAppaRao Puli             path = "/";
293b52664e2SAppaRao Puli         }
294f8ca6d79SEd Tanous         std::shared_ptr<Subscription> subValue = std::make_shared<Subscription>(
295f8ca6d79SEd Tanous             host, port, path, urlProto, app.ioContext());
296b52664e2SAppaRao Puli 
297b52664e2SAppaRao Puli         subValue->destinationUrl = destUrl;
298e5aaf047SAppaRao Puli 
299e5aaf047SAppaRao Puli         if (subscriptionType)
300e5aaf047SAppaRao Puli         {
301e5aaf047SAppaRao Puli             if (*subscriptionType != "RedfishEvent")
302e5aaf047SAppaRao Puli             {
303fffb8c1fSEd Tanous                 messages::propertyValueNotInList(
304fffb8c1fSEd Tanous                     asyncResp->res, *subscriptionType, "SubscriptionType");
305e5aaf047SAppaRao Puli                 return;
306e5aaf047SAppaRao Puli             }
307b52664e2SAppaRao Puli             subValue->subscriptionType = *subscriptionType;
308e5aaf047SAppaRao Puli         }
309e5aaf047SAppaRao Puli         else
310e5aaf047SAppaRao Puli         {
311b52664e2SAppaRao Puli             subValue->subscriptionType = "RedfishEvent"; // Default
312e5aaf047SAppaRao Puli         }
313e5aaf047SAppaRao Puli 
314e5aaf047SAppaRao Puli         if (protocol != "Redfish")
315e5aaf047SAppaRao Puli         {
316e5aaf047SAppaRao Puli             messages::propertyValueNotInList(asyncResp->res, protocol,
317e5aaf047SAppaRao Puli                                              "Protocol");
318e5aaf047SAppaRao Puli             return;
319e5aaf047SAppaRao Puli         }
320b52664e2SAppaRao Puli         subValue->protocol = protocol;
321e5aaf047SAppaRao Puli 
32223a21a1cSEd Tanous         if (eventFormatType2)
323e5aaf047SAppaRao Puli         {
324e5aaf047SAppaRao Puli             if (std::find(supportedEvtFormatTypes.begin(),
325e5aaf047SAppaRao Puli                           supportedEvtFormatTypes.end(),
326002d39b4SEd Tanous                           *eventFormatType2) == supportedEvtFormatTypes.end())
327e5aaf047SAppaRao Puli             {
328fffb8c1fSEd Tanous                 messages::propertyValueNotInList(
329fffb8c1fSEd Tanous                     asyncResp->res, *eventFormatType2, "EventFormatType");
330e5aaf047SAppaRao Puli                 return;
331e5aaf047SAppaRao Puli             }
33223a21a1cSEd Tanous             subValue->eventFormatType = *eventFormatType2;
333e5aaf047SAppaRao Puli         }
334e5aaf047SAppaRao Puli         else
335e5aaf047SAppaRao Puli         {
336e5aaf047SAppaRao Puli             // If not specified, use default "Event"
33723a21a1cSEd Tanous             subValue->eventFormatType = "Event";
338e5aaf047SAppaRao Puli         }
339e5aaf047SAppaRao Puli 
340e5aaf047SAppaRao Puli         if (context)
341e5aaf047SAppaRao Puli         {
342600af5f1SAppaRao Puli             // This value is selected aribitrarily.
343600af5f1SAppaRao Puli             constexpr const size_t maxContextSize = 256;
344600af5f1SAppaRao Puli             if (context->size() > maxContextSize)
345600af5f1SAppaRao Puli             {
346600af5f1SAppaRao Puli                 messages::stringValueTooLong(asyncResp->res, "Context",
347600af5f1SAppaRao Puli                                              maxContextSize);
348600af5f1SAppaRao Puli                 return;
349600af5f1SAppaRao Puli             }
350b52664e2SAppaRao Puli             subValue->customText = *context;
351e5aaf047SAppaRao Puli         }
352e5aaf047SAppaRao Puli 
353e5aaf047SAppaRao Puli         if (headers)
354e5aaf047SAppaRao Puli         {
355600af5f1SAppaRao Puli             size_t cumulativeLen = 0;
356600af5f1SAppaRao Puli 
357601c71aeSEd Tanous             for (const nlohmann::json& headerChunk : *headers)
358601c71aeSEd Tanous             {
359600af5f1SAppaRao Puli                 std::string hdr{headerChunk.dump(
360600af5f1SAppaRao Puli                     -1, ' ', true, nlohmann::json::error_handler_t::replace)};
361600af5f1SAppaRao Puli                 cumulativeLen += hdr.length();
362600af5f1SAppaRao Puli 
363600af5f1SAppaRao Puli                 // This value is selected to mirror http_connection.hpp
364600af5f1SAppaRao Puli                 constexpr const uint16_t maxHeaderSizeED = 8096;
365600af5f1SAppaRao Puli                 if (cumulativeLen > maxHeaderSizeED)
366600af5f1SAppaRao Puli                 {
367600af5f1SAppaRao Puli                     messages::arraySizeTooLong(asyncResp->res, "HttpHeaders",
368600af5f1SAppaRao Puli                                                maxHeaderSizeED);
369600af5f1SAppaRao Puli                     return;
370600af5f1SAppaRao Puli                 }
371601c71aeSEd Tanous                 for (const auto& item : headerChunk.items())
372601c71aeSEd Tanous                 {
373601c71aeSEd Tanous                     const std::string* value =
374601c71aeSEd Tanous                         item.value().get_ptr<const std::string*>();
375601c71aeSEd Tanous                     if (value == nullptr)
376601c71aeSEd Tanous                     {
377601c71aeSEd Tanous                         messages::propertyValueFormatError(
378e662eae8SEd Tanous                             asyncResp->res, item.value().dump(2, 1),
379601c71aeSEd Tanous                             "HttpHeaders/" + item.key());
380601c71aeSEd Tanous                         return;
381601c71aeSEd Tanous                     }
382601c71aeSEd Tanous                     subValue->httpHeaders.set(item.key(), *value);
383601c71aeSEd Tanous                 }
384601c71aeSEd Tanous             }
385e5aaf047SAppaRao Puli         }
386e5aaf047SAppaRao Puli 
387e5aaf047SAppaRao Puli         if (regPrefixes)
388e5aaf047SAppaRao Puli         {
389e5aaf047SAppaRao Puli             for (const std::string& it : *regPrefixes)
390e5aaf047SAppaRao Puli             {
391e5aaf047SAppaRao Puli                 if (std::find(supportedRegPrefixes.begin(),
392e5aaf047SAppaRao Puli                               supportedRegPrefixes.end(),
393e5aaf047SAppaRao Puli                               it) == supportedRegPrefixes.end())
394e5aaf047SAppaRao Puli                 {
395fffb8c1fSEd Tanous                     messages::propertyValueNotInList(asyncResp->res, it,
396fffb8c1fSEd Tanous                                                      "RegistryPrefixes");
397e5aaf047SAppaRao Puli                     return;
398e5aaf047SAppaRao Puli                 }
399e5aaf047SAppaRao Puli             }
400b52664e2SAppaRao Puli             subValue->registryPrefixes = *regPrefixes;
401e5aaf047SAppaRao Puli         }
402e5aaf047SAppaRao Puli 
403e56f254cSSunitha Harish         if (resTypes)
404e56f254cSSunitha Harish         {
405e56f254cSSunitha Harish             for (const std::string& it : *resTypes)
406e56f254cSSunitha Harish             {
407e56f254cSSunitha Harish                 if (std::find(supportedResourceTypes.begin(),
408e56f254cSSunitha Harish                               supportedResourceTypes.end(),
409e56f254cSSunitha Harish                               it) == supportedResourceTypes.end())
410e56f254cSSunitha Harish                 {
411e56f254cSSunitha Harish                     messages::propertyValueNotInList(asyncResp->res, it,
412e56f254cSSunitha Harish                                                      "ResourceTypes");
413e56f254cSSunitha Harish                     return;
414e56f254cSSunitha Harish                 }
415e56f254cSSunitha Harish             }
416e56f254cSSunitha Harish             subValue->resourceTypes = *resTypes;
417e56f254cSSunitha Harish         }
418e56f254cSSunitha Harish 
419e5aaf047SAppaRao Puli         if (msgIds)
420e5aaf047SAppaRao Puli         {
421b304bd79SP Dheeraj Srujan Kumar             std::vector<std::string> registryPrefix;
422b304bd79SP Dheeraj Srujan Kumar 
4237e860f15SJohn Edward Broadbent             // If no registry prefixes are mentioned, consider all
4247e860f15SJohn Edward Broadbent             // supported prefixes
425b304bd79SP Dheeraj Srujan Kumar             if (subValue->registryPrefixes.empty())
426b304bd79SP Dheeraj Srujan Kumar             {
427b304bd79SP Dheeraj Srujan Kumar                 registryPrefix.assign(supportedRegPrefixes.begin(),
428b304bd79SP Dheeraj Srujan Kumar                                       supportedRegPrefixes.end());
429b304bd79SP Dheeraj Srujan Kumar             }
430b304bd79SP Dheeraj Srujan Kumar             else
431b304bd79SP Dheeraj Srujan Kumar             {
432b304bd79SP Dheeraj Srujan Kumar                 registryPrefix = subValue->registryPrefixes;
433b304bd79SP Dheeraj Srujan Kumar             }
434b304bd79SP Dheeraj Srujan Kumar 
435b304bd79SP Dheeraj Srujan Kumar             for (const std::string& id : *msgIds)
436b304bd79SP Dheeraj Srujan Kumar             {
437b304bd79SP Dheeraj Srujan Kumar                 bool validId = false;
438b304bd79SP Dheeraj Srujan Kumar 
439b304bd79SP Dheeraj Srujan Kumar                 // Check for Message ID in each of the selected Registry
440b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& it : registryPrefix)
441b304bd79SP Dheeraj Srujan Kumar                 {
442fffb8c1fSEd Tanous                     const std::span<const redfish::registries::MessageEntry>
443fffb8c1fSEd Tanous                         registry =
444fffb8c1fSEd Tanous                             redfish::registries::getRegistryFromPrefix(it);
445b304bd79SP Dheeraj Srujan Kumar 
446b304bd79SP Dheeraj Srujan Kumar                     if (std::any_of(
44726702d01SEd Tanous                             registry.begin(), registry.end(),
448fffb8c1fSEd Tanous                             [&id](const redfish::registries::MessageEntry&
449fffb8c1fSEd Tanous                                       messageEntry) {
45055f79e6fSEd Tanous                         return id == messageEntry.first;
451b304bd79SP Dheeraj Srujan Kumar                             }))
452b304bd79SP Dheeraj Srujan Kumar                     {
453b304bd79SP Dheeraj Srujan Kumar                         validId = true;
454b304bd79SP Dheeraj Srujan Kumar                         break;
455b304bd79SP Dheeraj Srujan Kumar                     }
456b304bd79SP Dheeraj Srujan Kumar                 }
457b304bd79SP Dheeraj Srujan Kumar 
458b304bd79SP Dheeraj Srujan Kumar                 if (!validId)
459b304bd79SP Dheeraj Srujan Kumar                 {
460b304bd79SP Dheeraj Srujan Kumar                     messages::propertyValueNotInList(asyncResp->res, id,
461b304bd79SP Dheeraj Srujan Kumar                                                      "MessageIds");
462b304bd79SP Dheeraj Srujan Kumar                     return;
463b304bd79SP Dheeraj Srujan Kumar                 }
464b304bd79SP Dheeraj Srujan Kumar             }
465b304bd79SP Dheeraj Srujan Kumar 
466b52664e2SAppaRao Puli             subValue->registryMsgIds = *msgIds;
467e5aaf047SAppaRao Puli         }
468e5aaf047SAppaRao Puli 
469e5aaf047SAppaRao Puli         if (retryPolicy)
470e5aaf047SAppaRao Puli         {
471e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
472e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
473e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
474e5aaf047SAppaRao Puli             {
475002d39b4SEd Tanous                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
476002d39b4SEd Tanous                                                  "DeliveryRetryPolicy");
477e5aaf047SAppaRao Puli                 return;
478e5aaf047SAppaRao Puli             }
479b52664e2SAppaRao Puli             subValue->retryPolicy = *retryPolicy;
480e5aaf047SAppaRao Puli         }
481e5aaf047SAppaRao Puli         else
482e5aaf047SAppaRao Puli         {
483e5aaf047SAppaRao Puli             // Default "TerminateAfterRetries"
484b52664e2SAppaRao Puli             subValue->retryPolicy = "TerminateAfterRetries";
485e5aaf047SAppaRao Puli         }
486e5aaf047SAppaRao Puli 
487144b6318SAppaRao Puli         if (mrdJsonArray)
488156d6b00SAppaRao Puli         {
489144b6318SAppaRao Puli             for (nlohmann::json& mrdObj : *mrdJsonArray)
490144b6318SAppaRao Puli             {
491144b6318SAppaRao Puli                 std::string mrdUri;
492ea2e6eecSWilly Tu 
493002d39b4SEd Tanous                 if (!json_util::readJson(mrdObj, asyncResp->res, "@odata.id",
494002d39b4SEd Tanous                                          mrdUri))
495ea2e6eecSWilly Tu 
496144b6318SAppaRao Puli                 {
497144b6318SAppaRao Puli                     return;
498144b6318SAppaRao Puli                 }
499ea2e6eecSWilly Tu                 subValue->metricReportDefinitions.emplace_back(mrdUri);
500144b6318SAppaRao Puli             }
501156d6b00SAppaRao Puli         }
502156d6b00SAppaRao Puli 
503b52664e2SAppaRao Puli         std::string id =
504fffb8c1fSEd Tanous             EventServiceManager::getInstance().addSubscription(subValue);
505b52664e2SAppaRao Puli         if (id.empty())
506e5aaf047SAppaRao Puli         {
507e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
508e5aaf047SAppaRao Puli             return;
509e5aaf047SAppaRao Puli         }
510e5aaf047SAppaRao Puli 
511e5aaf047SAppaRao Puli         messages::created(asyncResp->res);
512e5aaf047SAppaRao Puli         asyncResp->res.addHeader(
513e5aaf047SAppaRao Puli             "Location", "/redfish/v1/EventService/Subscriptions/" + id);
5147e860f15SJohn Edward Broadbent         });
515e5aaf047SAppaRao Puli }
516e5aaf047SAppaRao Puli 
5177e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
518e5aaf047SAppaRao Puli {
5199d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
520ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
5217e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
52245ca1b86SEd Tanous             [&app](const crow::Request& req,
5237e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5247e860f15SJohn Edward Broadbent                    const std::string& param) {
5253ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
52645ca1b86SEd Tanous         {
52745ca1b86SEd Tanous             return;
52845ca1b86SEd Tanous         }
529b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
5307e860f15SJohn Edward Broadbent             EventServiceManager::getInstance().getSubscription(param);
531b52664e2SAppaRao Puli         if (subValue == nullptr)
532e5aaf047SAppaRao Puli         {
533002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::not_found);
534e5aaf047SAppaRao Puli             return;
535e5aaf047SAppaRao Puli         }
5367e860f15SJohn Edward Broadbent         const std::string& id = param;
537e5aaf047SAppaRao Puli 
5381476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
5391476687dSEd Tanous             "#EventDestination.v1_7_0.EventDestination";
5401476687dSEd Tanous         asyncResp->res.jsonValue["Protocol"] = "Redfish";
541e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["@odata.id"] =
542e5aaf047SAppaRao Puli             "/redfish/v1/EventService/Subscriptions/" + id;
543e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Id"] = id;
544e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
545002d39b4SEd Tanous         asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
546b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Context"] = subValue->customText;
547e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["SubscriptionType"] =
548b52664e2SAppaRao Puli             subValue->subscriptionType;
549002d39b4SEd Tanous         asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array();
550002d39b4SEd Tanous         asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
551e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["RegistryPrefixes"] =
552b52664e2SAppaRao Puli             subValue->registryPrefixes;
553002d39b4SEd Tanous         asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes;
554e56f254cSSunitha Harish 
555002d39b4SEd Tanous         asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
556002d39b4SEd Tanous         asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
557144b6318SAppaRao Puli 
5581476687dSEd Tanous         nlohmann::json::array_t mrdJsonArray;
559144b6318SAppaRao Puli         for (const auto& mdrUri : subValue->metricReportDefinitions)
560144b6318SAppaRao Puli         {
5611476687dSEd Tanous             nlohmann::json::object_t mdr;
5621476687dSEd Tanous             mdr["@odata.id"] = mdrUri;
5631476687dSEd Tanous             mrdJsonArray.emplace_back(std::move(mdr));
564144b6318SAppaRao Puli         }
565002d39b4SEd Tanous         asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray;
5667e860f15SJohn Edward Broadbent         });
5679d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
568ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
569ed398213SEd Tanous         // ConfigureSelf
5707eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
571ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
572432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
5737e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
57445ca1b86SEd Tanous             [&app](const crow::Request& req,
5757e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5767e860f15SJohn Edward Broadbent                    const std::string& param) {
5773ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
57845ca1b86SEd Tanous         {
57945ca1b86SEd Tanous             return;
58045ca1b86SEd Tanous         }
581b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
5827e860f15SJohn Edward Broadbent             EventServiceManager::getInstance().getSubscription(param);
583b52664e2SAppaRao Puli         if (subValue == nullptr)
584e5aaf047SAppaRao Puli         {
585002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::not_found);
586e5aaf047SAppaRao Puli             return;
587e5aaf047SAppaRao Puli         }
588e5aaf047SAppaRao Puli 
589e5aaf047SAppaRao Puli         std::optional<std::string> context;
590e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
591e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
592e5aaf047SAppaRao Puli 
593002d39b4SEd Tanous         if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context,
594002d39b4SEd Tanous                                       "DeliveryRetryPolicy", retryPolicy,
595002d39b4SEd Tanous                                       "HttpHeaders", headers))
596e5aaf047SAppaRao Puli         {
597e5aaf047SAppaRao Puli             return;
598e5aaf047SAppaRao Puli         }
599e5aaf047SAppaRao Puli 
600e5aaf047SAppaRao Puli         if (context)
601e5aaf047SAppaRao Puli         {
602b52664e2SAppaRao Puli             subValue->customText = *context;
603e5aaf047SAppaRao Puli         }
604e5aaf047SAppaRao Puli 
605e5aaf047SAppaRao Puli         if (headers)
606e5aaf047SAppaRao Puli         {
607601c71aeSEd Tanous             boost::beast::http::fields fields;
608601c71aeSEd Tanous             for (const nlohmann::json& headerChunk : *headers)
609601c71aeSEd Tanous             {
61062bafc01SPatrick Williams                 for (const auto& it : headerChunk.items())
611601c71aeSEd Tanous                 {
612601c71aeSEd Tanous                     const std::string* value =
613601c71aeSEd Tanous                         it.value().get_ptr<const std::string*>();
614601c71aeSEd Tanous                     if (value == nullptr)
615601c71aeSEd Tanous                     {
616601c71aeSEd Tanous                         messages::propertyValueFormatError(
617002d39b4SEd Tanous                             asyncResp->res, it.value().dump(2, ' ', true),
618601c71aeSEd Tanous                             "HttpHeaders/" + it.key());
619601c71aeSEd Tanous                         return;
620601c71aeSEd Tanous                     }
621601c71aeSEd Tanous                     fields.set(it.key(), *value);
622601c71aeSEd Tanous                 }
623601c71aeSEd Tanous             }
624601c71aeSEd Tanous             subValue->httpHeaders = fields;
625e5aaf047SAppaRao Puli         }
626e5aaf047SAppaRao Puli 
627e5aaf047SAppaRao Puli         if (retryPolicy)
628e5aaf047SAppaRao Puli         {
629e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
630e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
631e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
632e5aaf047SAppaRao Puli             {
633002d39b4SEd Tanous                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
634e5aaf047SAppaRao Puli                                                  "DeliveryRetryPolicy");
635e5aaf047SAppaRao Puli                 return;
636e5aaf047SAppaRao Puli             }
637b52664e2SAppaRao Puli             subValue->retryPolicy = *retryPolicy;
638e5aaf047SAppaRao Puli         }
639e5aaf047SAppaRao Puli 
640b52664e2SAppaRao Puli         EventServiceManager::getInstance().updateSubscriptionData();
6417e860f15SJohn Edward Broadbent         });
6429d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
643ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
644ed398213SEd Tanous         // ConfigureSelf
6457eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
646ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
647432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
6487e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
64945ca1b86SEd Tanous             [&app](const crow::Request& req,
6507e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6517e860f15SJohn Edward Broadbent                    const std::string& param) {
6523ba00073SCarson Labrado         if (!redfish::setUpRedfishRoute(app, req, asyncResp))
65345ca1b86SEd Tanous         {
65445ca1b86SEd Tanous             return;
65545ca1b86SEd Tanous         }
656002d39b4SEd Tanous         if (!EventServiceManager::getInstance().isSubscriptionExist(param))
657e5aaf047SAppaRao Puli         {
658002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::not_found);
659e5aaf047SAppaRao Puli             return;
660e5aaf047SAppaRao Puli         }
6617e860f15SJohn Edward Broadbent         EventServiceManager::getInstance().deleteSubscription(param);
6627e860f15SJohn Edward Broadbent         });
663e5aaf047SAppaRao Puli }
664e5aaf047SAppaRao Puli 
665e5aaf047SAppaRao Puli } // namespace redfish
666