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
17b52664e2SAppaRao Puli #include "event_service_manager.hpp"
18e5aaf047SAppaRao Puli 
197e860f15SJohn Edward Broadbent #include <app.hpp>
20601c71aeSEd Tanous #include <boost/beast/http/fields.hpp>
21eb1c47d3SEd Tanous #include <http/utility.hpp>
22eb1c47d3SEd Tanous #include <logging.hpp>
2345ca1b86SEd Tanous #include <query.hpp>
24ed398213SEd Tanous #include <registries/privilege_registry.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 
46e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
47e5aaf047SAppaRao Puli 
487e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app)
49e5aaf047SAppaRao Puli {
507e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
51ed398213SEd Tanous         .privileges(redfish::privileges::getEventService)
52*002d39b4SEd Tanous         .methods(boost::beast::http::verb::get)(
53*002d39b4SEd Tanous             [&app](const crow::Request& req,
54*002d39b4SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
5545ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
5645ca1b86SEd Tanous         {
5745ca1b86SEd Tanous             return;
5845ca1b86SEd Tanous         }
591476687dSEd Tanous 
601476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] = "/redfish/v1/EventService";
611476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
621476687dSEd Tanous             "#EventService.v1_5_0.EventService";
631476687dSEd Tanous         asyncResp->res.jsonValue["Id"] = "EventService";
641476687dSEd Tanous         asyncResp->res.jsonValue["Name"] = "Event Service";
651476687dSEd Tanous         asyncResp->res.jsonValue["Subscriptions"]["@odata.id"] =
661476687dSEd Tanous             "/redfish/v1/EventService/Subscriptions";
67*002d39b4SEd Tanous         asyncResp->res
68*002d39b4SEd Tanous             .jsonValue["Actions"]["#EventService.SubmitTestEvent"]["target"] =
691476687dSEd Tanous             "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent";
70e5aaf047SAppaRao Puli 
7128afb49cSJunLin Chen         const persistent_data::EventServiceConfig eventServiceConfig =
7228afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
7328afb49cSJunLin Chen                 .getEventServiceConfig();
747d1cc387SAppaRao Puli 
757d1cc387SAppaRao Puli         asyncResp->res.jsonValue["Status"]["State"] =
7628afb49cSJunLin Chen             (eventServiceConfig.enabled ? "Enabled" : "Disabled");
77*002d39b4SEd Tanous         asyncResp->res.jsonValue["ServiceEnabled"] = eventServiceConfig.enabled;
787e860f15SJohn Edward Broadbent         asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
7928afb49cSJunLin Chen             eventServiceConfig.retryAttempts;
80e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
8128afb49cSJunLin Chen             eventServiceConfig.retryTimeoutInterval;
82*002d39b4SEd Tanous         asyncResp->res.jsonValue["EventFormatTypes"] = supportedEvtFormatTypes;
830fda0f12SGeorge Liu         asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
840fda0f12SGeorge Liu         asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
8507941a88SAyushi Smriti 
8607941a88SAyushi Smriti         nlohmann::json supportedSSEFilters = {
8707941a88SAyushi Smriti             {"EventFormatType", true},        {"MessageId", true},
8807941a88SAyushi Smriti             {"MetricReportDefinition", true}, {"RegistryPrefix", true},
8907941a88SAyushi Smriti             {"OriginResource", false},        {"ResourceType", false}};
9007941a88SAyushi Smriti 
9107941a88SAyushi Smriti         asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
9207941a88SAyushi Smriti             supportedSSEFilters;
937e860f15SJohn Edward Broadbent         });
94e5aaf047SAppaRao Puli 
957e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
96ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
977e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
9845ca1b86SEd Tanous             [&app](const crow::Request& req,
9945ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
10045ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
101e5aaf047SAppaRao Puli         {
10245ca1b86SEd Tanous             return;
10345ca1b86SEd Tanous         }
104e5aaf047SAppaRao Puli         std::optional<bool> serviceEnabled;
105e5aaf047SAppaRao Puli         std::optional<uint32_t> retryAttemps;
106e5aaf047SAppaRao Puli         std::optional<uint32_t> retryInterval;
107e5aaf047SAppaRao Puli 
10815ed6780SWilly Tu         if (!json_util::readJsonPatch(
1097e860f15SJohn Edward Broadbent                 req, asyncResp->res, "ServiceEnabled", serviceEnabled,
1107e860f15SJohn Edward Broadbent                 "DeliveryRetryAttempts", retryAttemps,
1117e860f15SJohn Edward Broadbent                 "DeliveryRetryIntervalSeconds", retryInterval))
112e5aaf047SAppaRao Puli         {
113e5aaf047SAppaRao Puli             return;
114e5aaf047SAppaRao Puli         }
115e5aaf047SAppaRao Puli 
11628afb49cSJunLin Chen         persistent_data::EventServiceConfig eventServiceConfig =
11728afb49cSJunLin Chen             persistent_data::EventServiceStore::getInstance()
11828afb49cSJunLin Chen                 .getEventServiceConfig();
1197d1cc387SAppaRao Puli 
120e5aaf047SAppaRao Puli         if (serviceEnabled)
121e5aaf047SAppaRao Puli         {
12228afb49cSJunLin Chen             eventServiceConfig.enabled = *serviceEnabled;
123e5aaf047SAppaRao Puli         }
124e5aaf047SAppaRao Puli 
125e5aaf047SAppaRao Puli         if (retryAttemps)
126e5aaf047SAppaRao Puli         {
127e5aaf047SAppaRao Puli             // Supported range [1-3]
128e5aaf047SAppaRao Puli             if ((*retryAttemps < 1) || (*retryAttemps > 3))
129e5aaf047SAppaRao Puli             {
130e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
131e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryAttemps),
132e5aaf047SAppaRao Puli                     "DeliveryRetryAttempts", "[1-3]");
133e5aaf047SAppaRao Puli             }
134e5aaf047SAppaRao Puli             else
135e5aaf047SAppaRao Puli             {
13628afb49cSJunLin Chen                 eventServiceConfig.retryAttempts = *retryAttemps;
137e5aaf047SAppaRao Puli             }
138e5aaf047SAppaRao Puli         }
139e5aaf047SAppaRao Puli 
140e5aaf047SAppaRao Puli         if (retryInterval)
141e5aaf047SAppaRao Puli         {
142e5aaf047SAppaRao Puli             // Supported range [30 - 180]
143e5aaf047SAppaRao Puli             if ((*retryInterval < 30) || (*retryInterval > 180))
144e5aaf047SAppaRao Puli             {
145e5aaf047SAppaRao Puli                 messages::queryParameterOutOfRange(
146e5aaf047SAppaRao Puli                     asyncResp->res, std::to_string(*retryInterval),
147e5aaf047SAppaRao Puli                     "DeliveryRetryIntervalSeconds", "[30-180]");
148e5aaf047SAppaRao Puli             }
149e5aaf047SAppaRao Puli             else
150e5aaf047SAppaRao Puli             {
151*002d39b4SEd Tanous                 eventServiceConfig.retryTimeoutInterval = *retryInterval;
152e5aaf047SAppaRao Puli             }
153e5aaf047SAppaRao Puli         }
154e5aaf047SAppaRao Puli 
1557d1cc387SAppaRao Puli         EventServiceManager::getInstance().setEventServiceConfig(
15628afb49cSJunLin Chen             eventServiceConfig);
1577e860f15SJohn Edward Broadbent         });
1580b4bdd93SAppaRao Puli }
1590b4bdd93SAppaRao Puli 
1607e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1610b4bdd93SAppaRao Puli {
1627e860f15SJohn Edward Broadbent 
1637e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1647e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
165ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1667e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
16745ca1b86SEd Tanous             [&app](const crow::Request& req,
1687e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
16945ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
17045ca1b86SEd Tanous         {
17145ca1b86SEd Tanous             return;
17245ca1b86SEd Tanous         }
1736ba8c82eSsunharis_in         if (!EventServiceManager::getInstance().sendTestEventLog())
1746ba8c82eSsunharis_in         {
1756ba8c82eSsunharis_in             messages::serviceDisabled(asyncResp->res,
1766ba8c82eSsunharis_in                                       "/redfish/v1/EventService/");
1776ba8c82eSsunharis_in             return;
1786ba8c82eSsunharis_in         }
1798d1b46d7Szhanghch05         asyncResp->res.result(boost::beast::http::status::no_content);
1807e860f15SJohn Edward Broadbent         });
181e5aaf047SAppaRao Puli }
182e5aaf047SAppaRao Puli 
1837e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
184e5aaf047SAppaRao Puli {
1851ebe3e41SGayathri Leburu     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
186ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
1877e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
18845ca1b86SEd Tanous             [&app](const crow::Request& req,
1897e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
19045ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
19145ca1b86SEd Tanous         {
19245ca1b86SEd Tanous             return;
19345ca1b86SEd Tanous         }
1941476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
1951476687dSEd Tanous             "#EventDestinationCollection.EventDestinationCollection";
1961476687dSEd Tanous         asyncResp->res.jsonValue["@odata.id"] =
1971476687dSEd Tanous             "/redfish/v1/EventService/Subscriptions";
198*002d39b4SEd Tanous         asyncResp->res.jsonValue["Name"] = "Event Destination Collections";
199e5aaf047SAppaRao Puli 
200*002d39b4SEd Tanous         nlohmann::json& memberArray = asyncResp->res.jsonValue["Members"];
201e5aaf047SAppaRao Puli 
202b52664e2SAppaRao Puli         std::vector<std::string> subscripIds =
203b52664e2SAppaRao Puli             EventServiceManager::getInstance().getAllIDs();
204b52664e2SAppaRao Puli         memberArray = nlohmann::json::array();
205*002d39b4SEd Tanous         asyncResp->res.jsonValue["Members@odata.count"] = subscripIds.size();
206b52664e2SAppaRao Puli 
207b52664e2SAppaRao Puli         for (const std::string& id : subscripIds)
208e5aaf047SAppaRao Puli         {
2091476687dSEd Tanous             nlohmann::json::object_t member;
2101476687dSEd Tanous             member["@odata.id"] =
2111476687dSEd Tanous                 "/redfish/v1/EventService/Subscriptions/" + id;
2121476687dSEd Tanous             memberArray.push_back(std::move(member));
213e5aaf047SAppaRao Puli         }
2147e860f15SJohn Edward Broadbent         });
2157e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
2167eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
217*002d39b4SEd Tanous         .methods(boost::beast::http::verb::post)(
218*002d39b4SEd Tanous             [&app](const crow::Request& req,
2197e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
22045ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
22145ca1b86SEd Tanous         {
22245ca1b86SEd Tanous             return;
22345ca1b86SEd Tanous         }
224fffb8c1fSEd Tanous         if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
225fffb8c1fSEd Tanous             maxNoOfSubscriptions)
226e5aaf047SAppaRao Puli         {
227e5aaf047SAppaRao Puli             messages::eventSubscriptionLimitExceeded(asyncResp->res);
228e5aaf047SAppaRao Puli             return;
229e5aaf047SAppaRao Puli         }
230e5aaf047SAppaRao Puli         std::string destUrl;
231e5aaf047SAppaRao Puli         std::string protocol;
232e5aaf047SAppaRao Puli         std::optional<std::string> context;
233e5aaf047SAppaRao Puli         std::optional<std::string> subscriptionType;
23423a21a1cSEd Tanous         std::optional<std::string> eventFormatType2;
235e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
236e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> msgIds;
237e5aaf047SAppaRao Puli         std::optional<std::vector<std::string>> regPrefixes;
238e56f254cSSunitha Harish         std::optional<std::vector<std::string>> resTypes;
239e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
240144b6318SAppaRao Puli         std::optional<std::vector<nlohmann::json>> mrdJsonArray;
241e5aaf047SAppaRao Puli 
24215ed6780SWilly Tu         if (!json_util::readJsonPatch(
243*002d39b4SEd Tanous                 req, asyncResp->res, "Destination", destUrl, "Context", context,
244*002d39b4SEd Tanous                 "Protocol", protocol, "SubscriptionType", subscriptionType,
245*002d39b4SEd Tanous                 "EventFormatType", eventFormatType2, "HttpHeaders", headers,
246*002d39b4SEd Tanous                 "RegistryPrefixes", regPrefixes, "MessageIds", msgIds,
247*002d39b4SEd Tanous                 "DeliveryRetryPolicy", retryPolicy, "MetricReportDefinitions",
248*002d39b4SEd Tanous                 mrdJsonArray, "ResourceTypes", resTypes))
249e5aaf047SAppaRao Puli         {
250e5aaf047SAppaRao Puli             return;
251e5aaf047SAppaRao Puli         }
252e5aaf047SAppaRao Puli 
253dd28ba82SAppaRao Puli         if (regPrefixes && msgIds)
254dd28ba82SAppaRao Puli         {
25526f6976fSEd Tanous             if (!regPrefixes->empty() && !msgIds->empty())
256dd28ba82SAppaRao Puli             {
257*002d39b4SEd Tanous                 messages::propertyValueConflict(asyncResp->res, "MessageIds",
258*002d39b4SEd Tanous                                                 "RegistryPrefixes");
259dd28ba82SAppaRao Puli                 return;
260dd28ba82SAppaRao Puli             }
261dd28ba82SAppaRao Puli         }
262dd28ba82SAppaRao Puli 
263eb1c47d3SEd Tanous         std::string host;
264eb1c47d3SEd Tanous         std::string urlProto;
265eb1c47d3SEd Tanous         uint16_t port = 0;
266eb1c47d3SEd Tanous         std::string path;
267eb1c47d3SEd Tanous 
268*002d39b4SEd Tanous         if (!crow::utility::validateAndSplitUrl(destUrl, urlProto, host, port,
269*002d39b4SEd Tanous                                                 path))
270e5aaf047SAppaRao Puli         {
271eb1c47d3SEd Tanous             BMCWEB_LOG_WARNING
272eb1c47d3SEd Tanous                 << "Failed to validate and split destination url";
273e5aaf047SAppaRao Puli             messages::propertyValueFormatError(asyncResp->res, destUrl,
274e5aaf047SAppaRao Puli                                                "Destination");
275e5aaf047SAppaRao Puli             return;
276e5aaf047SAppaRao Puli         }
277b52664e2SAppaRao Puli 
278b52664e2SAppaRao Puli         if (path.empty())
279b52664e2SAppaRao Puli         {
280b52664e2SAppaRao Puli             path = "/";
281b52664e2SAppaRao Puli         }
282b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
283eb1c47d3SEd Tanous             std::make_shared<Subscription>(host, port, path, urlProto);
284b52664e2SAppaRao Puli 
285b52664e2SAppaRao Puli         subValue->destinationUrl = destUrl;
286e5aaf047SAppaRao Puli 
287e5aaf047SAppaRao Puli         if (subscriptionType)
288e5aaf047SAppaRao Puli         {
289e5aaf047SAppaRao Puli             if (*subscriptionType != "RedfishEvent")
290e5aaf047SAppaRao Puli             {
291fffb8c1fSEd Tanous                 messages::propertyValueNotInList(
292fffb8c1fSEd Tanous                     asyncResp->res, *subscriptionType, "SubscriptionType");
293e5aaf047SAppaRao Puli                 return;
294e5aaf047SAppaRao Puli             }
295b52664e2SAppaRao Puli             subValue->subscriptionType = *subscriptionType;
296e5aaf047SAppaRao Puli         }
297e5aaf047SAppaRao Puli         else
298e5aaf047SAppaRao Puli         {
299b52664e2SAppaRao Puli             subValue->subscriptionType = "RedfishEvent"; // Default
300e5aaf047SAppaRao Puli         }
301e5aaf047SAppaRao Puli 
302e5aaf047SAppaRao Puli         if (protocol != "Redfish")
303e5aaf047SAppaRao Puli         {
304e5aaf047SAppaRao Puli             messages::propertyValueNotInList(asyncResp->res, protocol,
305e5aaf047SAppaRao Puli                                              "Protocol");
306e5aaf047SAppaRao Puli             return;
307e5aaf047SAppaRao Puli         }
308b52664e2SAppaRao Puli         subValue->protocol = protocol;
309e5aaf047SAppaRao Puli 
31023a21a1cSEd Tanous         if (eventFormatType2)
311e5aaf047SAppaRao Puli         {
312e5aaf047SAppaRao Puli             if (std::find(supportedEvtFormatTypes.begin(),
313e5aaf047SAppaRao Puli                           supportedEvtFormatTypes.end(),
314*002d39b4SEd Tanous                           *eventFormatType2) == supportedEvtFormatTypes.end())
315e5aaf047SAppaRao Puli             {
316fffb8c1fSEd Tanous                 messages::propertyValueNotInList(
317fffb8c1fSEd Tanous                     asyncResp->res, *eventFormatType2, "EventFormatType");
318e5aaf047SAppaRao Puli                 return;
319e5aaf047SAppaRao Puli             }
32023a21a1cSEd Tanous             subValue->eventFormatType = *eventFormatType2;
321e5aaf047SAppaRao Puli         }
322e5aaf047SAppaRao Puli         else
323e5aaf047SAppaRao Puli         {
324e5aaf047SAppaRao Puli             // If not specified, use default "Event"
32523a21a1cSEd Tanous             subValue->eventFormatType = "Event";
326e5aaf047SAppaRao Puli         }
327e5aaf047SAppaRao Puli 
328e5aaf047SAppaRao Puli         if (context)
329e5aaf047SAppaRao Puli         {
330b52664e2SAppaRao Puli             subValue->customText = *context;
331e5aaf047SAppaRao Puli         }
332e5aaf047SAppaRao Puli 
333e5aaf047SAppaRao Puli         if (headers)
334e5aaf047SAppaRao Puli         {
335601c71aeSEd Tanous             for (const nlohmann::json& headerChunk : *headers)
336601c71aeSEd Tanous             {
337601c71aeSEd Tanous                 for (const auto& item : headerChunk.items())
338601c71aeSEd Tanous                 {
339601c71aeSEd Tanous                     const std::string* value =
340601c71aeSEd Tanous                         item.value().get_ptr<const std::string*>();
341601c71aeSEd Tanous                     if (value == nullptr)
342601c71aeSEd Tanous                     {
343601c71aeSEd Tanous                         messages::propertyValueFormatError(
344e662eae8SEd Tanous                             asyncResp->res, item.value().dump(2, 1),
345601c71aeSEd Tanous                             "HttpHeaders/" + item.key());
346601c71aeSEd Tanous                         return;
347601c71aeSEd Tanous                     }
348601c71aeSEd Tanous                     subValue->httpHeaders.set(item.key(), *value);
349601c71aeSEd Tanous                 }
350601c71aeSEd Tanous             }
351e5aaf047SAppaRao Puli         }
352e5aaf047SAppaRao Puli 
353e5aaf047SAppaRao Puli         if (regPrefixes)
354e5aaf047SAppaRao Puli         {
355e5aaf047SAppaRao Puli             for (const std::string& it : *regPrefixes)
356e5aaf047SAppaRao Puli             {
357e5aaf047SAppaRao Puli                 if (std::find(supportedRegPrefixes.begin(),
358e5aaf047SAppaRao Puli                               supportedRegPrefixes.end(),
359e5aaf047SAppaRao Puli                               it) == supportedRegPrefixes.end())
360e5aaf047SAppaRao Puli                 {
361fffb8c1fSEd Tanous                     messages::propertyValueNotInList(asyncResp->res, it,
362fffb8c1fSEd Tanous                                                      "RegistryPrefixes");
363e5aaf047SAppaRao Puli                     return;
364e5aaf047SAppaRao Puli                 }
365e5aaf047SAppaRao Puli             }
366b52664e2SAppaRao Puli             subValue->registryPrefixes = *regPrefixes;
367e5aaf047SAppaRao Puli         }
368e5aaf047SAppaRao Puli 
369e56f254cSSunitha Harish         if (resTypes)
370e56f254cSSunitha Harish         {
371e56f254cSSunitha Harish             for (const std::string& it : *resTypes)
372e56f254cSSunitha Harish             {
373e56f254cSSunitha Harish                 if (std::find(supportedResourceTypes.begin(),
374e56f254cSSunitha Harish                               supportedResourceTypes.end(),
375e56f254cSSunitha Harish                               it) == supportedResourceTypes.end())
376e56f254cSSunitha Harish                 {
377e56f254cSSunitha Harish                     messages::propertyValueNotInList(asyncResp->res, it,
378e56f254cSSunitha Harish                                                      "ResourceTypes");
379e56f254cSSunitha Harish                     return;
380e56f254cSSunitha Harish                 }
381e56f254cSSunitha Harish             }
382e56f254cSSunitha Harish             subValue->resourceTypes = *resTypes;
383e56f254cSSunitha Harish         }
384e56f254cSSunitha Harish 
385e5aaf047SAppaRao Puli         if (msgIds)
386e5aaf047SAppaRao Puli         {
387b304bd79SP Dheeraj Srujan Kumar             std::vector<std::string> registryPrefix;
388b304bd79SP Dheeraj Srujan Kumar 
3897e860f15SJohn Edward Broadbent             // If no registry prefixes are mentioned, consider all
3907e860f15SJohn Edward Broadbent             // supported prefixes
391b304bd79SP Dheeraj Srujan Kumar             if (subValue->registryPrefixes.empty())
392b304bd79SP Dheeraj Srujan Kumar             {
393b304bd79SP Dheeraj Srujan Kumar                 registryPrefix.assign(supportedRegPrefixes.begin(),
394b304bd79SP Dheeraj Srujan Kumar                                       supportedRegPrefixes.end());
395b304bd79SP Dheeraj Srujan Kumar             }
396b304bd79SP Dheeraj Srujan Kumar             else
397b304bd79SP Dheeraj Srujan Kumar             {
398b304bd79SP Dheeraj Srujan Kumar                 registryPrefix = subValue->registryPrefixes;
399b304bd79SP Dheeraj Srujan Kumar             }
400b304bd79SP Dheeraj Srujan Kumar 
401b304bd79SP Dheeraj Srujan Kumar             for (const std::string& id : *msgIds)
402b304bd79SP Dheeraj Srujan Kumar             {
403b304bd79SP Dheeraj Srujan Kumar                 bool validId = false;
404b304bd79SP Dheeraj Srujan Kumar 
405b304bd79SP Dheeraj Srujan Kumar                 // Check for Message ID in each of the selected Registry
406b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& it : registryPrefix)
407b304bd79SP Dheeraj Srujan Kumar                 {
408fffb8c1fSEd Tanous                     const std::span<const redfish::registries::MessageEntry>
409fffb8c1fSEd Tanous                         registry =
410fffb8c1fSEd Tanous                             redfish::registries::getRegistryFromPrefix(it);
411b304bd79SP Dheeraj Srujan Kumar 
412b304bd79SP Dheeraj Srujan Kumar                     if (std::any_of(
41326702d01SEd Tanous                             registry.begin(), registry.end(),
414fffb8c1fSEd Tanous                             [&id](const redfish::registries::MessageEntry&
415fffb8c1fSEd Tanous                                       messageEntry) {
41655f79e6fSEd Tanous                         return id == messageEntry.first;
417b304bd79SP Dheeraj Srujan Kumar                             }))
418b304bd79SP Dheeraj Srujan Kumar                     {
419b304bd79SP Dheeraj Srujan Kumar                         validId = true;
420b304bd79SP Dheeraj Srujan Kumar                         break;
421b304bd79SP Dheeraj Srujan Kumar                     }
422b304bd79SP Dheeraj Srujan Kumar                 }
423b304bd79SP Dheeraj Srujan Kumar 
424b304bd79SP Dheeraj Srujan Kumar                 if (!validId)
425b304bd79SP Dheeraj Srujan Kumar                 {
426b304bd79SP Dheeraj Srujan Kumar                     messages::propertyValueNotInList(asyncResp->res, id,
427b304bd79SP Dheeraj Srujan Kumar                                                      "MessageIds");
428b304bd79SP Dheeraj Srujan Kumar                     return;
429b304bd79SP Dheeraj Srujan Kumar                 }
430b304bd79SP Dheeraj Srujan Kumar             }
431b304bd79SP Dheeraj Srujan Kumar 
432b52664e2SAppaRao Puli             subValue->registryMsgIds = *msgIds;
433e5aaf047SAppaRao Puli         }
434e5aaf047SAppaRao Puli 
435e5aaf047SAppaRao Puli         if (retryPolicy)
436e5aaf047SAppaRao Puli         {
437e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
438e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
439e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
440e5aaf047SAppaRao Puli             {
441*002d39b4SEd Tanous                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
442*002d39b4SEd Tanous                                                  "DeliveryRetryPolicy");
443e5aaf047SAppaRao Puli                 return;
444e5aaf047SAppaRao Puli             }
445b52664e2SAppaRao Puli             subValue->retryPolicy = *retryPolicy;
446e5aaf047SAppaRao Puli         }
447e5aaf047SAppaRao Puli         else
448e5aaf047SAppaRao Puli         {
449e5aaf047SAppaRao Puli             // Default "TerminateAfterRetries"
450b52664e2SAppaRao Puli             subValue->retryPolicy = "TerminateAfterRetries";
451e5aaf047SAppaRao Puli         }
452e5aaf047SAppaRao Puli 
453144b6318SAppaRao Puli         if (mrdJsonArray)
454156d6b00SAppaRao Puli         {
455144b6318SAppaRao Puli             for (nlohmann::json& mrdObj : *mrdJsonArray)
456144b6318SAppaRao Puli             {
457144b6318SAppaRao Puli                 std::string mrdUri;
458ea2e6eecSWilly Tu 
459*002d39b4SEd Tanous                 if (!json_util::readJson(mrdObj, asyncResp->res, "@odata.id",
460*002d39b4SEd Tanous                                          mrdUri))
461ea2e6eecSWilly Tu 
462144b6318SAppaRao Puli                 {
463144b6318SAppaRao Puli                     return;
464144b6318SAppaRao Puli                 }
465ea2e6eecSWilly Tu                 subValue->metricReportDefinitions.emplace_back(mrdUri);
466144b6318SAppaRao Puli             }
467156d6b00SAppaRao Puli         }
468156d6b00SAppaRao Puli 
469b52664e2SAppaRao Puli         std::string id =
470fffb8c1fSEd Tanous             EventServiceManager::getInstance().addSubscription(subValue);
471b52664e2SAppaRao Puli         if (id.empty())
472e5aaf047SAppaRao Puli         {
473e5aaf047SAppaRao Puli             messages::internalError(asyncResp->res);
474e5aaf047SAppaRao Puli             return;
475e5aaf047SAppaRao Puli         }
476e5aaf047SAppaRao Puli 
477e5aaf047SAppaRao Puli         messages::created(asyncResp->res);
478e5aaf047SAppaRao Puli         asyncResp->res.addHeader(
479e5aaf047SAppaRao Puli             "Location", "/redfish/v1/EventService/Subscriptions/" + id);
4807e860f15SJohn Edward Broadbent         });
481e5aaf047SAppaRao Puli }
482e5aaf047SAppaRao Puli 
4837e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
484e5aaf047SAppaRao Puli {
4859d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
486ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
4877e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
48845ca1b86SEd Tanous             [&app](const crow::Request& req,
4897e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
4907e860f15SJohn Edward Broadbent                    const std::string& param) {
49145ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
49245ca1b86SEd Tanous         {
49345ca1b86SEd Tanous             return;
49445ca1b86SEd Tanous         }
495b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
4967e860f15SJohn Edward Broadbent             EventServiceManager::getInstance().getSubscription(param);
497b52664e2SAppaRao Puli         if (subValue == nullptr)
498e5aaf047SAppaRao Puli         {
499*002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::not_found);
500e5aaf047SAppaRao Puli             return;
501e5aaf047SAppaRao Puli         }
5027e860f15SJohn Edward Broadbent         const std::string& id = param;
503e5aaf047SAppaRao Puli 
5041476687dSEd Tanous         asyncResp->res.jsonValue["@odata.type"] =
5051476687dSEd Tanous             "#EventDestination.v1_7_0.EventDestination";
5061476687dSEd Tanous         asyncResp->res.jsonValue["Protocol"] = "Redfish";
507e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["@odata.id"] =
508e5aaf047SAppaRao Puli             "/redfish/v1/EventService/Subscriptions/" + id;
509e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Id"] = id;
510e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
511*002d39b4SEd Tanous         asyncResp->res.jsonValue["Destination"] = subValue->destinationUrl;
512b52664e2SAppaRao Puli         asyncResp->res.jsonValue["Context"] = subValue->customText;
513e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["SubscriptionType"] =
514b52664e2SAppaRao Puli             subValue->subscriptionType;
515*002d39b4SEd Tanous         asyncResp->res.jsonValue["HttpHeaders"] = nlohmann::json::array();
516*002d39b4SEd Tanous         asyncResp->res.jsonValue["EventFormatType"] = subValue->eventFormatType;
517e5aaf047SAppaRao Puli         asyncResp->res.jsonValue["RegistryPrefixes"] =
518b52664e2SAppaRao Puli             subValue->registryPrefixes;
519*002d39b4SEd Tanous         asyncResp->res.jsonValue["ResourceTypes"] = subValue->resourceTypes;
520e56f254cSSunitha Harish 
521*002d39b4SEd Tanous         asyncResp->res.jsonValue["MessageIds"] = subValue->registryMsgIds;
522*002d39b4SEd Tanous         asyncResp->res.jsonValue["DeliveryRetryPolicy"] = subValue->retryPolicy;
523144b6318SAppaRao Puli 
5241476687dSEd Tanous         nlohmann::json::array_t mrdJsonArray;
525144b6318SAppaRao Puli         for (const auto& mdrUri : subValue->metricReportDefinitions)
526144b6318SAppaRao Puli         {
5271476687dSEd Tanous             nlohmann::json::object_t mdr;
5281476687dSEd Tanous             mdr["@odata.id"] = mdrUri;
5291476687dSEd Tanous             mrdJsonArray.emplace_back(std::move(mdr));
530144b6318SAppaRao Puli         }
531*002d39b4SEd Tanous         asyncResp->res.jsonValue["MetricReportDefinitions"] = mrdJsonArray;
5327e860f15SJohn Edward Broadbent         });
5339d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
534ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
535ed398213SEd Tanous         // ConfigureSelf
5367eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
537ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
538432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
5397e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
54045ca1b86SEd Tanous             [&app](const crow::Request& req,
5417e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5427e860f15SJohn Edward Broadbent                    const std::string& param) {
54345ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
54445ca1b86SEd Tanous         {
54545ca1b86SEd Tanous             return;
54645ca1b86SEd Tanous         }
547b52664e2SAppaRao Puli         std::shared_ptr<Subscription> subValue =
5487e860f15SJohn Edward Broadbent             EventServiceManager::getInstance().getSubscription(param);
549b52664e2SAppaRao Puli         if (subValue == nullptr)
550e5aaf047SAppaRao Puli         {
551*002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::not_found);
552e5aaf047SAppaRao Puli             return;
553e5aaf047SAppaRao Puli         }
554e5aaf047SAppaRao Puli 
555e5aaf047SAppaRao Puli         std::optional<std::string> context;
556e5aaf047SAppaRao Puli         std::optional<std::string> retryPolicy;
557e5aaf047SAppaRao Puli         std::optional<std::vector<nlohmann::json>> headers;
558e5aaf047SAppaRao Puli 
559*002d39b4SEd Tanous         if (!json_util::readJsonPatch(req, asyncResp->res, "Context", context,
560*002d39b4SEd Tanous                                       "DeliveryRetryPolicy", retryPolicy,
561*002d39b4SEd Tanous                                       "HttpHeaders", headers))
562e5aaf047SAppaRao Puli         {
563e5aaf047SAppaRao Puli             return;
564e5aaf047SAppaRao Puli         }
565e5aaf047SAppaRao Puli 
566e5aaf047SAppaRao Puli         if (context)
567e5aaf047SAppaRao Puli         {
568b52664e2SAppaRao Puli             subValue->customText = *context;
569e5aaf047SAppaRao Puli         }
570e5aaf047SAppaRao Puli 
571e5aaf047SAppaRao Puli         if (headers)
572e5aaf047SAppaRao Puli         {
573601c71aeSEd Tanous             boost::beast::http::fields fields;
574601c71aeSEd Tanous             for (const nlohmann::json& headerChunk : *headers)
575601c71aeSEd Tanous             {
576601c71aeSEd Tanous                 for (auto& it : headerChunk.items())
577601c71aeSEd Tanous                 {
578601c71aeSEd Tanous                     const std::string* value =
579601c71aeSEd Tanous                         it.value().get_ptr<const std::string*>();
580601c71aeSEd Tanous                     if (value == nullptr)
581601c71aeSEd Tanous                     {
582601c71aeSEd Tanous                         messages::propertyValueFormatError(
583*002d39b4SEd Tanous                             asyncResp->res, it.value().dump(2, ' ', true),
584601c71aeSEd Tanous                             "HttpHeaders/" + it.key());
585601c71aeSEd Tanous                         return;
586601c71aeSEd Tanous                     }
587601c71aeSEd Tanous                     fields.set(it.key(), *value);
588601c71aeSEd Tanous                 }
589601c71aeSEd Tanous             }
590601c71aeSEd Tanous             subValue->httpHeaders = fields;
591e5aaf047SAppaRao Puli         }
592e5aaf047SAppaRao Puli 
593e5aaf047SAppaRao Puli         if (retryPolicy)
594e5aaf047SAppaRao Puli         {
595e5aaf047SAppaRao Puli             if (std::find(supportedRetryPolicies.begin(),
596e5aaf047SAppaRao Puli                           supportedRetryPolicies.end(),
597e5aaf047SAppaRao Puli                           *retryPolicy) == supportedRetryPolicies.end())
598e5aaf047SAppaRao Puli             {
599*002d39b4SEd Tanous                 messages::propertyValueNotInList(asyncResp->res, *retryPolicy,
600e5aaf047SAppaRao Puli                                                  "DeliveryRetryPolicy");
601e5aaf047SAppaRao Puli                 return;
602e5aaf047SAppaRao Puli             }
603b52664e2SAppaRao Puli             subValue->retryPolicy = *retryPolicy;
604fe44eb0bSAyushi Smriti             subValue->updateRetryPolicy();
605e5aaf047SAppaRao Puli         }
606e5aaf047SAppaRao Puli 
607b52664e2SAppaRao Puli         EventServiceManager::getInstance().updateSubscriptionData();
6087e860f15SJohn Edward Broadbent         });
6099d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
610ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
611ed398213SEd Tanous         // ConfigureSelf
6127eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
613ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
614432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
6157e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
61645ca1b86SEd Tanous             [&app](const crow::Request& req,
6177e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6187e860f15SJohn Edward Broadbent                    const std::string& param) {
61945ca1b86SEd Tanous         if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
62045ca1b86SEd Tanous         {
62145ca1b86SEd Tanous             return;
62245ca1b86SEd Tanous         }
623*002d39b4SEd Tanous         if (!EventServiceManager::getInstance().isSubscriptionExist(param))
624e5aaf047SAppaRao Puli         {
625*002d39b4SEd Tanous             asyncResp->res.result(boost::beast::http::status::not_found);
626e5aaf047SAppaRao Puli             return;
627e5aaf047SAppaRao Puli         }
6287e860f15SJohn Edward Broadbent         EventServiceManager::getInstance().deleteSubscription(param);
6297e860f15SJohn Edward Broadbent         });
630e5aaf047SAppaRao Puli }
631e5aaf047SAppaRao Puli 
632e5aaf047SAppaRao Puli } // namespace redfish
633