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>
21ed398213SEd Tanous #include <registries/privilege_registry.hpp>
22ed398213SEd Tanous 
231e270c5fSPatrick Williams #include <span>
241e270c5fSPatrick Williams 
25e5aaf047SAppaRao Puli namespace redfish
26e5aaf047SAppaRao Puli {
27e5aaf047SAppaRao Puli 
28156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
29156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
30e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
31b304bd79SP Dheeraj Srujan Kumar     "Base", "OpenBMC", "TaskEvent"};
32e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
33e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
34e5aaf047SAppaRao Puli 
35e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
36e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = {
37e56f254cSSunitha Harish     "IBMConfigFile", "Task"};
38e56f254cSSunitha Harish #else
39e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = {
40e56f254cSSunitha Harish     "Task"};
41e56f254cSSunitha Harish #endif
42e56f254cSSunitha Harish 
43e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
44e5aaf047SAppaRao Puli 
457e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app)
46e5aaf047SAppaRao Puli {
477e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
48ed398213SEd Tanous         .privileges(redfish::privileges::getEventService)
490fda0f12SGeorge Liu         .methods(
500fda0f12SGeorge Liu             boost::beast::http::verb::
510fda0f12SGeorge Liu                 get)([](const crow::Request&,
527e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
538d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
54e5aaf047SAppaRao Puli                 {"@odata.type", "#EventService.v1_5_0.EventService"},
55e5aaf047SAppaRao Puli                 {"Id", "EventService"},
56e5aaf047SAppaRao Puli                 {"Name", "Event Service"},
57e5aaf047SAppaRao Puli                 {"Subscriptions",
58e5aaf047SAppaRao Puli                  {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
590b4bdd93SAppaRao Puli                 {"Actions",
600b4bdd93SAppaRao Puli                  {{"#EventService.SubmitTestEvent",
610fda0f12SGeorge Liu                    {{"target",
620fda0f12SGeorge Liu                      "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"}}}}},
63e5aaf047SAppaRao Puli                 {"@odata.id", "/redfish/v1/EventService"}};
64e5aaf047SAppaRao Puli 
6528afb49cSJunLin Chen             const persistent_data::EventServiceConfig eventServiceConfig =
6628afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
6728afb49cSJunLin Chen                     .getEventServiceConfig();
687d1cc387SAppaRao Puli 
697d1cc387SAppaRao Puli             asyncResp->res.jsonValue["Status"]["State"] =
7028afb49cSJunLin Chen                 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
7128afb49cSJunLin Chen             asyncResp->res.jsonValue["ServiceEnabled"] =
7228afb49cSJunLin Chen                 eventServiceConfig.enabled;
737e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
7428afb49cSJunLin Chen                 eventServiceConfig.retryAttempts;
75e5aaf047SAppaRao Puli             asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
7628afb49cSJunLin Chen                 eventServiceConfig.retryTimeoutInterval;
777e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["EventFormatTypes"] =
787e860f15SJohn Edward Broadbent                 supportedEvtFormatTypes;
790fda0f12SGeorge Liu             asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
800fda0f12SGeorge Liu             asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
8107941a88SAyushi Smriti 
8207941a88SAyushi Smriti             nlohmann::json supportedSSEFilters = {
8307941a88SAyushi Smriti                 {"EventFormatType", true},        {"MessageId", true},
8407941a88SAyushi Smriti                 {"MetricReportDefinition", true}, {"RegistryPrefix", true},
8507941a88SAyushi Smriti                 {"OriginResource", false},        {"ResourceType", false}};
8607941a88SAyushi Smriti 
8707941a88SAyushi Smriti             asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
8807941a88SAyushi Smriti                 supportedSSEFilters;
897e860f15SJohn Edward Broadbent         });
90e5aaf047SAppaRao Puli 
917e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
92ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
937e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
947e860f15SJohn Edward Broadbent             [](const crow::Request& req,
957e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
967e860f15SJohn Edward Broadbent 
97e5aaf047SAppaRao Puli             {
98e5aaf047SAppaRao Puli                 std::optional<bool> serviceEnabled;
99e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryAttemps;
100e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryInterval;
101e5aaf047SAppaRao Puli 
10215ed6780SWilly Tu                 if (!json_util::readJsonPatch(
1037e860f15SJohn Edward Broadbent                         req, asyncResp->res, "ServiceEnabled", serviceEnabled,
1047e860f15SJohn Edward Broadbent                         "DeliveryRetryAttempts", retryAttemps,
1057e860f15SJohn Edward Broadbent                         "DeliveryRetryIntervalSeconds", retryInterval))
106e5aaf047SAppaRao Puli                 {
107e5aaf047SAppaRao Puli                     return;
108e5aaf047SAppaRao Puli                 }
109e5aaf047SAppaRao Puli 
11028afb49cSJunLin Chen                 persistent_data::EventServiceConfig eventServiceConfig =
11128afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
11228afb49cSJunLin Chen                         .getEventServiceConfig();
1137d1cc387SAppaRao Puli 
114e5aaf047SAppaRao Puli                 if (serviceEnabled)
115e5aaf047SAppaRao Puli                 {
11628afb49cSJunLin Chen                     eventServiceConfig.enabled = *serviceEnabled;
117e5aaf047SAppaRao Puli                 }
118e5aaf047SAppaRao Puli 
119e5aaf047SAppaRao Puli                 if (retryAttemps)
120e5aaf047SAppaRao Puli                 {
121e5aaf047SAppaRao Puli                     // Supported range [1-3]
122e5aaf047SAppaRao Puli                     if ((*retryAttemps < 1) || (*retryAttemps > 3))
123e5aaf047SAppaRao Puli                     {
124e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
125e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryAttemps),
126e5aaf047SAppaRao Puli                             "DeliveryRetryAttempts", "[1-3]");
127e5aaf047SAppaRao Puli                     }
128e5aaf047SAppaRao Puli                     else
129e5aaf047SAppaRao Puli                     {
13028afb49cSJunLin Chen                         eventServiceConfig.retryAttempts = *retryAttemps;
131e5aaf047SAppaRao Puli                     }
132e5aaf047SAppaRao Puli                 }
133e5aaf047SAppaRao Puli 
134e5aaf047SAppaRao Puli                 if (retryInterval)
135e5aaf047SAppaRao Puli                 {
136e5aaf047SAppaRao Puli                     // Supported range [30 - 180]
137e5aaf047SAppaRao Puli                     if ((*retryInterval < 30) || (*retryInterval > 180))
138e5aaf047SAppaRao Puli                     {
139e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
140e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryInterval),
141e5aaf047SAppaRao Puli                             "DeliveryRetryIntervalSeconds", "[30-180]");
142e5aaf047SAppaRao Puli                     }
143e5aaf047SAppaRao Puli                     else
144e5aaf047SAppaRao Puli                     {
14528afb49cSJunLin Chen                         eventServiceConfig.retryTimeoutInterval =
14628afb49cSJunLin Chen                             *retryInterval;
147e5aaf047SAppaRao Puli                     }
148e5aaf047SAppaRao Puli                 }
149e5aaf047SAppaRao Puli 
1507d1cc387SAppaRao Puli                 EventServiceManager::getInstance().setEventServiceConfig(
15128afb49cSJunLin Chen                     eventServiceConfig);
1527e860f15SJohn Edward Broadbent             });
1530b4bdd93SAppaRao Puli }
1540b4bdd93SAppaRao Puli 
1557e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1560b4bdd93SAppaRao Puli {
1577e860f15SJohn Edward Broadbent 
1587e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1597e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
160ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1617e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
1627e860f15SJohn Edward Broadbent             [](const crow::Request&,
1637e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1646ba8c82eSsunharis_in                 if (!EventServiceManager::getInstance().sendTestEventLog())
1656ba8c82eSsunharis_in                 {
1666ba8c82eSsunharis_in                     messages::serviceDisabled(asyncResp->res,
1676ba8c82eSsunharis_in                                               "/redfish/v1/EventService/");
1686ba8c82eSsunharis_in                     return;
1696ba8c82eSsunharis_in                 }
1708d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
1717e860f15SJohn Edward Broadbent             });
172e5aaf047SAppaRao Puli }
173e5aaf047SAppaRao Puli 
1747e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
175e5aaf047SAppaRao Puli {
1761ebe3e41SGayathri Leburu     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
177ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
1787e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
1797e860f15SJohn Edward Broadbent             [](const crow::Request&,
1807e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1818d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
182e5aaf047SAppaRao Puli                     {"@odata.type",
183e5aaf047SAppaRao Puli                      "#EventDestinationCollection.EventDestinationCollection"},
184e5aaf047SAppaRao Puli                     {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
185e5aaf047SAppaRao Puli                     {"Name", "Event Destination Collections"}};
186e5aaf047SAppaRao Puli 
1877e860f15SJohn Edward Broadbent                 nlohmann::json& memberArray =
1887e860f15SJohn Edward Broadbent                     asyncResp->res.jsonValue["Members"];
189e5aaf047SAppaRao Puli 
190b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
191b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
192b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
1937e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members@odata.count"] =
1947e860f15SJohn Edward Broadbent                     subscripIds.size();
195b52664e2SAppaRao Puli 
196b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
197e5aaf047SAppaRao Puli                 {
198e5aaf047SAppaRao Puli                     memberArray.push_back(
199e5aaf047SAppaRao Puli                         {{"@odata.id",
200b52664e2SAppaRao Puli                           "/redfish/v1/EventService/Subscriptions/" + id}});
201e5aaf047SAppaRao Puli                 }
2027e860f15SJohn Edward Broadbent             });
2037e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
2047eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
205*fffb8c1fSEd Tanous         .methods(
206*fffb8c1fSEd Tanous             boost::beast::http::verb::
207*fffb8c1fSEd Tanous                 post)([](const crow::Request& req,
2087e860f15SJohn Edward Broadbent                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
209*fffb8c1fSEd Tanous             if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
210*fffb8c1fSEd Tanous                 maxNoOfSubscriptions)
211e5aaf047SAppaRao Puli             {
212e5aaf047SAppaRao Puli                 messages::eventSubscriptionLimitExceeded(asyncResp->res);
213e5aaf047SAppaRao Puli                 return;
214e5aaf047SAppaRao Puli             }
215e5aaf047SAppaRao Puli             std::string destUrl;
216e5aaf047SAppaRao Puli             std::string protocol;
217e5aaf047SAppaRao Puli             std::optional<std::string> context;
218e5aaf047SAppaRao Puli             std::optional<std::string> subscriptionType;
21923a21a1cSEd Tanous             std::optional<std::string> eventFormatType2;
220e5aaf047SAppaRao Puli             std::optional<std::string> retryPolicy;
221e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> msgIds;
222e5aaf047SAppaRao Puli             std::optional<std::vector<std::string>> regPrefixes;
223e56f254cSSunitha Harish             std::optional<std::vector<std::string>> resTypes;
224e5aaf047SAppaRao Puli             std::optional<std::vector<nlohmann::json>> headers;
225144b6318SAppaRao Puli             std::optional<std::vector<nlohmann::json>> mrdJsonArray;
226e5aaf047SAppaRao Puli 
22715ed6780SWilly Tu             if (!json_util::readJsonPatch(
2287e860f15SJohn Edward Broadbent                     req, asyncResp->res, "Destination", destUrl, "Context",
2297e860f15SJohn Edward Broadbent                     context, "Protocol", protocol, "SubscriptionType",
2307e860f15SJohn Edward Broadbent                     subscriptionType, "EventFormatType", eventFormatType2,
2317e860f15SJohn Edward Broadbent                     "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
232*fffb8c1fSEd Tanous                     "MessageIds", msgIds, "DeliveryRetryPolicy", retryPolicy,
233*fffb8c1fSEd Tanous                     "MetricReportDefinitions", mrdJsonArray, "ResourceTypes",
234*fffb8c1fSEd Tanous                     resTypes))
235e5aaf047SAppaRao Puli             {
236e5aaf047SAppaRao Puli                 return;
237e5aaf047SAppaRao Puli             }
238e5aaf047SAppaRao Puli 
239dd28ba82SAppaRao Puli             if (regPrefixes && msgIds)
240dd28ba82SAppaRao Puli             {
24126f6976fSEd Tanous                 if (!regPrefixes->empty() && !msgIds->empty())
242dd28ba82SAppaRao Puli                 {
2430a4304cfSEd Tanous                     messages::propertyValueConflict(
2440a4304cfSEd Tanous                         asyncResp->res, "MessageIds", "RegistryPrefixes");
245dd28ba82SAppaRao Puli                     return;
246dd28ba82SAppaRao Puli                 }
247dd28ba82SAppaRao Puli             }
248dd28ba82SAppaRao Puli 
249e5aaf047SAppaRao Puli             // Validate the URL using regex expression
250b52664e2SAppaRao Puli             // Format: <protocol>://<host>:<port>/<uri>
251b52664e2SAppaRao Puli             // protocol: http/https
252b52664e2SAppaRao Puli             // host: Exclude ' ', ':', '#', '?'
2534e0453b1SGunnar Mills             // port: Empty or numeric value with ':' separator.
254b52664e2SAppaRao Puli             // uri: Start with '/' and Exclude '#', ' '
255b52664e2SAppaRao Puli             //      Can include query params(ex: '/event?test=1')
256b52664e2SAppaRao Puli             // TODO: Need to validate hostname extensively(as per rfc)
257b52664e2SAppaRao Puli             const std::regex urlRegex(
258b52664e2SAppaRao Puli                 "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
259b52664e2SAppaRao Puli                 "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
260b52664e2SAppaRao Puli             std::cmatch match;
261b52664e2SAppaRao Puli             if (!std::regex_match(destUrl.c_str(), match, urlRegex))
262e5aaf047SAppaRao Puli             {
263e5aaf047SAppaRao Puli                 messages::propertyValueFormatError(asyncResp->res, destUrl,
264e5aaf047SAppaRao Puli                                                    "Destination");
265e5aaf047SAppaRao Puli                 return;
266e5aaf047SAppaRao Puli             }
267b52664e2SAppaRao Puli 
268*fffb8c1fSEd Tanous             std::string uriProto = std::string(match[1].first, match[1].second);
269b52664e2SAppaRao Puli             if (uriProto == "http")
270b52664e2SAppaRao Puli             {
271b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
272b52664e2SAppaRao Puli                 messages::propertyValueFormatError(asyncResp->res, destUrl,
273b52664e2SAppaRao Puli                                                    "Destination");
274b52664e2SAppaRao Puli                 return;
275b52664e2SAppaRao Puli #endif
276b52664e2SAppaRao Puli             }
277b52664e2SAppaRao Puli 
278b52664e2SAppaRao Puli             std::string host = std::string(match[2].first, match[2].second);
279b52664e2SAppaRao Puli             std::string port = std::string(match[3].first, match[3].second);
280b52664e2SAppaRao Puli             std::string path = std::string(match[4].first, match[4].second);
281b52664e2SAppaRao Puli             if (port.empty())
282b52664e2SAppaRao Puli             {
283b52664e2SAppaRao Puli                 if (uriProto == "http")
284b52664e2SAppaRao Puli                 {
285b52664e2SAppaRao Puli                     port = "80";
286b52664e2SAppaRao Puli                 }
287b52664e2SAppaRao Puli                 else
288b52664e2SAppaRao Puli                 {
289b52664e2SAppaRao Puli                     port = "443";
290b52664e2SAppaRao Puli                 }
291b52664e2SAppaRao Puli             }
292b52664e2SAppaRao Puli             if (path.empty())
293b52664e2SAppaRao Puli             {
294b52664e2SAppaRao Puli                 path = "/";
295b52664e2SAppaRao Puli             }
296b52664e2SAppaRao Puli 
297b52664e2SAppaRao Puli             std::shared_ptr<Subscription> subValue =
298b52664e2SAppaRao Puli                 std::make_shared<Subscription>(host, port, path, uriProto);
299b52664e2SAppaRao Puli 
300b52664e2SAppaRao Puli             subValue->destinationUrl = destUrl;
301e5aaf047SAppaRao Puli 
302e5aaf047SAppaRao Puli             if (subscriptionType)
303e5aaf047SAppaRao Puli             {
304e5aaf047SAppaRao Puli                 if (*subscriptionType != "RedfishEvent")
305e5aaf047SAppaRao Puli                 {
306*fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
307*fffb8c1fSEd Tanous                         asyncResp->res, *subscriptionType, "SubscriptionType");
308e5aaf047SAppaRao Puli                     return;
309e5aaf047SAppaRao Puli                 }
310b52664e2SAppaRao Puli                 subValue->subscriptionType = *subscriptionType;
311e5aaf047SAppaRao Puli             }
312e5aaf047SAppaRao Puli             else
313e5aaf047SAppaRao Puli             {
314b52664e2SAppaRao Puli                 subValue->subscriptionType = "RedfishEvent"; // Default
315e5aaf047SAppaRao Puli             }
316e5aaf047SAppaRao Puli 
317e5aaf047SAppaRao Puli             if (protocol != "Redfish")
318e5aaf047SAppaRao Puli             {
319e5aaf047SAppaRao Puli                 messages::propertyValueNotInList(asyncResp->res, protocol,
320e5aaf047SAppaRao Puli                                                  "Protocol");
321e5aaf047SAppaRao Puli                 return;
322e5aaf047SAppaRao Puli             }
323b52664e2SAppaRao Puli             subValue->protocol = protocol;
324e5aaf047SAppaRao Puli 
32523a21a1cSEd Tanous             if (eventFormatType2)
326e5aaf047SAppaRao Puli             {
327e5aaf047SAppaRao Puli                 if (std::find(supportedEvtFormatTypes.begin(),
328e5aaf047SAppaRao Puli                               supportedEvtFormatTypes.end(),
3297e860f15SJohn Edward Broadbent                               *eventFormatType2) ==
3307e860f15SJohn Edward Broadbent                     supportedEvtFormatTypes.end())
331e5aaf047SAppaRao Puli                 {
332*fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
333*fffb8c1fSEd Tanous                         asyncResp->res, *eventFormatType2, "EventFormatType");
334e5aaf047SAppaRao Puli                     return;
335e5aaf047SAppaRao Puli                 }
33623a21a1cSEd Tanous                 subValue->eventFormatType = *eventFormatType2;
337e5aaf047SAppaRao Puli             }
338e5aaf047SAppaRao Puli             else
339e5aaf047SAppaRao Puli             {
340e5aaf047SAppaRao Puli                 // If not specified, use default "Event"
34123a21a1cSEd Tanous                 subValue->eventFormatType = "Event";
342e5aaf047SAppaRao Puli             }
343e5aaf047SAppaRao Puli 
344e5aaf047SAppaRao Puli             if (context)
345e5aaf047SAppaRao Puli             {
346b52664e2SAppaRao Puli                 subValue->customText = *context;
347e5aaf047SAppaRao Puli             }
348e5aaf047SAppaRao Puli 
349e5aaf047SAppaRao Puli             if (headers)
350e5aaf047SAppaRao Puli             {
351601c71aeSEd Tanous                 for (const nlohmann::json& headerChunk : *headers)
352601c71aeSEd Tanous                 {
353601c71aeSEd Tanous                     for (const auto& item : headerChunk.items())
354601c71aeSEd Tanous                     {
355601c71aeSEd Tanous                         const std::string* value =
356601c71aeSEd Tanous                             item.value().get_ptr<const std::string*>();
357601c71aeSEd Tanous                         if (value == nullptr)
358601c71aeSEd Tanous                         {
359601c71aeSEd Tanous                             messages::propertyValueFormatError(
360e662eae8SEd Tanous                                 asyncResp->res, item.value().dump(2, 1),
361601c71aeSEd Tanous                                 "HttpHeaders/" + item.key());
362601c71aeSEd Tanous                             return;
363601c71aeSEd Tanous                         }
364601c71aeSEd Tanous                         subValue->httpHeaders.set(item.key(), *value);
365601c71aeSEd Tanous                     }
366601c71aeSEd Tanous                 }
367e5aaf047SAppaRao Puli             }
368e5aaf047SAppaRao Puli 
369e5aaf047SAppaRao Puli             if (regPrefixes)
370e5aaf047SAppaRao Puli             {
371e5aaf047SAppaRao Puli                 for (const std::string& it : *regPrefixes)
372e5aaf047SAppaRao Puli                 {
373e5aaf047SAppaRao Puli                     if (std::find(supportedRegPrefixes.begin(),
374e5aaf047SAppaRao Puli                                   supportedRegPrefixes.end(),
375e5aaf047SAppaRao Puli                                   it) == supportedRegPrefixes.end())
376e5aaf047SAppaRao Puli                     {
377*fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
378*fffb8c1fSEd Tanous                                                          "RegistryPrefixes");
379e5aaf047SAppaRao Puli                         return;
380e5aaf047SAppaRao Puli                     }
381e5aaf047SAppaRao Puli                 }
382b52664e2SAppaRao Puli                 subValue->registryPrefixes = *regPrefixes;
383e5aaf047SAppaRao Puli             }
384e5aaf047SAppaRao Puli 
385e56f254cSSunitha Harish             if (resTypes)
386e56f254cSSunitha Harish             {
387e56f254cSSunitha Harish                 for (const std::string& it : *resTypes)
388e56f254cSSunitha Harish                 {
389e56f254cSSunitha Harish                     if (std::find(supportedResourceTypes.begin(),
390e56f254cSSunitha Harish                                   supportedResourceTypes.end(),
391e56f254cSSunitha Harish                                   it) == supportedResourceTypes.end())
392e56f254cSSunitha Harish                     {
393e56f254cSSunitha Harish                         messages::propertyValueNotInList(asyncResp->res, it,
394e56f254cSSunitha Harish                                                          "ResourceTypes");
395e56f254cSSunitha Harish                         return;
396e56f254cSSunitha Harish                     }
397e56f254cSSunitha Harish                 }
398e56f254cSSunitha Harish                 subValue->resourceTypes = *resTypes;
399e56f254cSSunitha Harish             }
400e56f254cSSunitha Harish 
401e5aaf047SAppaRao Puli             if (msgIds)
402e5aaf047SAppaRao Puli             {
403b304bd79SP Dheeraj Srujan Kumar                 std::vector<std::string> registryPrefix;
404b304bd79SP Dheeraj Srujan Kumar 
4057e860f15SJohn Edward Broadbent                 // If no registry prefixes are mentioned, consider all
4067e860f15SJohn Edward Broadbent                 // supported prefixes
407b304bd79SP Dheeraj Srujan Kumar                 if (subValue->registryPrefixes.empty())
408b304bd79SP Dheeraj Srujan Kumar                 {
409b304bd79SP Dheeraj Srujan Kumar                     registryPrefix.assign(supportedRegPrefixes.begin(),
410b304bd79SP Dheeraj Srujan Kumar                                           supportedRegPrefixes.end());
411b304bd79SP Dheeraj Srujan Kumar                 }
412b304bd79SP Dheeraj Srujan Kumar                 else
413b304bd79SP Dheeraj Srujan Kumar                 {
414b304bd79SP Dheeraj Srujan Kumar                     registryPrefix = subValue->registryPrefixes;
415b304bd79SP Dheeraj Srujan Kumar                 }
416b304bd79SP Dheeraj Srujan Kumar 
417b304bd79SP Dheeraj Srujan Kumar                 for (const std::string& id : *msgIds)
418b304bd79SP Dheeraj Srujan Kumar                 {
419b304bd79SP Dheeraj Srujan Kumar                     bool validId = false;
420b304bd79SP Dheeraj Srujan Kumar 
421b304bd79SP Dheeraj Srujan Kumar                     // Check for Message ID in each of the selected Registry
422b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& it : registryPrefix)
423b304bd79SP Dheeraj Srujan Kumar                     {
424*fffb8c1fSEd Tanous                         const std::span<const redfish::registries::MessageEntry>
425*fffb8c1fSEd Tanous                             registry =
426*fffb8c1fSEd Tanous                                 redfish::registries::getRegistryFromPrefix(it);
427b304bd79SP Dheeraj Srujan Kumar 
428b304bd79SP Dheeraj Srujan Kumar                         if (std::any_of(
42926702d01SEd Tanous                                 registry.begin(), registry.end(),
430*fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
431*fffb8c1fSEd Tanous                                           messageEntry) {
432*fffb8c1fSEd Tanous                                     return id.compare(messageEntry.first) == 0;
433b304bd79SP Dheeraj Srujan Kumar                                 }))
434b304bd79SP Dheeraj Srujan Kumar                         {
435b304bd79SP Dheeraj Srujan Kumar                             validId = true;
436b304bd79SP Dheeraj Srujan Kumar                             break;
437b304bd79SP Dheeraj Srujan Kumar                         }
438b304bd79SP Dheeraj Srujan Kumar                     }
439b304bd79SP Dheeraj Srujan Kumar 
440b304bd79SP Dheeraj Srujan Kumar                     if (!validId)
441b304bd79SP Dheeraj Srujan Kumar                     {
442b304bd79SP Dheeraj Srujan Kumar                         messages::propertyValueNotInList(asyncResp->res, id,
443b304bd79SP Dheeraj Srujan Kumar                                                          "MessageIds");
444b304bd79SP Dheeraj Srujan Kumar                         return;
445b304bd79SP Dheeraj Srujan Kumar                     }
446b304bd79SP Dheeraj Srujan Kumar                 }
447b304bd79SP Dheeraj Srujan Kumar 
448b52664e2SAppaRao Puli                 subValue->registryMsgIds = *msgIds;
449e5aaf047SAppaRao Puli             }
450e5aaf047SAppaRao Puli 
451e5aaf047SAppaRao Puli             if (retryPolicy)
452e5aaf047SAppaRao Puli             {
453e5aaf047SAppaRao Puli                 if (std::find(supportedRetryPolicies.begin(),
454e5aaf047SAppaRao Puli                               supportedRetryPolicies.end(),
455e5aaf047SAppaRao Puli                               *retryPolicy) == supportedRetryPolicies.end())
456e5aaf047SAppaRao Puli                 {
457*fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
458*fffb8c1fSEd Tanous                         asyncResp->res, *retryPolicy, "DeliveryRetryPolicy");
459e5aaf047SAppaRao Puli                     return;
460e5aaf047SAppaRao Puli                 }
461b52664e2SAppaRao Puli                 subValue->retryPolicy = *retryPolicy;
462e5aaf047SAppaRao Puli             }
463e5aaf047SAppaRao Puli             else
464e5aaf047SAppaRao Puli             {
465e5aaf047SAppaRao Puli                 // Default "TerminateAfterRetries"
466b52664e2SAppaRao Puli                 subValue->retryPolicy = "TerminateAfterRetries";
467e5aaf047SAppaRao Puli             }
468e5aaf047SAppaRao Puli 
469144b6318SAppaRao Puli             if (mrdJsonArray)
470156d6b00SAppaRao Puli             {
471144b6318SAppaRao Puli                 for (nlohmann::json& mrdObj : *mrdJsonArray)
472144b6318SAppaRao Puli                 {
473144b6318SAppaRao Puli                     std::string mrdUri;
474ea2e6eecSWilly Tu 
475ea2e6eecSWilly Tu                     if (!json_util::readJson(mrdObj, asyncResp->res,
476ea2e6eecSWilly Tu                                              "@odata.id", mrdUri))
477ea2e6eecSWilly Tu 
478144b6318SAppaRao Puli                     {
479144b6318SAppaRao Puli                         return;
480144b6318SAppaRao Puli                     }
481ea2e6eecSWilly Tu                     subValue->metricReportDefinitions.emplace_back(mrdUri);
482144b6318SAppaRao Puli                 }
483156d6b00SAppaRao Puli             }
484156d6b00SAppaRao Puli 
485b52664e2SAppaRao Puli             std::string id =
486*fffb8c1fSEd Tanous                 EventServiceManager::getInstance().addSubscription(subValue);
487b52664e2SAppaRao Puli             if (id.empty())
488e5aaf047SAppaRao Puli             {
489e5aaf047SAppaRao Puli                 messages::internalError(asyncResp->res);
490e5aaf047SAppaRao Puli                 return;
491e5aaf047SAppaRao Puli             }
492e5aaf047SAppaRao Puli 
493e5aaf047SAppaRao Puli             messages::created(asyncResp->res);
494e5aaf047SAppaRao Puli             asyncResp->res.addHeader(
495e5aaf047SAppaRao Puli                 "Location", "/redfish/v1/EventService/Subscriptions/" + id);
4967e860f15SJohn Edward Broadbent         });
497e5aaf047SAppaRao Puli }
498e5aaf047SAppaRao Puli 
4997e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
500e5aaf047SAppaRao Puli {
5019d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
502ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
5037e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
5047e860f15SJohn Edward Broadbent             [](const crow::Request&,
5057e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5067e860f15SJohn Edward Broadbent                const std::string& param) {
507b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5087e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
509b52664e2SAppaRao Puli                 if (subValue == nullptr)
510e5aaf047SAppaRao Puli                 {
5117e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5127e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
513e5aaf047SAppaRao Puli                     return;
514e5aaf047SAppaRao Puli                 }
5157e860f15SJohn Edward Broadbent                 const std::string& id = param;
516e5aaf047SAppaRao Puli 
5178d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
5187e860f15SJohn Edward Broadbent                     {"@odata.type",
5197e860f15SJohn Edward Broadbent                      "#EventDestination.v1_7_0.EventDestination"},
520e5aaf047SAppaRao Puli                     {"Protocol", "Redfish"}};
521e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["@odata.id"] =
522e5aaf047SAppaRao Puli                     "/redfish/v1/EventService/Subscriptions/" + id;
523e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Id"] = id;
524e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
5257e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Destination"] =
5267e860f15SJohn Edward Broadbent                     subValue->destinationUrl;
527b52664e2SAppaRao Puli                 asyncResp->res.jsonValue["Context"] = subValue->customText;
528e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["SubscriptionType"] =
529b52664e2SAppaRao Puli                     subValue->subscriptionType;
530ad22fefeSEd Tanous                 asyncResp->res.jsonValue["HttpHeaders"] =
531ad22fefeSEd Tanous                     nlohmann::json::array();
5327e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["EventFormatType"] =
5337e860f15SJohn Edward Broadbent                     subValue->eventFormatType;
534e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["RegistryPrefixes"] =
535b52664e2SAppaRao Puli                     subValue->registryPrefixes;
5367e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["ResourceTypes"] =
5377e860f15SJohn Edward Broadbent                     subValue->resourceTypes;
538e56f254cSSunitha Harish 
5397e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MessageIds"] =
5407e860f15SJohn Edward Broadbent                     subValue->registryMsgIds;
5417e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
5427e860f15SJohn Edward Broadbent                     subValue->retryPolicy;
543144b6318SAppaRao Puli 
544144b6318SAppaRao Puli                 std::vector<nlohmann::json> mrdJsonArray;
545144b6318SAppaRao Puli                 for (const auto& mdrUri : subValue->metricReportDefinitions)
546144b6318SAppaRao Puli                 {
547144b6318SAppaRao Puli                     mrdJsonArray.push_back({{"@odata.id", mdrUri}});
548144b6318SAppaRao Puli                 }
5497e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MetricReportDefinitions"] =
5507e860f15SJohn Edward Broadbent                     mrdJsonArray;
5517e860f15SJohn Edward Broadbent             });
5529d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
553ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
554ed398213SEd Tanous         // ConfigureSelf
5557eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
556ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
557432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
5587e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
5597e860f15SJohn Edward Broadbent             [](const crow::Request& req,
5607e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5617e860f15SJohn Edward Broadbent                const std::string& param) {
562b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5637e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
564b52664e2SAppaRao Puli                 if (subValue == nullptr)
565e5aaf047SAppaRao Puli                 {
5667e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5677e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
568e5aaf047SAppaRao Puli                     return;
569e5aaf047SAppaRao Puli                 }
570e5aaf047SAppaRao Puli 
571e5aaf047SAppaRao Puli                 std::optional<std::string> context;
572e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
573e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
574e5aaf047SAppaRao Puli 
57515ed6780SWilly Tu                 if (!json_util::readJsonPatch(req, asyncResp->res, "Context",
5767e860f15SJohn Edward Broadbent                                               context, "DeliveryRetryPolicy",
57715ed6780SWilly Tu                                               retryPolicy, "HttpHeaders",
57815ed6780SWilly Tu                                               headers))
579e5aaf047SAppaRao Puli                 {
580e5aaf047SAppaRao Puli                     return;
581e5aaf047SAppaRao Puli                 }
582e5aaf047SAppaRao Puli 
583e5aaf047SAppaRao Puli                 if (context)
584e5aaf047SAppaRao Puli                 {
585b52664e2SAppaRao Puli                     subValue->customText = *context;
586e5aaf047SAppaRao Puli                 }
587e5aaf047SAppaRao Puli 
588e5aaf047SAppaRao Puli                 if (headers)
589e5aaf047SAppaRao Puli                 {
590601c71aeSEd Tanous                     boost::beast::http::fields fields;
591601c71aeSEd Tanous                     for (const nlohmann::json& headerChunk : *headers)
592601c71aeSEd Tanous                     {
593601c71aeSEd Tanous                         for (auto& it : headerChunk.items())
594601c71aeSEd Tanous                         {
595601c71aeSEd Tanous                             const std::string* value =
596601c71aeSEd Tanous                                 it.value().get_ptr<const std::string*>();
597601c71aeSEd Tanous                             if (value == nullptr)
598601c71aeSEd Tanous                             {
599601c71aeSEd Tanous                                 messages::propertyValueFormatError(
600601c71aeSEd Tanous                                     asyncResp->res,
601601c71aeSEd Tanous                                     it.value().dump(2, ' ', true),
602601c71aeSEd Tanous                                     "HttpHeaders/" + it.key());
603601c71aeSEd Tanous                                 return;
604601c71aeSEd Tanous                             }
605601c71aeSEd Tanous                             fields.set(it.key(), *value);
606601c71aeSEd Tanous                         }
607601c71aeSEd Tanous                     }
608601c71aeSEd Tanous                     subValue->httpHeaders = fields;
609e5aaf047SAppaRao Puli                 }
610e5aaf047SAppaRao Puli 
611e5aaf047SAppaRao Puli                 if (retryPolicy)
612e5aaf047SAppaRao Puli                 {
613e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
614e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
615e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
616e5aaf047SAppaRao Puli                     {
6177e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
6187e860f15SJohn Edward Broadbent                                                          *retryPolicy,
619e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
620e5aaf047SAppaRao Puli                         return;
621e5aaf047SAppaRao Puli                     }
622b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
623fe44eb0bSAyushi Smriti                     subValue->updateRetryPolicy();
624e5aaf047SAppaRao Puli                 }
625e5aaf047SAppaRao Puli 
626b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
6277e860f15SJohn Edward Broadbent             });
6289d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
629ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
630ed398213SEd Tanous         // ConfigureSelf
6317eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
632ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
633432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
6347e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
6357e860f15SJohn Edward Broadbent             [](const crow::Request&,
6367e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6377e860f15SJohn Edward Broadbent                const std::string& param) {
6387e860f15SJohn Edward Broadbent                 if (!EventServiceManager::getInstance().isSubscriptionExist(
6397e860f15SJohn Edward Broadbent                         param))
640e5aaf047SAppaRao Puli                 {
6417e860f15SJohn Edward Broadbent                     asyncResp->res.result(
6427e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
643e5aaf047SAppaRao Puli                     return;
644e5aaf047SAppaRao Puli                 }
6457e860f15SJohn Edward Broadbent                 EventServiceManager::getInstance().deleteSubscription(param);
6467e860f15SJohn Edward Broadbent             });
647e5aaf047SAppaRao Puli }
648e5aaf047SAppaRao Puli 
649e5aaf047SAppaRao Puli } // namespace redfish
650