xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision 1e270c5f5436a856ed2d43fde2288b87aed23998)
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 
23*1e270c5fSPatrick Williams #include <span>
24*1e270c5fSPatrick 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 
1027e860f15SJohn Edward Broadbent                 if (!json_util::readJson(
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) {
1640b4bdd93SAppaRao Puli                 EventServiceManager::getInstance().sendTestEventLog();
1658d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
1667e860f15SJohn Edward Broadbent             });
167e5aaf047SAppaRao Puli }
168e5aaf047SAppaRao Puli 
1697e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
170e5aaf047SAppaRao Puli {
1717e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions")
172ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
1737e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
1747e860f15SJohn Edward Broadbent             [](const crow::Request&,
1757e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1768d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
177e5aaf047SAppaRao Puli                     {"@odata.type",
178e5aaf047SAppaRao Puli                      "#EventDestinationCollection.EventDestinationCollection"},
179e5aaf047SAppaRao Puli                     {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
180e5aaf047SAppaRao Puli                     {"Name", "Event Destination Collections"}};
181e5aaf047SAppaRao Puli 
1827e860f15SJohn Edward Broadbent                 nlohmann::json& memberArray =
1837e860f15SJohn Edward Broadbent                     asyncResp->res.jsonValue["Members"];
184e5aaf047SAppaRao Puli 
185b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
186b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
187b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
1887e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members@odata.count"] =
1897e860f15SJohn Edward Broadbent                     subscripIds.size();
190b52664e2SAppaRao Puli 
191b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
192e5aaf047SAppaRao Puli                 {
193e5aaf047SAppaRao Puli                     memberArray.push_back(
194e5aaf047SAppaRao Puli                         {{"@odata.id",
195b52664e2SAppaRao Puli                           "/redfish/v1/EventService/Subscriptions/" + id}});
196e5aaf047SAppaRao Puli                 }
1977e860f15SJohn Edward Broadbent             });
1987e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
1997eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
2007e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
2017e860f15SJohn Edward Broadbent             [](const crow::Request& req,
2027e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2037e860f15SJohn Edward Broadbent                 if (EventServiceManager::getInstance()
2047e860f15SJohn Edward Broadbent                         .getNumberOfSubscriptions() >= maxNoOfSubscriptions)
205e5aaf047SAppaRao Puli                 {
206e5aaf047SAppaRao Puli                     messages::eventSubscriptionLimitExceeded(asyncResp->res);
207e5aaf047SAppaRao Puli                     return;
208e5aaf047SAppaRao Puli                 }
209e5aaf047SAppaRao Puli                 std::string destUrl;
210e5aaf047SAppaRao Puli                 std::string protocol;
211e5aaf047SAppaRao Puli                 std::optional<std::string> context;
212e5aaf047SAppaRao Puli                 std::optional<std::string> subscriptionType;
21323a21a1cSEd Tanous                 std::optional<std::string> eventFormatType2;
214e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
215e5aaf047SAppaRao Puli                 std::optional<std::vector<std::string>> msgIds;
216e5aaf047SAppaRao Puli                 std::optional<std::vector<std::string>> regPrefixes;
217e56f254cSSunitha Harish                 std::optional<std::vector<std::string>> resTypes;
218e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
219144b6318SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> mrdJsonArray;
220e5aaf047SAppaRao Puli 
221e5aaf047SAppaRao Puli                 if (!json_util::readJson(
2227e860f15SJohn Edward Broadbent                         req, asyncResp->res, "Destination", destUrl, "Context",
2237e860f15SJohn Edward Broadbent                         context, "Protocol", protocol, "SubscriptionType",
2247e860f15SJohn Edward Broadbent                         subscriptionType, "EventFormatType", eventFormatType2,
2257e860f15SJohn Edward Broadbent                         "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
2267e860f15SJohn Edward Broadbent                         "MessageIds", msgIds, "DeliveryRetryPolicy",
2277e860f15SJohn Edward Broadbent                         retryPolicy, "MetricReportDefinitions", mrdJsonArray,
2287e860f15SJohn Edward Broadbent                         "ResourceTypes", resTypes))
229e5aaf047SAppaRao Puli                 {
230e5aaf047SAppaRao Puli                     return;
231e5aaf047SAppaRao Puli                 }
232e5aaf047SAppaRao Puli 
233dd28ba82SAppaRao Puli                 if (regPrefixes && msgIds)
234dd28ba82SAppaRao Puli                 {
235dd28ba82SAppaRao Puli                     if (regPrefixes->size() && msgIds->size())
236dd28ba82SAppaRao Puli                     {
237dd28ba82SAppaRao Puli                         messages::mutualExclusiveProperties(
238dd28ba82SAppaRao Puli                             asyncResp->res, "RegistryPrefixes", "MessageIds");
239dd28ba82SAppaRao Puli                         return;
240dd28ba82SAppaRao Puli                     }
241dd28ba82SAppaRao Puli                 }
242dd28ba82SAppaRao Puli 
243e5aaf047SAppaRao Puli                 // Validate the URL using regex expression
244b52664e2SAppaRao Puli                 // Format: <protocol>://<host>:<port>/<uri>
245b52664e2SAppaRao Puli                 // protocol: http/https
246b52664e2SAppaRao Puli                 // host: Exclude ' ', ':', '#', '?'
2474e0453b1SGunnar Mills                 // port: Empty or numeric value with ':' separator.
248b52664e2SAppaRao Puli                 // uri: Start with '/' and Exclude '#', ' '
249b52664e2SAppaRao Puli                 //      Can include query params(ex: '/event?test=1')
250b52664e2SAppaRao Puli                 // TODO: Need to validate hostname extensively(as per rfc)
251b52664e2SAppaRao Puli                 const std::regex urlRegex(
252b52664e2SAppaRao Puli                     "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
253b52664e2SAppaRao Puli                     "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
254b52664e2SAppaRao Puli                 std::cmatch match;
255b52664e2SAppaRao Puli                 if (!std::regex_match(destUrl.c_str(), match, urlRegex))
256e5aaf047SAppaRao Puli                 {
257e5aaf047SAppaRao Puli                     messages::propertyValueFormatError(asyncResp->res, destUrl,
258e5aaf047SAppaRao Puli                                                        "Destination");
259e5aaf047SAppaRao Puli                     return;
260e5aaf047SAppaRao Puli                 }
261b52664e2SAppaRao Puli 
2627e860f15SJohn Edward Broadbent                 std::string uriProto =
2637e860f15SJohn Edward Broadbent                     std::string(match[1].first, match[1].second);
264b52664e2SAppaRao Puli                 if (uriProto == "http")
265b52664e2SAppaRao Puli                 {
266b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
267b52664e2SAppaRao Puli                     messages::propertyValueFormatError(asyncResp->res, destUrl,
268b52664e2SAppaRao Puli                                                        "Destination");
269b52664e2SAppaRao Puli                     return;
270b52664e2SAppaRao Puli #endif
271b52664e2SAppaRao Puli                 }
272b52664e2SAppaRao Puli 
273b52664e2SAppaRao Puli                 std::string host = std::string(match[2].first, match[2].second);
274b52664e2SAppaRao Puli                 std::string port = std::string(match[3].first, match[3].second);
275b52664e2SAppaRao Puli                 std::string path = std::string(match[4].first, match[4].second);
276b52664e2SAppaRao Puli                 if (port.empty())
277b52664e2SAppaRao Puli                 {
278b52664e2SAppaRao Puli                     if (uriProto == "http")
279b52664e2SAppaRao Puli                     {
280b52664e2SAppaRao Puli                         port = "80";
281b52664e2SAppaRao Puli                     }
282b52664e2SAppaRao Puli                     else
283b52664e2SAppaRao Puli                     {
284b52664e2SAppaRao Puli                         port = "443";
285b52664e2SAppaRao Puli                     }
286b52664e2SAppaRao Puli                 }
287b52664e2SAppaRao Puli                 if (path.empty())
288b52664e2SAppaRao Puli                 {
289b52664e2SAppaRao Puli                     path = "/";
290b52664e2SAppaRao Puli                 }
291b52664e2SAppaRao Puli 
292b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
293b52664e2SAppaRao Puli                     std::make_shared<Subscription>(host, port, path, uriProto);
294b52664e2SAppaRao Puli 
295b52664e2SAppaRao Puli                 subValue->destinationUrl = destUrl;
296e5aaf047SAppaRao Puli 
297e5aaf047SAppaRao Puli                 if (subscriptionType)
298e5aaf047SAppaRao Puli                 {
299e5aaf047SAppaRao Puli                     if (*subscriptionType != "RedfishEvent")
300e5aaf047SAppaRao Puli                     {
3017e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
3027e860f15SJohn Edward Broadbent                                                          *subscriptionType,
3037e860f15SJohn Edward Broadbent                                                          "SubscriptionType");
304e5aaf047SAppaRao Puli                         return;
305e5aaf047SAppaRao Puli                     }
306b52664e2SAppaRao Puli                     subValue->subscriptionType = *subscriptionType;
307e5aaf047SAppaRao Puli                 }
308e5aaf047SAppaRao Puli                 else
309e5aaf047SAppaRao Puli                 {
310b52664e2SAppaRao Puli                     subValue->subscriptionType = "RedfishEvent"; // Default
311e5aaf047SAppaRao Puli                 }
312e5aaf047SAppaRao Puli 
313e5aaf047SAppaRao Puli                 if (protocol != "Redfish")
314e5aaf047SAppaRao Puli                 {
315e5aaf047SAppaRao Puli                     messages::propertyValueNotInList(asyncResp->res, protocol,
316e5aaf047SAppaRao Puli                                                      "Protocol");
317e5aaf047SAppaRao Puli                     return;
318e5aaf047SAppaRao Puli                 }
319b52664e2SAppaRao Puli                 subValue->protocol = protocol;
320e5aaf047SAppaRao Puli 
32123a21a1cSEd Tanous                 if (eventFormatType2)
322e5aaf047SAppaRao Puli                 {
323e5aaf047SAppaRao Puli                     if (std::find(supportedEvtFormatTypes.begin(),
324e5aaf047SAppaRao Puli                                   supportedEvtFormatTypes.end(),
3257e860f15SJohn Edward Broadbent                                   *eventFormatType2) ==
3267e860f15SJohn Edward Broadbent                         supportedEvtFormatTypes.end())
327e5aaf047SAppaRao Puli                     {
3287e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
3297e860f15SJohn Edward Broadbent                                                          *eventFormatType2,
3307e860f15SJohn Edward Broadbent                                                          "EventFormatType");
331e5aaf047SAppaRao Puli                         return;
332e5aaf047SAppaRao Puli                     }
33323a21a1cSEd Tanous                     subValue->eventFormatType = *eventFormatType2;
334e5aaf047SAppaRao Puli                 }
335e5aaf047SAppaRao Puli                 else
336e5aaf047SAppaRao Puli                 {
337e5aaf047SAppaRao Puli                     // If not specified, use default "Event"
33823a21a1cSEd Tanous                     subValue->eventFormatType = "Event";
339e5aaf047SAppaRao Puli                 }
340e5aaf047SAppaRao Puli 
341e5aaf047SAppaRao Puli                 if (context)
342e5aaf047SAppaRao Puli                 {
343b52664e2SAppaRao Puli                     subValue->customText = *context;
344e5aaf047SAppaRao Puli                 }
345e5aaf047SAppaRao Puli 
346e5aaf047SAppaRao Puli                 if (headers)
347e5aaf047SAppaRao Puli                 {
348601c71aeSEd Tanous                     for (const nlohmann::json& headerChunk : *headers)
349601c71aeSEd Tanous                     {
350601c71aeSEd Tanous                         for (const auto& item : headerChunk.items())
351601c71aeSEd Tanous                         {
352601c71aeSEd Tanous                             const std::string* value =
353601c71aeSEd Tanous                                 item.value().get_ptr<const std::string*>();
354601c71aeSEd Tanous                             if (value == nullptr)
355601c71aeSEd Tanous                             {
356601c71aeSEd Tanous                                 messages::propertyValueFormatError(
357601c71aeSEd Tanous                                     asyncResp->res, item.value().dump(2, true),
358601c71aeSEd Tanous                                     "HttpHeaders/" + item.key());
359601c71aeSEd Tanous                                 return;
360601c71aeSEd Tanous                             }
361601c71aeSEd Tanous                             subValue->httpHeaders.set(item.key(), *value);
362601c71aeSEd Tanous                         }
363601c71aeSEd Tanous                     }
364e5aaf047SAppaRao Puli                 }
365e5aaf047SAppaRao Puli 
366e5aaf047SAppaRao Puli                 if (regPrefixes)
367e5aaf047SAppaRao Puli                 {
368e5aaf047SAppaRao Puli                     for (const std::string& it : *regPrefixes)
369e5aaf047SAppaRao Puli                     {
370e5aaf047SAppaRao Puli                         if (std::find(supportedRegPrefixes.begin(),
371e5aaf047SAppaRao Puli                                       supportedRegPrefixes.end(),
372e5aaf047SAppaRao Puli                                       it) == supportedRegPrefixes.end())
373e5aaf047SAppaRao Puli                         {
3747e860f15SJohn Edward Broadbent                             messages::propertyValueNotInList(
3757e860f15SJohn Edward Broadbent                                 asyncResp->res, it, "RegistryPrefixes");
376e5aaf047SAppaRao Puli                             return;
377e5aaf047SAppaRao Puli                         }
378e5aaf047SAppaRao Puli                     }
379b52664e2SAppaRao Puli                     subValue->registryPrefixes = *regPrefixes;
380e5aaf047SAppaRao Puli                 }
381e5aaf047SAppaRao Puli 
382e56f254cSSunitha Harish                 if (resTypes)
383e56f254cSSunitha Harish                 {
384e56f254cSSunitha Harish                     for (const std::string& it : *resTypes)
385e56f254cSSunitha Harish                     {
386e56f254cSSunitha Harish                         if (std::find(supportedResourceTypes.begin(),
387e56f254cSSunitha Harish                                       supportedResourceTypes.end(),
388e56f254cSSunitha Harish                                       it) == supportedResourceTypes.end())
389e56f254cSSunitha Harish                         {
390e56f254cSSunitha Harish                             messages::propertyValueNotInList(asyncResp->res, it,
391e56f254cSSunitha Harish                                                              "ResourceTypes");
392e56f254cSSunitha Harish                             return;
393e56f254cSSunitha Harish                         }
394e56f254cSSunitha Harish                     }
395e56f254cSSunitha Harish                     subValue->resourceTypes = *resTypes;
396e56f254cSSunitha Harish                 }
397e56f254cSSunitha Harish 
398e5aaf047SAppaRao Puli                 if (msgIds)
399e5aaf047SAppaRao Puli                 {
400b304bd79SP Dheeraj Srujan Kumar                     std::vector<std::string> registryPrefix;
401b304bd79SP Dheeraj Srujan Kumar 
4027e860f15SJohn Edward Broadbent                     // If no registry prefixes are mentioned, consider all
4037e860f15SJohn Edward Broadbent                     // supported prefixes
404b304bd79SP Dheeraj Srujan Kumar                     if (subValue->registryPrefixes.empty())
405b304bd79SP Dheeraj Srujan Kumar                     {
406b304bd79SP Dheeraj Srujan Kumar                         registryPrefix.assign(supportedRegPrefixes.begin(),
407b304bd79SP Dheeraj Srujan Kumar                                               supportedRegPrefixes.end());
408b304bd79SP Dheeraj Srujan Kumar                     }
409b304bd79SP Dheeraj Srujan Kumar                     else
410b304bd79SP Dheeraj Srujan Kumar                     {
411b304bd79SP Dheeraj Srujan Kumar                         registryPrefix = subValue->registryPrefixes;
412b304bd79SP Dheeraj Srujan Kumar                     }
413b304bd79SP Dheeraj Srujan Kumar 
414b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& id : *msgIds)
415b304bd79SP Dheeraj Srujan Kumar                     {
416b304bd79SP Dheeraj Srujan Kumar                         bool validId = false;
417b304bd79SP Dheeraj Srujan Kumar 
418b304bd79SP Dheeraj Srujan Kumar                         // Check for Message ID in each of the selected Registry
419b304bd79SP Dheeraj Srujan Kumar                         for (const std::string& it : registryPrefix)
420b304bd79SP Dheeraj Srujan Kumar                         {
42126702d01SEd Tanous                             const std::span<
422b304bd79SP Dheeraj Srujan Kumar                                 const redfish::message_registries::MessageEntry>
4237e860f15SJohn Edward Broadbent                                 registry = redfish::message_registries::
4247e860f15SJohn Edward Broadbent                                     getRegistryFromPrefix(it);
425b304bd79SP Dheeraj Srujan Kumar 
426b304bd79SP Dheeraj Srujan Kumar                             if (std::any_of(
42726702d01SEd Tanous                                     registry.begin(), registry.end(),
4287e860f15SJohn Edward Broadbent                                     [&id](const redfish::message_registries::
4297e860f15SJohn Edward Broadbent                                               MessageEntry& messageEntry) {
430b304bd79SP Dheeraj Srujan Kumar                                         return !id.compare(messageEntry.first);
431b304bd79SP Dheeraj Srujan Kumar                                     }))
432b304bd79SP Dheeraj Srujan Kumar                             {
433b304bd79SP Dheeraj Srujan Kumar                                 validId = true;
434b304bd79SP Dheeraj Srujan Kumar                                 break;
435b304bd79SP Dheeraj Srujan Kumar                             }
436b304bd79SP Dheeraj Srujan Kumar                         }
437b304bd79SP Dheeraj Srujan Kumar 
438b304bd79SP Dheeraj Srujan Kumar                         if (!validId)
439b304bd79SP Dheeraj Srujan Kumar                         {
440b304bd79SP Dheeraj Srujan Kumar                             messages::propertyValueNotInList(asyncResp->res, id,
441b304bd79SP Dheeraj Srujan Kumar                                                              "MessageIds");
442b304bd79SP Dheeraj Srujan Kumar                             return;
443b304bd79SP Dheeraj Srujan Kumar                         }
444b304bd79SP Dheeraj Srujan Kumar                     }
445b304bd79SP Dheeraj Srujan Kumar 
446b52664e2SAppaRao Puli                     subValue->registryMsgIds = *msgIds;
447e5aaf047SAppaRao Puli                 }
448e5aaf047SAppaRao Puli 
449e5aaf047SAppaRao Puli                 if (retryPolicy)
450e5aaf047SAppaRao Puli                 {
451e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
452e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
453e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
454e5aaf047SAppaRao Puli                     {
4557e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
4567e860f15SJohn Edward Broadbent                                                          *retryPolicy,
457e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
458e5aaf047SAppaRao Puli                         return;
459e5aaf047SAppaRao Puli                     }
460b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
461e5aaf047SAppaRao Puli                 }
462e5aaf047SAppaRao Puli                 else
463e5aaf047SAppaRao Puli                 {
464e5aaf047SAppaRao Puli                     // Default "TerminateAfterRetries"
465b52664e2SAppaRao Puli                     subValue->retryPolicy = "TerminateAfterRetries";
466e5aaf047SAppaRao Puli                 }
467e5aaf047SAppaRao Puli 
468144b6318SAppaRao Puli                 if (mrdJsonArray)
469156d6b00SAppaRao Puli                 {
470144b6318SAppaRao Puli                     for (nlohmann::json& mrdObj : *mrdJsonArray)
471144b6318SAppaRao Puli                     {
472144b6318SAppaRao Puli                         std::string mrdUri;
4737e860f15SJohn Edward Broadbent                         if (json_util::getValueFromJsonObject(
4747e860f15SJohn Edward Broadbent                                 mrdObj, "@odata.id", mrdUri))
475144b6318SAppaRao Puli                         {
4767e860f15SJohn Edward Broadbent                             subValue->metricReportDefinitions.emplace_back(
4777e860f15SJohn Edward Broadbent                                 mrdUri);
478144b6318SAppaRao Puli                         }
479144b6318SAppaRao Puli                         else
480144b6318SAppaRao Puli                         {
481144b6318SAppaRao Puli                             messages::propertyValueFormatError(
48271f52d96SEd Tanous                                 asyncResp->res,
4837e860f15SJohn Edward Broadbent                                 mrdObj.dump(
4847e860f15SJohn Edward Broadbent                                     2, ' ', true,
48571f52d96SEd Tanous                                     nlohmann::json::error_handler_t::replace),
486144b6318SAppaRao Puli                                 "MetricReportDefinitions");
487144b6318SAppaRao Puli                             return;
488144b6318SAppaRao Puli                         }
489144b6318SAppaRao Puli                     }
490156d6b00SAppaRao Puli                 }
491156d6b00SAppaRao Puli 
492b52664e2SAppaRao Puli                 std::string id =
4937e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().addSubscription(
4947e860f15SJohn Edward Broadbent                         subValue);
495b52664e2SAppaRao Puli                 if (id.empty())
496e5aaf047SAppaRao Puli                 {
497e5aaf047SAppaRao Puli                     messages::internalError(asyncResp->res);
498e5aaf047SAppaRao Puli                     return;
499e5aaf047SAppaRao Puli                 }
500e5aaf047SAppaRao Puli 
501e5aaf047SAppaRao Puli                 messages::created(asyncResp->res);
502e5aaf047SAppaRao Puli                 asyncResp->res.addHeader(
503e5aaf047SAppaRao Puli                     "Location", "/redfish/v1/EventService/Subscriptions/" + id);
5047e860f15SJohn Edward Broadbent             });
505e5aaf047SAppaRao Puli }
506e5aaf047SAppaRao Puli 
5077e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
508e5aaf047SAppaRao Puli {
5099d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
510ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
5117e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
5127e860f15SJohn Edward Broadbent             [](const crow::Request&,
5137e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5147e860f15SJohn Edward Broadbent                const std::string& param) {
515b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5167e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
517b52664e2SAppaRao Puli                 if (subValue == nullptr)
518e5aaf047SAppaRao Puli                 {
5197e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5207e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
521e5aaf047SAppaRao Puli                     return;
522e5aaf047SAppaRao Puli                 }
5237e860f15SJohn Edward Broadbent                 const std::string& id = param;
524e5aaf047SAppaRao Puli 
5258d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
5267e860f15SJohn Edward Broadbent                     {"@odata.type",
5277e860f15SJohn Edward Broadbent                      "#EventDestination.v1_7_0.EventDestination"},
528e5aaf047SAppaRao Puli                     {"Protocol", "Redfish"}};
529e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["@odata.id"] =
530e5aaf047SAppaRao Puli                     "/redfish/v1/EventService/Subscriptions/" + id;
531e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Id"] = id;
532e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
5337e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Destination"] =
5347e860f15SJohn Edward Broadbent                     subValue->destinationUrl;
535b52664e2SAppaRao Puli                 asyncResp->res.jsonValue["Context"] = subValue->customText;
536e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["SubscriptionType"] =
537b52664e2SAppaRao Puli                     subValue->subscriptionType;
538ad22fefeSEd Tanous                 asyncResp->res.jsonValue["HttpHeaders"] =
539ad22fefeSEd Tanous                     nlohmann::json::array();
5407e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["EventFormatType"] =
5417e860f15SJohn Edward Broadbent                     subValue->eventFormatType;
542e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["RegistryPrefixes"] =
543b52664e2SAppaRao Puli                     subValue->registryPrefixes;
5447e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["ResourceTypes"] =
5457e860f15SJohn Edward Broadbent                     subValue->resourceTypes;
546e56f254cSSunitha Harish 
5477e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MessageIds"] =
5487e860f15SJohn Edward Broadbent                     subValue->registryMsgIds;
5497e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
5507e860f15SJohn Edward Broadbent                     subValue->retryPolicy;
551144b6318SAppaRao Puli 
552144b6318SAppaRao Puli                 std::vector<nlohmann::json> mrdJsonArray;
553144b6318SAppaRao Puli                 for (const auto& mdrUri : subValue->metricReportDefinitions)
554144b6318SAppaRao Puli                 {
555144b6318SAppaRao Puli                     mrdJsonArray.push_back({{"@odata.id", mdrUri}});
556144b6318SAppaRao Puli                 }
5577e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MetricReportDefinitions"] =
5587e860f15SJohn Edward Broadbent                     mrdJsonArray;
5597e860f15SJohn Edward Broadbent             });
5609d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
561ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
562ed398213SEd Tanous         // ConfigureSelf
5637eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
564ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
565432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
5667e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
5677e860f15SJohn Edward Broadbent             [](const crow::Request& req,
5687e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5697e860f15SJohn Edward Broadbent                const std::string& param) {
570b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5717e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
572b52664e2SAppaRao Puli                 if (subValue == nullptr)
573e5aaf047SAppaRao Puli                 {
5747e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5757e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
576e5aaf047SAppaRao Puli                     return;
577e5aaf047SAppaRao Puli                 }
578e5aaf047SAppaRao Puli 
579e5aaf047SAppaRao Puli                 std::optional<std::string> context;
580e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
581e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
582e5aaf047SAppaRao Puli 
5837e860f15SJohn Edward Broadbent                 if (!json_util::readJson(req, asyncResp->res, "Context",
5847e860f15SJohn Edward Broadbent                                          context, "DeliveryRetryPolicy",
5857e860f15SJohn Edward Broadbent                                          retryPolicy, "HttpHeaders", headers))
586e5aaf047SAppaRao Puli                 {
587e5aaf047SAppaRao Puli                     return;
588e5aaf047SAppaRao Puli                 }
589e5aaf047SAppaRao Puli 
590e5aaf047SAppaRao Puli                 if (context)
591e5aaf047SAppaRao Puli                 {
592b52664e2SAppaRao Puli                     subValue->customText = *context;
593e5aaf047SAppaRao Puli                 }
594e5aaf047SAppaRao Puli 
595e5aaf047SAppaRao Puli                 if (headers)
596e5aaf047SAppaRao Puli                 {
597601c71aeSEd Tanous                     boost::beast::http::fields fields;
598601c71aeSEd Tanous                     for (const nlohmann::json& headerChunk : *headers)
599601c71aeSEd Tanous                     {
600601c71aeSEd Tanous                         for (auto& it : headerChunk.items())
601601c71aeSEd Tanous                         {
602601c71aeSEd Tanous                             const std::string* value =
603601c71aeSEd Tanous                                 it.value().get_ptr<const std::string*>();
604601c71aeSEd Tanous                             if (value == nullptr)
605601c71aeSEd Tanous                             {
606601c71aeSEd Tanous                                 messages::propertyValueFormatError(
607601c71aeSEd Tanous                                     asyncResp->res,
608601c71aeSEd Tanous                                     it.value().dump(2, ' ', true),
609601c71aeSEd Tanous                                     "HttpHeaders/" + it.key());
610601c71aeSEd Tanous                                 return;
611601c71aeSEd Tanous                             }
612601c71aeSEd Tanous                             fields.set(it.key(), *value);
613601c71aeSEd Tanous                         }
614601c71aeSEd Tanous                     }
615601c71aeSEd Tanous                     subValue->httpHeaders = fields;
616e5aaf047SAppaRao Puli                 }
617e5aaf047SAppaRao Puli 
618e5aaf047SAppaRao Puli                 if (retryPolicy)
619e5aaf047SAppaRao Puli                 {
620e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
621e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
622e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
623e5aaf047SAppaRao Puli                     {
6247e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
6257e860f15SJohn Edward Broadbent                                                          *retryPolicy,
626e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
627e5aaf047SAppaRao Puli                         return;
628e5aaf047SAppaRao Puli                     }
629b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
630fe44eb0bSAyushi Smriti                     subValue->updateRetryPolicy();
631e5aaf047SAppaRao Puli                 }
632e5aaf047SAppaRao Puli 
633b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
6347e860f15SJohn Edward Broadbent             });
6359d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
636ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
637ed398213SEd Tanous         // ConfigureSelf
6387eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
639ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
640432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
6417e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
6427e860f15SJohn Edward Broadbent             [](const crow::Request&,
6437e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6447e860f15SJohn Edward Broadbent                const std::string& param) {
6457e860f15SJohn Edward Broadbent                 if (!EventServiceManager::getInstance().isSubscriptionExist(
6467e860f15SJohn Edward Broadbent                         param))
647e5aaf047SAppaRao Puli                 {
6487e860f15SJohn Edward Broadbent                     asyncResp->res.result(
6497e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
650e5aaf047SAppaRao Puli                     return;
651e5aaf047SAppaRao Puli                 }
6527e860f15SJohn Edward Broadbent                 EventServiceManager::getInstance().deleteSubscription(param);
6537e860f15SJohn Edward Broadbent             });
654e5aaf047SAppaRao Puli }
655e5aaf047SAppaRao Puli 
656e5aaf047SAppaRao Puli } // namespace redfish
657