xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision 55f79e6fe156505cdaddd521212a29b2a977193a)
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)
205fffb8c1fSEd Tanous         .methods(
206fffb8c1fSEd Tanous             boost::beast::http::verb::
207fffb8c1fSEd Tanous                 post)([](const crow::Request& req,
2087e860f15SJohn Edward Broadbent                          const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
209fffb8c1fSEd Tanous             if (EventServiceManager::getInstance().getNumberOfSubscriptions() >=
210fffb8c1fSEd 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,
232fffb8c1fSEd Tanous                     "MessageIds", msgIds, "DeliveryRetryPolicy", retryPolicy,
233fffb8c1fSEd Tanous                     "MetricReportDefinitions", mrdJsonArray, "ResourceTypes",
234fffb8c1fSEd 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 
268fffb8c1fSEd 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                 {
306fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
307fffb8c1fSEd 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                 {
332fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
333fffb8c1fSEd 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                     {
377fffb8c1fSEd Tanous                         messages::propertyValueNotInList(asyncResp->res, it,
378fffb8c1fSEd 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                     {
424fffb8c1fSEd Tanous                         const std::span<const redfish::registries::MessageEntry>
425fffb8c1fSEd Tanous                             registry =
426fffb8c1fSEd Tanous                                 redfish::registries::getRegistryFromPrefix(it);
427b304bd79SP Dheeraj Srujan Kumar 
428b304bd79SP Dheeraj Srujan Kumar                         if (std::any_of(
42926702d01SEd Tanous                                 registry.begin(), registry.end(),
430fffb8c1fSEd Tanous                                 [&id](const redfish::registries::MessageEntry&
431fffb8c1fSEd Tanous                                           messageEntry) {
432*55f79e6fSEd Tanous                                     return id == messageEntry.first;
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                 {
457fffb8c1fSEd Tanous                     messages::propertyValueNotInList(
458fffb8c1fSEd 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 =
486fffb8c1fSEd 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