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>
21*45ca1b86SEd Tanous #include <query.hpp>
22ed398213SEd Tanous #include <registries/privilege_registry.hpp>
23ed398213SEd Tanous 
241e270c5fSPatrick Williams #include <span>
251e270c5fSPatrick Williams 
26e5aaf047SAppaRao Puli namespace redfish
27e5aaf047SAppaRao Puli {
28e5aaf047SAppaRao Puli 
29156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
30156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
31e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
32b304bd79SP Dheeraj Srujan Kumar     "Base", "OpenBMC", "TaskEvent"};
33e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
34e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
35e5aaf047SAppaRao Puli 
36e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
37e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = {
38e56f254cSSunitha Harish     "IBMConfigFile", "Task"};
39e56f254cSSunitha Harish #else
40e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = {
41e56f254cSSunitha Harish     "Task"};
42e56f254cSSunitha Harish #endif
43e56f254cSSunitha Harish 
44e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
45e5aaf047SAppaRao Puli 
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)
50*45ca1b86SEd Tanous         .methods(boost::beast::http::verb::get)([&app](const crow::Request& req,
51*45ca1b86SEd Tanous                                                        const std::shared_ptr<
52*45ca1b86SEd Tanous                                                            bmcweb::AsyncResp>&
53*45ca1b86SEd Tanous                                                            asyncResp) {
54*45ca1b86SEd Tanous             if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
55*45ca1b86SEd Tanous             {
56*45ca1b86SEd Tanous                 return;
57*45ca1b86SEd Tanous             }
588d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
59e5aaf047SAppaRao Puli                 {"@odata.type", "#EventService.v1_5_0.EventService"},
60e5aaf047SAppaRao Puli                 {"Id", "EventService"},
61e5aaf047SAppaRao Puli                 {"Name", "Event Service"},
62e5aaf047SAppaRao Puli                 {"Subscriptions",
63e5aaf047SAppaRao Puli                  {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
640b4bdd93SAppaRao Puli                 {"Actions",
650b4bdd93SAppaRao Puli                  {{"#EventService.SubmitTestEvent",
660fda0f12SGeorge Liu                    {{"target",
670fda0f12SGeorge Liu                      "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"}}}}},
68e5aaf047SAppaRao Puli                 {"@odata.id", "/redfish/v1/EventService"}};
69e5aaf047SAppaRao Puli 
7028afb49cSJunLin Chen             const persistent_data::EventServiceConfig eventServiceConfig =
7128afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
7228afb49cSJunLin Chen                     .getEventServiceConfig();
737d1cc387SAppaRao Puli 
747d1cc387SAppaRao Puli             asyncResp->res.jsonValue["Status"]["State"] =
7528afb49cSJunLin Chen                 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
7628afb49cSJunLin Chen             asyncResp->res.jsonValue["ServiceEnabled"] =
7728afb49cSJunLin Chen                 eventServiceConfig.enabled;
787e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
7928afb49cSJunLin Chen                 eventServiceConfig.retryAttempts;
80e5aaf047SAppaRao Puli             asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
8128afb49cSJunLin Chen                 eventServiceConfig.retryTimeoutInterval;
827e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["EventFormatTypes"] =
837e860f15SJohn Edward Broadbent                 supportedEvtFormatTypes;
840fda0f12SGeorge Liu             asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
850fda0f12SGeorge Liu             asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
8607941a88SAyushi Smriti 
8707941a88SAyushi Smriti             nlohmann::json supportedSSEFilters = {
8807941a88SAyushi Smriti                 {"EventFormatType", true},        {"MessageId", true},
8907941a88SAyushi Smriti                 {"MetricReportDefinition", true}, {"RegistryPrefix", true},
9007941a88SAyushi Smriti                 {"OriginResource", false},        {"ResourceType", false}};
9107941a88SAyushi Smriti 
9207941a88SAyushi Smriti             asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
9307941a88SAyushi Smriti                 supportedSSEFilters;
947e860f15SJohn Edward Broadbent         });
95e5aaf047SAppaRao Puli 
967e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
97ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
987e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
99*45ca1b86SEd Tanous             [&app](const crow::Request& req,
100*45ca1b86SEd Tanous                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
101*45ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
102e5aaf047SAppaRao Puli                 {
103*45ca1b86SEd Tanous                     return;
104*45ca1b86SEd Tanous                 }
105e5aaf047SAppaRao Puli                 std::optional<bool> serviceEnabled;
106e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryAttemps;
107e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryInterval;
108e5aaf047SAppaRao Puli 
10915ed6780SWilly Tu                 if (!json_util::readJsonPatch(
1107e860f15SJohn Edward Broadbent                         req, asyncResp->res, "ServiceEnabled", serviceEnabled,
1117e860f15SJohn Edward Broadbent                         "DeliveryRetryAttempts", retryAttemps,
1127e860f15SJohn Edward Broadbent                         "DeliveryRetryIntervalSeconds", retryInterval))
113e5aaf047SAppaRao Puli                 {
114e5aaf047SAppaRao Puli                     return;
115e5aaf047SAppaRao Puli                 }
116e5aaf047SAppaRao Puli 
11728afb49cSJunLin Chen                 persistent_data::EventServiceConfig eventServiceConfig =
11828afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
11928afb49cSJunLin Chen                         .getEventServiceConfig();
1207d1cc387SAppaRao Puli 
121e5aaf047SAppaRao Puli                 if (serviceEnabled)
122e5aaf047SAppaRao Puli                 {
12328afb49cSJunLin Chen                     eventServiceConfig.enabled = *serviceEnabled;
124e5aaf047SAppaRao Puli                 }
125e5aaf047SAppaRao Puli 
126e5aaf047SAppaRao Puli                 if (retryAttemps)
127e5aaf047SAppaRao Puli                 {
128e5aaf047SAppaRao Puli                     // Supported range [1-3]
129e5aaf047SAppaRao Puli                     if ((*retryAttemps < 1) || (*retryAttemps > 3))
130e5aaf047SAppaRao Puli                     {
131e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
132e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryAttemps),
133e5aaf047SAppaRao Puli                             "DeliveryRetryAttempts", "[1-3]");
134e5aaf047SAppaRao Puli                     }
135e5aaf047SAppaRao Puli                     else
136e5aaf047SAppaRao Puli                     {
13728afb49cSJunLin Chen                         eventServiceConfig.retryAttempts = *retryAttemps;
138e5aaf047SAppaRao Puli                     }
139e5aaf047SAppaRao Puli                 }
140e5aaf047SAppaRao Puli 
141e5aaf047SAppaRao Puli                 if (retryInterval)
142e5aaf047SAppaRao Puli                 {
143e5aaf047SAppaRao Puli                     // Supported range [30 - 180]
144e5aaf047SAppaRao Puli                     if ((*retryInterval < 30) || (*retryInterval > 180))
145e5aaf047SAppaRao Puli                     {
146e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
147e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryInterval),
148e5aaf047SAppaRao Puli                             "DeliveryRetryIntervalSeconds", "[30-180]");
149e5aaf047SAppaRao Puli                     }
150e5aaf047SAppaRao Puli                     else
151e5aaf047SAppaRao Puli                     {
15228afb49cSJunLin Chen                         eventServiceConfig.retryTimeoutInterval =
15328afb49cSJunLin Chen                             *retryInterval;
154e5aaf047SAppaRao Puli                     }
155e5aaf047SAppaRao Puli                 }
156e5aaf047SAppaRao Puli 
1577d1cc387SAppaRao Puli                 EventServiceManager::getInstance().setEventServiceConfig(
15828afb49cSJunLin Chen                     eventServiceConfig);
1597e860f15SJohn Edward Broadbent             });
1600b4bdd93SAppaRao Puli }
1610b4bdd93SAppaRao Puli 
1627e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1630b4bdd93SAppaRao Puli {
1647e860f15SJohn Edward Broadbent 
1657e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1667e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
167ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1687e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
169*45ca1b86SEd Tanous             [&app](const crow::Request& req,
1707e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
171*45ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
172*45ca1b86SEd Tanous                 {
173*45ca1b86SEd Tanous                     return;
174*45ca1b86SEd Tanous                 }
1756ba8c82eSsunharis_in                 if (!EventServiceManager::getInstance().sendTestEventLog())
1766ba8c82eSsunharis_in                 {
1776ba8c82eSsunharis_in                     messages::serviceDisabled(asyncResp->res,
1786ba8c82eSsunharis_in                                               "/redfish/v1/EventService/");
1796ba8c82eSsunharis_in                     return;
1806ba8c82eSsunharis_in                 }
1818d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
1827e860f15SJohn Edward Broadbent             });
183e5aaf047SAppaRao Puli }
184e5aaf047SAppaRao Puli 
1857e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
186e5aaf047SAppaRao Puli {
1871ebe3e41SGayathri Leburu     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
188ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
1897e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
190*45ca1b86SEd Tanous             [&app](const crow::Request& req,
1917e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
192*45ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
193*45ca1b86SEd Tanous                 {
194*45ca1b86SEd Tanous                     return;
195*45ca1b86SEd Tanous                 }
1968d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
197e5aaf047SAppaRao Puli                     {"@odata.type",
198e5aaf047SAppaRao Puli                      "#EventDestinationCollection.EventDestinationCollection"},
199e5aaf047SAppaRao Puli                     {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
200e5aaf047SAppaRao Puli                     {"Name", "Event Destination Collections"}};
201e5aaf047SAppaRao Puli 
2027e860f15SJohn Edward Broadbent                 nlohmann::json& memberArray =
2037e860f15SJohn Edward Broadbent                     asyncResp->res.jsonValue["Members"];
204e5aaf047SAppaRao Puli 
205b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
206b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
207b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
2087e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members@odata.count"] =
2097e860f15SJohn Edward Broadbent                     subscripIds.size();
210b52664e2SAppaRao Puli 
211b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
212e5aaf047SAppaRao Puli                 {
213e5aaf047SAppaRao Puli                     memberArray.push_back(
214e5aaf047SAppaRao Puli                         {{"@odata.id",
215b52664e2SAppaRao Puli                           "/redfish/v1/EventService/Subscriptions/" + id}});
216e5aaf047SAppaRao Puli                 }
2177e860f15SJohn Edward Broadbent             });
2187e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
2197eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
220fffb8c1fSEd Tanous         .methods(
221fffb8c1fSEd Tanous             boost::beast::http::verb::
222*45ca1b86SEd Tanous                 post)([&app](
223*45ca1b86SEd Tanous                           const crow::Request& req,
2247e860f15SJohn Edward Broadbent                           const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
225*45ca1b86SEd Tanous             if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
226*45ca1b86SEd Tanous             {
227*45ca1b86SEd Tanous                 return;
228*45ca1b86SEd Tanous             }
229fffb8c1fSEd Tanous             if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
230fffb8c1fSEd Tanous                 maxNoOfSubscriptions)
231e5aaf047SAppaRao Puli             {
232e5aaf047SAppaRao Puli                 messages::eventSubscriptionLimitExceeded(asyncResp->res);
233e5aaf047SAppaRao Puli                 return;
234e5aaf047SAppaRao Puli             }
235e5aaf047SAppaRao Puli             std::string destUrl;
236e5aaf047SAppaRao Puli             std::string protocol;
237e5aaf047SAppaRao Puli             std::optional<std::string> context;
238e5aaf047SAppaRao Puli             std::optional<std::string> subscriptionType;
23923a21a1cSEd Tanous             std::optional<std::string> eventFormatType2;
240e5aaf047SAppaRao Puli             std::optional<std::string> retryPolicy;
241e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> msgIds;
242e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> regPrefixes;
243e56f254cSSunitha Harish             std::optional<std::vector<std::string>> resTypes;
244e5aaf047SAppaRao Puli             std::optional<std::vector<nlohmann::json>> headers;
245144b6318SAppaRao Puli             std::optional<std::vector<nlohmann::json>> mrdJsonArray;
246e5aaf047SAppaRao Puli 
24715ed6780SWilly Tu             if (!json_util::readJsonPatch(
2487e860f15SJohn Edward Broadbent                     req, asyncResp->res, "Destination", destUrl, "Context",
2497e860f15SJohn Edward Broadbent                     context, "Protocol", protocol, "SubscriptionType",
2507e860f15SJohn Edward Broadbent                     subscriptionType, "EventFormatType", eventFormatType2,
2517e860f15SJohn Edward Broadbent                     "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
252fffb8c1fSEd Tanous                     "MessageIds", msgIds, "DeliveryRetryPolicy", retryPolicy,
253fffb8c1fSEd Tanous                     "MetricReportDefinitions", mrdJsonArray, "ResourceTypes",
254fffb8c1fSEd Tanous                     resTypes))
255e5aaf047SAppaRao Puli             {
256e5aaf047SAppaRao Puli                 return;
257e5aaf047SAppaRao Puli             }
258e5aaf047SAppaRao Puli 
259dd28ba82SAppaRao Puli             if (regPrefixes && msgIds)
260dd28ba82SAppaRao Puli             {
26126f6976fSEd Tanous                 if (!regPrefixes->empty() && !msgIds->empty())
262dd28ba82SAppaRao Puli                 {
2630a4304cfSEd Tanous                     messages::propertyValueConflict(
2640a4304cfSEd Tanous                         asyncResp->res, "MessageIds", "RegistryPrefixes");
265dd28ba82SAppaRao Puli                     return;
266dd28ba82SAppaRao Puli                 }
267dd28ba82SAppaRao Puli             }
268dd28ba82SAppaRao Puli 
269e5aaf047SAppaRao Puli             // Validate the URL using regex expression
270b52664e2SAppaRao Puli             // Format: <protocol>://<host>:<port>/<uri>
271b52664e2SAppaRao Puli             // protocol: http/https
272b52664e2SAppaRao Puli             // host: Exclude ' ', ':', '#', '?'
2734e0453b1SGunnar Mills             // port: Empty or numeric value with ':' separator.
274b52664e2SAppaRao Puli             // uri: Start with '/' and Exclude '#', ' '
275b52664e2SAppaRao Puli             //      Can include query params(ex: '/event?test=1')
276b52664e2SAppaRao Puli             // TODO: Need to validate hostname extensively(as per rfc)
277b52664e2SAppaRao Puli             const std::regex urlRegex(
278b52664e2SAppaRao Puli                 "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
279b52664e2SAppaRao Puli                 "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
280b52664e2SAppaRao Puli             std::cmatch match;
281b52664e2SAppaRao Puli             if (!std::regex_match(destUrl.c_str(), match, urlRegex))
282e5aaf047SAppaRao Puli             {
283e5aaf047SAppaRao Puli                 messages::propertyValueFormatError(asyncResp->res, destUrl,
284e5aaf047SAppaRao Puli                                                    "Destination");
285e5aaf047SAppaRao Puli                 return;
286e5aaf047SAppaRao Puli             }
287b52664e2SAppaRao Puli 
288fffb8c1fSEd Tanous             std::string uriProto = std::string(match[1].first, match[1].second);
289b52664e2SAppaRao Puli             if (uriProto == "http")
290b52664e2SAppaRao Puli             {
291b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
292b52664e2SAppaRao Puli                 messages::propertyValueFormatError(asyncResp->res, destUrl,
293b52664e2SAppaRao Puli                                                    "Destination");
294b52664e2SAppaRao Puli                 return;
295b52664e2SAppaRao Puli #endif
296b52664e2SAppaRao Puli             }
297b52664e2SAppaRao Puli 
298b52664e2SAppaRao Puli             std::string host = std::string(match[2].first, match[2].second);
299b52664e2SAppaRao Puli             std::string port = std::string(match[3].first, match[3].second);
300b52664e2SAppaRao Puli             std::string path = std::string(match[4].first, match[4].second);
301b52664e2SAppaRao Puli             if (port.empty())
302b52664e2SAppaRao Puli             {
303b52664e2SAppaRao Puli                 if (uriProto == "http")
304b52664e2SAppaRao Puli                 {
305b52664e2SAppaRao Puli                     port = "80";
306b52664e2SAppaRao Puli                 }
307b52664e2SAppaRao Puli                 else
308b52664e2SAppaRao Puli                 {
309b52664e2SAppaRao Puli                     port = "443";
310b52664e2SAppaRao Puli                 }
311b52664e2SAppaRao Puli             }
312b52664e2SAppaRao Puli             if (path.empty())
313b52664e2SAppaRao Puli             {
314b52664e2SAppaRao Puli                 path = "/";
315b52664e2SAppaRao Puli             }
316b52664e2SAppaRao Puli 
317b52664e2SAppaRao Puli             std::shared_ptr<Subscription> subValue =
318b52664e2SAppaRao Puli                 std::make_shared<Subscription>(host, port, path, uriProto);
319b52664e2SAppaRao Puli 
320b52664e2SAppaRao Puli             subValue->destinationUrl = destUrl;
321e5aaf047SAppaRao Puli 
322e5aaf047SAppaRao Puli             if (subscriptionType)
323e5aaf047SAppaRao Puli             {
324e5aaf047SAppaRao Puli                 if (*subscriptionType != "RedfishEvent")
325e5aaf047SAppaRao Puli                 {
326fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
327fffb8c1fSEd Tanous                         asyncResp->res, *subscriptionType, "SubscriptionType");
328e5aaf047SAppaRao Puli                     return;
329e5aaf047SAppaRao Puli                 }
330b52664e2SAppaRao Puli                 subValue->subscriptionType = *subscriptionType;
331e5aaf047SAppaRao Puli             }
332e5aaf047SAppaRao Puli             else
333e5aaf047SAppaRao Puli             {
334b52664e2SAppaRao Puli                 subValue->subscriptionType = "RedfishEvent"; // Default
335e5aaf047SAppaRao Puli             }
336e5aaf047SAppaRao Puli 
337e5aaf047SAppaRao Puli             if (protocol != "Redfish")
338e5aaf047SAppaRao Puli             {
339e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, protocol,
340e5aaf047SAppaRao Puli                                                  "Protocol");
341e5aaf047SAppaRao Puli                 return;
342e5aaf047SAppaRao Puli             }
343b52664e2SAppaRao Puli             subValue->protocol = protocol;
344e5aaf047SAppaRao Puli 
34523a21a1cSEd Tanous             if (eventFormatType2)
346e5aaf047SAppaRao Puli             {
347e5aaf047SAppaRao Puli                 if (std::find(supportedEvtFormatTypes.begin(),
348e5aaf047SAppaRao Puli                               supportedEvtFormatTypes.end(),
3497e860f15SJohn Edward Broadbent                               *eventFormatType2) ==
3507e860f15SJohn Edward Broadbent                     supportedEvtFormatTypes.end())
351e5aaf047SAppaRao Puli                 {
352fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
353fffb8c1fSEd Tanous                         asyncResp->res, *eventFormatType2, "EventFormatType");
354e5aaf047SAppaRao Puli                     return;
355e5aaf047SAppaRao Puli                 }
35623a21a1cSEd Tanous                 subValue->eventFormatType = *eventFormatType2;
357e5aaf047SAppaRao Puli             }
358e5aaf047SAppaRao Puli             else
359e5aaf047SAppaRao Puli             {
360e5aaf047SAppaRao Puli                 // If not specified, use default "Event"
36123a21a1cSEd Tanous                 subValue->eventFormatType = "Event";
362e5aaf047SAppaRao Puli             }
363e5aaf047SAppaRao Puli 
364e5aaf047SAppaRao Puli             if (context)
365e5aaf047SAppaRao Puli             {
366b52664e2SAppaRao Puli                 subValue->customText = *context;
367e5aaf047SAppaRao Puli             }
368e5aaf047SAppaRao Puli 
369e5aaf047SAppaRao Puli             if (headers)
370e5aaf047SAppaRao Puli             {
371601c71aeSEd Tanous                 for (const nlohmann::json& headerChunk : *headers)
372601c71aeSEd Tanous                 {
373601c71aeSEd Tanous                     for (const auto& item : headerChunk.items())
374601c71aeSEd Tanous                     {
375601c71aeSEd Tanous                         const std::string* value =
376601c71aeSEd Tanous                             item.value().get_ptr<const std::string*>();
377601c71aeSEd Tanous                         if (value == nullptr)
378601c71aeSEd Tanous                         {
379601c71aeSEd Tanous                             messages::propertyValueFormatError(
380e662eae8SEd Tanous                                 asyncResp->res, item.value().dump(2, 1),
381601c71aeSEd Tanous                                 "HttpHeaders/" + item.key());
382601c71aeSEd Tanous                             return;
383601c71aeSEd Tanous                         }
384601c71aeSEd Tanous                         subValue->httpHeaders.set(item.key(), *value);
385601c71aeSEd Tanous                     }
386601c71aeSEd Tanous                 }
387e5aaf047SAppaRao Puli             }
388e5aaf047SAppaRao Puli 
389e5aaf047SAppaRao Puli             if (regPrefixes)
390e5aaf047SAppaRao Puli             {
391e5aaf047SAppaRao Puli                 for (const std::string& it : *regPrefixes)
392e5aaf047SAppaRao Puli                 {
393e5aaf047SAppaRao Puli                     if (std::find(supportedRegPrefixes.begin(),
394e5aaf047SAppaRao Puli                                   supportedRegPrefixes.end(),
395e5aaf047SAppaRao Puli                                   it) == supportedRegPrefixes.end())
396e5aaf047SAppaRao Puli                     {
397fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
398fffb8c1fSEd Tanous                                                          "RegistryPrefixes");
399e5aaf047SAppaRao Puli                         return;
400e5aaf047SAppaRao Puli                     }
401e5aaf047SAppaRao Puli                 }
402b52664e2SAppaRao Puli                 subValue->registryPrefixes = *regPrefixes;
403e5aaf047SAppaRao Puli             }
404e5aaf047SAppaRao Puli 
405e56f254cSSunitha Harish             if (resTypes)
406e56f254cSSunitha Harish             {
407e56f254cSSunitha Harish                 for (const std::string& it : *resTypes)
408e56f254cSSunitha Harish                 {
409e56f254cSSunitha Harish                     if (std::find(supportedResourceTypes.begin(),
410e56f254cSSunitha Harish                                   supportedResourceTypes.end(),
411e56f254cSSunitha Harish                                   it) == supportedResourceTypes.end())
412e56f254cSSunitha Harish                     {
413e56f254cSSunitha Harish                         messages::propertyValueNotInList(asyncResp->res, it,
414e56f254cSSunitha Harish                                                          "ResourceTypes");
415e56f254cSSunitha Harish                         return;
416e56f254cSSunitha Harish                     }
417e56f254cSSunitha Harish                 }
418e56f254cSSunitha Harish                 subValue->resourceTypes = *resTypes;
419e56f254cSSunitha Harish             }
420e56f254cSSunitha Harish 
421e5aaf047SAppaRao Puli             if (msgIds)
422e5aaf047SAppaRao Puli             {
423b304bd79SP Dheeraj Srujan Kumar                 std::vector<std::string> registryPrefix;
424b304bd79SP Dheeraj Srujan Kumar 
4257e860f15SJohn Edward Broadbent                 // If no registry prefixes are mentioned, consider all
4267e860f15SJohn Edward Broadbent                 // supported prefixes
427b304bd79SP Dheeraj Srujan Kumar                 if (subValue->registryPrefixes.empty())
428b304bd79SP Dheeraj Srujan Kumar                 {
429b304bd79SP Dheeraj Srujan Kumar                     registryPrefix.assign(supportedRegPrefixes.begin(),
430b304bd79SP Dheeraj Srujan Kumar                                           supportedRegPrefixes.end());
431b304bd79SP Dheeraj Srujan Kumar                 }
432b304bd79SP Dheeraj Srujan Kumar                 else
433b304bd79SP Dheeraj Srujan Kumar                 {
434b304bd79SP Dheeraj Srujan Kumar                     registryPrefix = subValue->registryPrefixes;
435b304bd79SP Dheeraj Srujan Kumar                 }
436b304bd79SP Dheeraj Srujan Kumar 
437b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& id : *msgIds)
438b304bd79SP Dheeraj Srujan Kumar                 {
439b304bd79SP Dheeraj Srujan Kumar                     bool validId = false;
440b304bd79SP Dheeraj Srujan Kumar 
441b304bd79SP Dheeraj Srujan Kumar                     // Check for Message ID in each of the selected Registry
442b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& it : registryPrefix)
443b304bd79SP Dheeraj Srujan Kumar                     {
444fffb8c1fSEd Tanous                         const std::span<const redfish::registries::MessageEntry>
445fffb8c1fSEd Tanous                             registry =
446fffb8c1fSEd Tanous                                 redfish::registries::getRegistryFromPrefix(it);
447b304bd79SP Dheeraj Srujan Kumar 
448b304bd79SP Dheeraj Srujan Kumar                         if (std::any_of(
44926702d01SEd Tanous                                 registry.begin(), registry.end(),
450fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
451fffb8c1fSEd Tanous                                           messageEntry) {
45255f79e6fSEd Tanous                                     return id == messageEntry.first;
453b304bd79SP Dheeraj Srujan Kumar                                 }))
454b304bd79SP Dheeraj Srujan Kumar                         {
455b304bd79SP Dheeraj Srujan Kumar                             validId = true;
456b304bd79SP Dheeraj Srujan Kumar                             break;
457b304bd79SP Dheeraj Srujan Kumar                         }
458b304bd79SP Dheeraj Srujan Kumar                     }
459b304bd79SP Dheeraj Srujan Kumar 
460b304bd79SP Dheeraj Srujan Kumar                     if (!validId)
461b304bd79SP Dheeraj Srujan Kumar                     {
462b304bd79SP Dheeraj Srujan Kumar                         messages::propertyValueNotInList(asyncResp->res, id,
463b304bd79SP Dheeraj Srujan Kumar                                                          "MessageIds");
464b304bd79SP Dheeraj Srujan Kumar                         return;
465b304bd79SP Dheeraj Srujan Kumar                     }
466b304bd79SP Dheeraj Srujan Kumar                 }
467b304bd79SP Dheeraj Srujan Kumar 
468b52664e2SAppaRao Puli                 subValue->registryMsgIds = *msgIds;
469e5aaf047SAppaRao Puli             }
470e5aaf047SAppaRao Puli 
471e5aaf047SAppaRao Puli             if (retryPolicy)
472e5aaf047SAppaRao Puli             {
473e5aaf047SAppaRao Puli                 if (std::find(supportedRetryPolicies.begin(),
474e5aaf047SAppaRao Puli                               supportedRetryPolicies.end(),
475e5aaf047SAppaRao Puli                               *retryPolicy) == supportedRetryPolicies.end())
476e5aaf047SAppaRao Puli                 {
477fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
478fffb8c1fSEd Tanous                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
479e5aaf047SAppaRao Puli                     return;
480e5aaf047SAppaRao Puli                 }
481b52664e2SAppaRao Puli                 subValue->retryPolicy = *retryPolicy;
482e5aaf047SAppaRao Puli             }
483e5aaf047SAppaRao Puli             else
484e5aaf047SAppaRao Puli             {
485e5aaf047SAppaRao Puli                 // Default "TerminateAfterRetries"
486b52664e2SAppaRao Puli                 subValue->retryPolicy = "TerminateAfterRetries";
487e5aaf047SAppaRao Puli             }
488e5aaf047SAppaRao Puli 
489144b6318SAppaRao Puli             if (mrdJsonArray)
490156d6b00SAppaRao Puli             {
491144b6318SAppaRao Puli                 for (nlohmann::json& mrdObj : *mrdJsonArray)
492144b6318SAppaRao Puli                 {
493144b6318SAppaRao Puli                     std::string mrdUri;
494ea2e6eecSWilly Tu 
495ea2e6eecSWilly Tu                     if (!json_util::readJson(mrdObj, asyncResp->res,
496ea2e6eecSWilly Tu                                              "@odata.id", mrdUri))
497ea2e6eecSWilly Tu 
498144b6318SAppaRao Puli                     {
499144b6318SAppaRao Puli                         return;
500144b6318SAppaRao Puli                     }
501ea2e6eecSWilly Tu                     subValue->metricReportDefinitions.emplace_back(mrdUri);
502144b6318SAppaRao Puli                 }
503156d6b00SAppaRao Puli             }
504156d6b00SAppaRao Puli 
505b52664e2SAppaRao Puli             std::string id =
506fffb8c1fSEd Tanous                 EventServiceManager::getInstance().addSubscription(subValue);
507b52664e2SAppaRao Puli             if (id.empty())
508e5aaf047SAppaRao Puli             {
509e5aaf047SAppaRao Puli                 messages::internalError(asyncResp->res);
510e5aaf047SAppaRao Puli                 return;
511e5aaf047SAppaRao Puli             }
512e5aaf047SAppaRao Puli 
513e5aaf047SAppaRao Puli             messages::created(asyncResp->res);
514e5aaf047SAppaRao Puli             asyncResp->res.addHeader(
515e5aaf047SAppaRao Puli                 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
5167e860f15SJohn Edward Broadbent         });
517e5aaf047SAppaRao Puli }
518e5aaf047SAppaRao Puli 
5197e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
520e5aaf047SAppaRao Puli {
5219d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
522ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
5237e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
524*45ca1b86SEd Tanous             [&app](const crow::Request& req,
5257e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5267e860f15SJohn Edward Broadbent                    const std::string& param) {
527*45ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
528*45ca1b86SEd Tanous                 {
529*45ca1b86SEd Tanous                     return;
530*45ca1b86SEd Tanous                 }
531b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5327e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
533b52664e2SAppaRao Puli                 if (subValue == nullptr)
534e5aaf047SAppaRao Puli                 {
5357e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5367e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
537e5aaf047SAppaRao Puli                     return;
538e5aaf047SAppaRao Puli                 }
5397e860f15SJohn Edward Broadbent                 const std::string& id = param;
540e5aaf047SAppaRao Puli 
5418d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
5427e860f15SJohn Edward Broadbent                     {"@odata.type",
5437e860f15SJohn Edward Broadbent                      "#EventDestination.v1_7_0.EventDestination"},
544e5aaf047SAppaRao Puli                     {"Protocol", "Redfish"}};
545e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["@odata.id"] =
546e5aaf047SAppaRao Puli                     "/redfish/v1/EventService/Subscriptions/" + id;
547e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Id"] = id;
548e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
5497e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Destination"] =
5507e860f15SJohn Edward Broadbent                     subValue->destinationUrl;
551b52664e2SAppaRao Puli                 asyncResp->res.jsonValue["Context"] = subValue->customText;
552e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["SubscriptionType"] =
553b52664e2SAppaRao Puli                     subValue->subscriptionType;
554ad22fefeSEd Tanous                 asyncResp->res.jsonValue["HttpHeaders"] =
555ad22fefeSEd Tanous                     nlohmann::json::array();
5567e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["EventFormatType"] =
5577e860f15SJohn Edward Broadbent                     subValue->eventFormatType;
558e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["RegistryPrefixes"] =
559b52664e2SAppaRao Puli                     subValue->registryPrefixes;
5607e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["ResourceTypes"] =
5617e860f15SJohn Edward Broadbent                     subValue->resourceTypes;
562e56f254cSSunitha Harish 
5637e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MessageIds"] =
5647e860f15SJohn Edward Broadbent                     subValue->registryMsgIds;
5657e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
5667e860f15SJohn Edward Broadbent                     subValue->retryPolicy;
567144b6318SAppaRao Puli 
568144b6318SAppaRao Puli                 std::vector<nlohmann::json> mrdJsonArray;
569144b6318SAppaRao Puli                 for (const auto& mdrUri : subValue->metricReportDefinitions)
570144b6318SAppaRao Puli                 {
571144b6318SAppaRao Puli                     mrdJsonArray.push_back({{"@odata.id", mdrUri}});
572144b6318SAppaRao Puli                 }
5737e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MetricReportDefinitions"] =
5747e860f15SJohn Edward Broadbent                     mrdJsonArray;
5757e860f15SJohn Edward Broadbent             });
5769d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
577ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
578ed398213SEd Tanous         // ConfigureSelf
5797eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
580ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
581432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
5827e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
583*45ca1b86SEd Tanous             [&app](const crow::Request& req,
5847e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5857e860f15SJohn Edward Broadbent                    const std::string& param) {
586*45ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
587*45ca1b86SEd Tanous                 {
588*45ca1b86SEd Tanous                     return;
589*45ca1b86SEd Tanous                 }
590b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5917e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
592b52664e2SAppaRao Puli                 if (subValue == nullptr)
593e5aaf047SAppaRao Puli                 {
5947e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5957e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
596e5aaf047SAppaRao Puli                     return;
597e5aaf047SAppaRao Puli                 }
598e5aaf047SAppaRao Puli 
599e5aaf047SAppaRao Puli                 std::optional<std::string> context;
600e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
601e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
602e5aaf047SAppaRao Puli 
60315ed6780SWilly Tu                 if (!json_util::readJsonPatch(req, asyncResp->res, "Context",
6047e860f15SJohn Edward Broadbent                                               context, "DeliveryRetryPolicy",
60515ed6780SWilly Tu                                               retryPolicy, "HttpHeaders",
60615ed6780SWilly Tu                                               headers))
607e5aaf047SAppaRao Puli                 {
608e5aaf047SAppaRao Puli                     return;
609e5aaf047SAppaRao Puli                 }
610e5aaf047SAppaRao Puli 
611e5aaf047SAppaRao Puli                 if (context)
612e5aaf047SAppaRao Puli                 {
613b52664e2SAppaRao Puli                     subValue->customText = *context;
614e5aaf047SAppaRao Puli                 }
615e5aaf047SAppaRao Puli 
616e5aaf047SAppaRao Puli                 if (headers)
617e5aaf047SAppaRao Puli                 {
618601c71aeSEd Tanous                     boost::beast::http::fields fields;
619601c71aeSEd Tanous                     for (const nlohmann::json& headerChunk : *headers)
620601c71aeSEd Tanous                     {
621601c71aeSEd Tanous                         for (auto& it : headerChunk.items())
622601c71aeSEd Tanous                         {
623601c71aeSEd Tanous                             const std::string* value =
624601c71aeSEd Tanous                                 it.value().get_ptr<const std::string*>();
625601c71aeSEd Tanous                             if (value == nullptr)
626601c71aeSEd Tanous                             {
627601c71aeSEd Tanous                                 messages::propertyValueFormatError(
628601c71aeSEd Tanous                                     asyncResp->res,
629601c71aeSEd Tanous                                     it.value().dump(2, ' ', true),
630601c71aeSEd Tanous                                     "HttpHeaders/" + it.key());
631601c71aeSEd Tanous                                 return;
632601c71aeSEd Tanous                             }
633601c71aeSEd Tanous                             fields.set(it.key(), *value);
634601c71aeSEd Tanous                         }
635601c71aeSEd Tanous                     }
636601c71aeSEd Tanous                     subValue->httpHeaders = fields;
637e5aaf047SAppaRao Puli                 }
638e5aaf047SAppaRao Puli 
639e5aaf047SAppaRao Puli                 if (retryPolicy)
640e5aaf047SAppaRao Puli                 {
641e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
642e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
643e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
644e5aaf047SAppaRao Puli                     {
6457e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
6467e860f15SJohn Edward Broadbent                                                          *retryPolicy,
647e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
648e5aaf047SAppaRao Puli                         return;
649e5aaf047SAppaRao Puli                     }
650b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
651fe44eb0bSAyushi Smriti                     subValue->updateRetryPolicy();
652e5aaf047SAppaRao Puli                 }
653e5aaf047SAppaRao Puli 
654b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
6557e860f15SJohn Edward Broadbent             });
6569d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
657ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
658ed398213SEd Tanous         // ConfigureSelf
6597eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
660ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
661432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
6627e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
663*45ca1b86SEd Tanous             [&app](const crow::Request& req,
6647e860f15SJohn Edward Broadbent                    const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6657e860f15SJohn Edward Broadbent                    const std::string& param) {
666*45ca1b86SEd Tanous                 if (!redfish::setUpRedfishRoute(app, req, asyncResp->res))
667*45ca1b86SEd Tanous                 {
668*45ca1b86SEd Tanous                     return;
669*45ca1b86SEd Tanous                 }
6707e860f15SJohn Edward Broadbent                 if (!EventServiceManager::getInstance().isSubscriptionExist(
6717e860f15SJohn Edward Broadbent                         param))
672e5aaf047SAppaRao Puli                 {
6737e860f15SJohn Edward Broadbent                     asyncResp->res.result(
6747e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
675e5aaf047SAppaRao Puli                     return;
676e5aaf047SAppaRao Puli                 }
6777e860f15SJohn Edward Broadbent                 EventServiceManager::getInstance().deleteSubscription(param);
6787e860f15SJohn Edward Broadbent             });
679e5aaf047SAppaRao Puli }
680e5aaf047SAppaRao Puli 
681e5aaf047SAppaRao Puli } // namespace redfish
682