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 
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) {
164*6ba8c82eSsunharis_in                 if (!EventServiceManager::getInstance().sendTestEventLog())
165*6ba8c82eSsunharis_in                 {
166*6ba8c82eSsunharis_in                     messages::serviceDisabled(asyncResp->res,
167*6ba8c82eSsunharis_in                                               "/redfish/v1/EventService/");
168*6ba8c82eSsunharis_in                     return;
169*6ba8c82eSsunharis_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 {
1767e860f15SJohn Edward Broadbent     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)
2057e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
2067e860f15SJohn Edward Broadbent             [](const crow::Request& req,
2077e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2087e860f15SJohn Edward Broadbent                 if (EventServiceManager::getInstance()
2097e860f15SJohn Edward Broadbent                         .getNumberOfSubscriptions() >= maxNoOfSubscriptions)
210e5aaf047SAppaRao Puli                 {
211e5aaf047SAppaRao Puli                     messages::eventSubscriptionLimitExceeded(asyncResp->res);
212e5aaf047SAppaRao Puli                     return;
213e5aaf047SAppaRao Puli                 }
214e5aaf047SAppaRao Puli                 std::string destUrl;
215e5aaf047SAppaRao Puli                 std::string protocol;
216e5aaf047SAppaRao Puli                 std::optional<std::string> context;
217e5aaf047SAppaRao Puli                 std::optional<std::string> subscriptionType;
21823a21a1cSEd Tanous                 std::optional<std::string> eventFormatType2;
219e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
220e5aaf047SAppaRao Puli                 std::optional<std::vector<std::string>> msgIds;
221e5aaf047SAppaRao Puli                 std::optional<std::vector<std::string>> regPrefixes;
222e56f254cSSunitha Harish                 std::optional<std::vector<std::string>> resTypes;
223e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
224144b6318SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> mrdJsonArray;
225e5aaf047SAppaRao Puli 
226e5aaf047SAppaRao Puli                 if (!json_util::readJson(
2277e860f15SJohn Edward Broadbent                         req, asyncResp->res, "Destination", destUrl, "Context",
2287e860f15SJohn Edward Broadbent                         context, "Protocol", protocol, "SubscriptionType",
2297e860f15SJohn Edward Broadbent                         subscriptionType, "EventFormatType", eventFormatType2,
2307e860f15SJohn Edward Broadbent                         "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
2317e860f15SJohn Edward Broadbent                         "MessageIds", msgIds, "DeliveryRetryPolicy",
2327e860f15SJohn Edward Broadbent                         retryPolicy, "MetricReportDefinitions", mrdJsonArray,
2337e860f15SJohn Edward Broadbent                         "ResourceTypes", resTypes))
234e5aaf047SAppaRao Puli                 {
235e5aaf047SAppaRao Puli                     return;
236e5aaf047SAppaRao Puli                 }
237e5aaf047SAppaRao Puli 
238dd28ba82SAppaRao Puli                 if (regPrefixes && msgIds)
239dd28ba82SAppaRao Puli                 {
24026f6976fSEd Tanous                     if (!regPrefixes->empty() && !msgIds->empty())
241dd28ba82SAppaRao Puli                     {
242dd28ba82SAppaRao Puli                         messages::mutualExclusiveProperties(
243dd28ba82SAppaRao Puli                             asyncResp->res, "RegistryPrefixes", "MessageIds");
244dd28ba82SAppaRao Puli                         return;
245dd28ba82SAppaRao Puli                     }
246dd28ba82SAppaRao Puli                 }
247dd28ba82SAppaRao Puli 
248e5aaf047SAppaRao Puli                 // Validate the URL using regex expression
249b52664e2SAppaRao Puli                 // Format: <protocol>://<host>:<port>/<uri>
250b52664e2SAppaRao Puli                 // protocol: http/https
251b52664e2SAppaRao Puli                 // host: Exclude ' ', ':', '#', '?'
2524e0453b1SGunnar Mills                 // port: Empty or numeric value with ':' separator.
253b52664e2SAppaRao Puli                 // uri: Start with '/' and Exclude '#', ' '
254b52664e2SAppaRao Puli                 //      Can include query params(ex: '/event?test=1')
255b52664e2SAppaRao Puli                 // TODO: Need to validate hostname extensively(as per rfc)
256b52664e2SAppaRao Puli                 const std::regex urlRegex(
257b52664e2SAppaRao Puli                     "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
258b52664e2SAppaRao Puli                     "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
259b52664e2SAppaRao Puli                 std::cmatch match;
260b52664e2SAppaRao Puli                 if (!std::regex_match(destUrl.c_str(), match, urlRegex))
261e5aaf047SAppaRao Puli                 {
262e5aaf047SAppaRao Puli                     messages::propertyValueFormatError(asyncResp->res, destUrl,
263e5aaf047SAppaRao Puli                                                        "Destination");
264e5aaf047SAppaRao Puli                     return;
265e5aaf047SAppaRao Puli                 }
266b52664e2SAppaRao Puli 
2677e860f15SJohn Edward Broadbent                 std::string uriProto =
2687e860f15SJohn Edward Broadbent                     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                     {
3067e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
3077e860f15SJohn Edward Broadbent                                                          *subscriptionType,
3087e860f15SJohn Edward Broadbent                                                          "SubscriptionType");
309e5aaf047SAppaRao Puli                         return;
310e5aaf047SAppaRao Puli                     }
311b52664e2SAppaRao Puli                     subValue->subscriptionType = *subscriptionType;
312e5aaf047SAppaRao Puli                 }
313e5aaf047SAppaRao Puli                 else
314e5aaf047SAppaRao Puli                 {
315b52664e2SAppaRao Puli                     subValue->subscriptionType = "RedfishEvent"; // Default
316e5aaf047SAppaRao Puli                 }
317e5aaf047SAppaRao Puli 
318e5aaf047SAppaRao Puli                 if (protocol != "Redfish")
319e5aaf047SAppaRao Puli                 {
320e5aaf047SAppaRao Puli                     messages::propertyValueNotInList(asyncResp->res, protocol,
321e5aaf047SAppaRao Puli                                                      "Protocol");
322e5aaf047SAppaRao Puli                     return;
323e5aaf047SAppaRao Puli                 }
324b52664e2SAppaRao Puli                 subValue->protocol = protocol;
325e5aaf047SAppaRao Puli 
32623a21a1cSEd Tanous                 if (eventFormatType2)
327e5aaf047SAppaRao Puli                 {
328e5aaf047SAppaRao Puli                     if (std::find(supportedEvtFormatTypes.begin(),
329e5aaf047SAppaRao Puli                                   supportedEvtFormatTypes.end(),
3307e860f15SJohn Edward Broadbent                                   *eventFormatType2) ==
3317e860f15SJohn Edward Broadbent                         supportedEvtFormatTypes.end())
332e5aaf047SAppaRao Puli                     {
3337e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
3347e860f15SJohn Edward Broadbent                                                          *eventFormatType2,
3357e860f15SJohn Edward Broadbent                                                          "EventFormatType");
336e5aaf047SAppaRao Puli                         return;
337e5aaf047SAppaRao Puli                     }
33823a21a1cSEd Tanous                     subValue->eventFormatType = *eventFormatType2;
339e5aaf047SAppaRao Puli                 }
340e5aaf047SAppaRao Puli                 else
341e5aaf047SAppaRao Puli                 {
342e5aaf047SAppaRao Puli                     // If not specified, use default "Event"
34323a21a1cSEd Tanous                     subValue->eventFormatType = "Event";
344e5aaf047SAppaRao Puli                 }
345e5aaf047SAppaRao Puli 
346e5aaf047SAppaRao Puli                 if (context)
347e5aaf047SAppaRao Puli                 {
348b52664e2SAppaRao Puli                     subValue->customText = *context;
349e5aaf047SAppaRao Puli                 }
350e5aaf047SAppaRao Puli 
351e5aaf047SAppaRao Puli                 if (headers)
352e5aaf047SAppaRao Puli                 {
353601c71aeSEd Tanous                     for (const nlohmann::json& headerChunk : *headers)
354601c71aeSEd Tanous                     {
355601c71aeSEd Tanous                         for (const auto& item : headerChunk.items())
356601c71aeSEd Tanous                         {
357601c71aeSEd Tanous                             const std::string* value =
358601c71aeSEd Tanous                                 item.value().get_ptr<const std::string*>();
359601c71aeSEd Tanous                             if (value == nullptr)
360601c71aeSEd Tanous                             {
361601c71aeSEd Tanous                                 messages::propertyValueFormatError(
362601c71aeSEd Tanous                                     asyncResp->res, item.value().dump(2, true),
363601c71aeSEd Tanous                                     "HttpHeaders/" + item.key());
364601c71aeSEd Tanous                                 return;
365601c71aeSEd Tanous                             }
366601c71aeSEd Tanous                             subValue->httpHeaders.set(item.key(), *value);
367601c71aeSEd Tanous                         }
368601c71aeSEd Tanous                     }
369e5aaf047SAppaRao Puli                 }
370e5aaf047SAppaRao Puli 
371e5aaf047SAppaRao Puli                 if (regPrefixes)
372e5aaf047SAppaRao Puli                 {
373e5aaf047SAppaRao Puli                     for (const std::string& it : *regPrefixes)
374e5aaf047SAppaRao Puli                     {
375e5aaf047SAppaRao Puli                         if (std::find(supportedRegPrefixes.begin(),
376e5aaf047SAppaRao Puli                                       supportedRegPrefixes.end(),
377e5aaf047SAppaRao Puli                                       it) == supportedRegPrefixes.end())
378e5aaf047SAppaRao Puli                         {
3797e860f15SJohn Edward Broadbent                             messages::propertyValueNotInList(
3807e860f15SJohn Edward Broadbent                                 asyncResp->res, it, "RegistryPrefixes");
381e5aaf047SAppaRao Puli                             return;
382e5aaf047SAppaRao Puli                         }
383e5aaf047SAppaRao Puli                     }
384b52664e2SAppaRao Puli                     subValue->registryPrefixes = *regPrefixes;
385e5aaf047SAppaRao Puli                 }
386e5aaf047SAppaRao Puli 
387e56f254cSSunitha Harish                 if (resTypes)
388e56f254cSSunitha Harish                 {
389e56f254cSSunitha Harish                     for (const std::string& it : *resTypes)
390e56f254cSSunitha Harish                     {
391e56f254cSSunitha Harish                         if (std::find(supportedResourceTypes.begin(),
392e56f254cSSunitha Harish                                       supportedResourceTypes.end(),
393e56f254cSSunitha Harish                                       it) == supportedResourceTypes.end())
394e56f254cSSunitha Harish                         {
395e56f254cSSunitha Harish                             messages::propertyValueNotInList(asyncResp->res, it,
396e56f254cSSunitha Harish                                                              "ResourceTypes");
397e56f254cSSunitha Harish                             return;
398e56f254cSSunitha Harish                         }
399e56f254cSSunitha Harish                     }
400e56f254cSSunitha Harish                     subValue->resourceTypes = *resTypes;
401e56f254cSSunitha Harish                 }
402e56f254cSSunitha Harish 
403e5aaf047SAppaRao Puli                 if (msgIds)
404e5aaf047SAppaRao Puli                 {
405b304bd79SP Dheeraj Srujan Kumar                     std::vector<std::string> registryPrefix;
406b304bd79SP Dheeraj Srujan Kumar 
4077e860f15SJohn Edward Broadbent                     // If no registry prefixes are mentioned, consider all
4087e860f15SJohn Edward Broadbent                     // supported prefixes
409b304bd79SP Dheeraj Srujan Kumar                     if (subValue->registryPrefixes.empty())
410b304bd79SP Dheeraj Srujan Kumar                     {
411b304bd79SP Dheeraj Srujan Kumar                         registryPrefix.assign(supportedRegPrefixes.begin(),
412b304bd79SP Dheeraj Srujan Kumar                                               supportedRegPrefixes.end());
413b304bd79SP Dheeraj Srujan Kumar                     }
414b304bd79SP Dheeraj Srujan Kumar                     else
415b304bd79SP Dheeraj Srujan Kumar                     {
416b304bd79SP Dheeraj Srujan Kumar                         registryPrefix = subValue->registryPrefixes;
417b304bd79SP Dheeraj Srujan Kumar                     }
418b304bd79SP Dheeraj Srujan Kumar 
419b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& id : *msgIds)
420b304bd79SP Dheeraj Srujan Kumar                     {
421b304bd79SP Dheeraj Srujan Kumar                         bool validId = false;
422b304bd79SP Dheeraj Srujan Kumar 
423b304bd79SP Dheeraj Srujan Kumar                         // Check for Message ID in each of the selected Registry
424b304bd79SP Dheeraj Srujan Kumar                         for (const std::string& it : registryPrefix)
425b304bd79SP Dheeraj Srujan Kumar                         {
42626702d01SEd Tanous                             const std::span<
427b304bd79SP Dheeraj Srujan Kumar                                 const redfish::message_registries::MessageEntry>
4287e860f15SJohn Edward Broadbent                                 registry = redfish::message_registries::
4297e860f15SJohn Edward Broadbent                                     getRegistryFromPrefix(it);
430b304bd79SP Dheeraj Srujan Kumar 
431b304bd79SP Dheeraj Srujan Kumar                             if (std::any_of(
43226702d01SEd Tanous                                     registry.begin(), registry.end(),
4337e860f15SJohn Edward Broadbent                                     [&id](const redfish::message_registries::
4347e860f15SJohn Edward Broadbent                                               MessageEntry& messageEntry) {
435b304bd79SP Dheeraj Srujan Kumar                                         return !id.compare(messageEntry.first);
436b304bd79SP Dheeraj Srujan Kumar                                     }))
437b304bd79SP Dheeraj Srujan Kumar                             {
438b304bd79SP Dheeraj Srujan Kumar                                 validId = true;
439b304bd79SP Dheeraj Srujan Kumar                                 break;
440b304bd79SP Dheeraj Srujan Kumar                             }
441b304bd79SP Dheeraj Srujan Kumar                         }
442b304bd79SP Dheeraj Srujan Kumar 
443b304bd79SP Dheeraj Srujan Kumar                         if (!validId)
444b304bd79SP Dheeraj Srujan Kumar                         {
445b304bd79SP Dheeraj Srujan Kumar                             messages::propertyValueNotInList(asyncResp->res, id,
446b304bd79SP Dheeraj Srujan Kumar                                                              "MessageIds");
447b304bd79SP Dheeraj Srujan Kumar                             return;
448b304bd79SP Dheeraj Srujan Kumar                         }
449b304bd79SP Dheeraj Srujan Kumar                     }
450b304bd79SP Dheeraj Srujan Kumar 
451b52664e2SAppaRao Puli                     subValue->registryMsgIds = *msgIds;
452e5aaf047SAppaRao Puli                 }
453e5aaf047SAppaRao Puli 
454e5aaf047SAppaRao Puli                 if (retryPolicy)
455e5aaf047SAppaRao Puli                 {
456e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
457e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
458e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
459e5aaf047SAppaRao Puli                     {
4607e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
4617e860f15SJohn Edward Broadbent                                                          *retryPolicy,
462e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
463e5aaf047SAppaRao Puli                         return;
464e5aaf047SAppaRao Puli                     }
465b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
466e5aaf047SAppaRao Puli                 }
467e5aaf047SAppaRao Puli                 else
468e5aaf047SAppaRao Puli                 {
469e5aaf047SAppaRao Puli                     // Default "TerminateAfterRetries"
470b52664e2SAppaRao Puli                     subValue->retryPolicy = "TerminateAfterRetries";
471e5aaf047SAppaRao Puli                 }
472e5aaf047SAppaRao Puli 
473144b6318SAppaRao Puli                 if (mrdJsonArray)
474156d6b00SAppaRao Puli                 {
475144b6318SAppaRao Puli                     for (nlohmann::json& mrdObj : *mrdJsonArray)
476144b6318SAppaRao Puli                     {
477144b6318SAppaRao Puli                         std::string mrdUri;
4787e860f15SJohn Edward Broadbent                         if (json_util::getValueFromJsonObject(
4797e860f15SJohn Edward Broadbent                                 mrdObj, "@odata.id", mrdUri))
480144b6318SAppaRao Puli                         {
4817e860f15SJohn Edward Broadbent                             subValue->metricReportDefinitions.emplace_back(
4827e860f15SJohn Edward Broadbent                                 mrdUri);
483144b6318SAppaRao Puli                         }
484144b6318SAppaRao Puli                         else
485144b6318SAppaRao Puli                         {
486144b6318SAppaRao Puli                             messages::propertyValueFormatError(
48771f52d96SEd Tanous                                 asyncResp->res,
4887e860f15SJohn Edward Broadbent                                 mrdObj.dump(
4897e860f15SJohn Edward Broadbent                                     2, ' ', true,
49071f52d96SEd Tanous                                     nlohmann::json::error_handler_t::replace),
491144b6318SAppaRao Puli                                 "MetricReportDefinitions");
492144b6318SAppaRao Puli                             return;
493144b6318SAppaRao Puli                         }
494144b6318SAppaRao Puli                     }
495156d6b00SAppaRao Puli                 }
496156d6b00SAppaRao Puli 
497b52664e2SAppaRao Puli                 std::string id =
4987e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().addSubscription(
4997e860f15SJohn Edward Broadbent                         subValue);
500b52664e2SAppaRao Puli                 if (id.empty())
501e5aaf047SAppaRao Puli                 {
502e5aaf047SAppaRao Puli                     messages::internalError(asyncResp->res);
503e5aaf047SAppaRao Puli                     return;
504e5aaf047SAppaRao Puli                 }
505e5aaf047SAppaRao Puli 
506e5aaf047SAppaRao Puli                 messages::created(asyncResp->res);
507e5aaf047SAppaRao Puli                 asyncResp->res.addHeader(
508e5aaf047SAppaRao Puli                     "Location", "/redfish/v1/EventService/Subscriptions/" + id);
5097e860f15SJohn Edward Broadbent             });
510e5aaf047SAppaRao Puli }
511e5aaf047SAppaRao Puli 
5127e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
513e5aaf047SAppaRao Puli {
5149d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
515ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
5167e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
5177e860f15SJohn Edward Broadbent             [](const crow::Request&,
5187e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5197e860f15SJohn Edward Broadbent                const std::string& param) {
520b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5217e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
522b52664e2SAppaRao Puli                 if (subValue == nullptr)
523e5aaf047SAppaRao Puli                 {
5247e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5257e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
526e5aaf047SAppaRao Puli                     return;
527e5aaf047SAppaRao Puli                 }
5287e860f15SJohn Edward Broadbent                 const std::string& id = param;
529e5aaf047SAppaRao Puli 
5308d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
5317e860f15SJohn Edward Broadbent                     {"@odata.type",
5327e860f15SJohn Edward Broadbent                      "#EventDestination.v1_7_0.EventDestination"},
533e5aaf047SAppaRao Puli                     {"Protocol", "Redfish"}};
534e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["@odata.id"] =
535e5aaf047SAppaRao Puli                     "/redfish/v1/EventService/Subscriptions/" + id;
536e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Id"] = id;
537e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
5387e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Destination"] =
5397e860f15SJohn Edward Broadbent                     subValue->destinationUrl;
540b52664e2SAppaRao Puli                 asyncResp->res.jsonValue["Context"] = subValue->customText;
541e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["SubscriptionType"] =
542b52664e2SAppaRao Puli                     subValue->subscriptionType;
543ad22fefeSEd Tanous                 asyncResp->res.jsonValue["HttpHeaders"] =
544ad22fefeSEd Tanous                     nlohmann::json::array();
5457e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["EventFormatType"] =
5467e860f15SJohn Edward Broadbent                     subValue->eventFormatType;
547e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["RegistryPrefixes"] =
548b52664e2SAppaRao Puli                     subValue->registryPrefixes;
5497e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["ResourceTypes"] =
5507e860f15SJohn Edward Broadbent                     subValue->resourceTypes;
551e56f254cSSunitha Harish 
5527e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MessageIds"] =
5537e860f15SJohn Edward Broadbent                     subValue->registryMsgIds;
5547e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
5557e860f15SJohn Edward Broadbent                     subValue->retryPolicy;
556144b6318SAppaRao Puli 
557144b6318SAppaRao Puli                 std::vector<nlohmann::json> mrdJsonArray;
558144b6318SAppaRao Puli                 for (const auto& mdrUri : subValue->metricReportDefinitions)
559144b6318SAppaRao Puli                 {
560144b6318SAppaRao Puli                     mrdJsonArray.push_back({{"@odata.id", mdrUri}});
561144b6318SAppaRao Puli                 }
5627e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MetricReportDefinitions"] =
5637e860f15SJohn Edward Broadbent                     mrdJsonArray;
5647e860f15SJohn Edward Broadbent             });
5659d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
566ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
567ed398213SEd Tanous         // ConfigureSelf
5687eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
569ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
570432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
5717e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
5727e860f15SJohn Edward Broadbent             [](const crow::Request& req,
5737e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5747e860f15SJohn Edward Broadbent                const std::string& param) {
575b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5767e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
577b52664e2SAppaRao Puli                 if (subValue == nullptr)
578e5aaf047SAppaRao Puli                 {
5797e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5807e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
581e5aaf047SAppaRao Puli                     return;
582e5aaf047SAppaRao Puli                 }
583e5aaf047SAppaRao Puli 
584e5aaf047SAppaRao Puli                 std::optional<std::string> context;
585e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
586e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
587e5aaf047SAppaRao Puli 
5887e860f15SJohn Edward Broadbent                 if (!json_util::readJson(req, asyncResp->res, "Context",
5897e860f15SJohn Edward Broadbent                                          context, "DeliveryRetryPolicy",
5907e860f15SJohn Edward Broadbent                                          retryPolicy, "HttpHeaders", headers))
591e5aaf047SAppaRao Puli                 {
592e5aaf047SAppaRao Puli                     return;
593e5aaf047SAppaRao Puli                 }
594e5aaf047SAppaRao Puli 
595e5aaf047SAppaRao Puli                 if (context)
596e5aaf047SAppaRao Puli                 {
597b52664e2SAppaRao Puli                     subValue->customText = *context;
598e5aaf047SAppaRao Puli                 }
599e5aaf047SAppaRao Puli 
600e5aaf047SAppaRao Puli                 if (headers)
601e5aaf047SAppaRao Puli                 {
602601c71aeSEd Tanous                     boost::beast::http::fields fields;
603601c71aeSEd Tanous                     for (const nlohmann::json& headerChunk : *headers)
604601c71aeSEd Tanous                     {
605601c71aeSEd Tanous                         for (auto& it : headerChunk.items())
606601c71aeSEd Tanous                         {
607601c71aeSEd Tanous                             const std::string* value =
608601c71aeSEd Tanous                                 it.value().get_ptr<const std::string*>();
609601c71aeSEd Tanous                             if (value == nullptr)
610601c71aeSEd Tanous                             {
611601c71aeSEd Tanous                                 messages::propertyValueFormatError(
612601c71aeSEd Tanous                                     asyncResp->res,
613601c71aeSEd Tanous                                     it.value().dump(2, ' ', true),
614601c71aeSEd Tanous                                     "HttpHeaders/" + it.key());
615601c71aeSEd Tanous                                 return;
616601c71aeSEd Tanous                             }
617601c71aeSEd Tanous                             fields.set(it.key(), *value);
618601c71aeSEd Tanous                         }
619601c71aeSEd Tanous                     }
620601c71aeSEd Tanous                     subValue->httpHeaders = fields;
621e5aaf047SAppaRao Puli                 }
622e5aaf047SAppaRao Puli 
623e5aaf047SAppaRao Puli                 if (retryPolicy)
624e5aaf047SAppaRao Puli                 {
625e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
626e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
627e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
628e5aaf047SAppaRao Puli                     {
6297e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
6307e860f15SJohn Edward Broadbent                                                          *retryPolicy,
631e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
632e5aaf047SAppaRao Puli                         return;
633e5aaf047SAppaRao Puli                     }
634b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
635fe44eb0bSAyushi Smriti                     subValue->updateRetryPolicy();
636e5aaf047SAppaRao Puli                 }
637e5aaf047SAppaRao Puli 
638b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
6397e860f15SJohn Edward Broadbent             });
6409d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
641ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
642ed398213SEd Tanous         // ConfigureSelf
6437eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
644ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
645432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
6467e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
6477e860f15SJohn Edward Broadbent             [](const crow::Request&,
6487e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6497e860f15SJohn Edward Broadbent                const std::string& param) {
6507e860f15SJohn Edward Broadbent                 if (!EventServiceManager::getInstance().isSubscriptionExist(
6517e860f15SJohn Edward Broadbent                         param))
652e5aaf047SAppaRao Puli                 {
6537e860f15SJohn Edward Broadbent                     asyncResp->res.result(
6547e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
655e5aaf047SAppaRao Puli                     return;
656e5aaf047SAppaRao Puli                 }
6577e860f15SJohn Edward Broadbent                 EventServiceManager::getInstance().deleteSubscription(param);
6587e860f15SJohn Edward Broadbent             });
659e5aaf047SAppaRao Puli }
660e5aaf047SAppaRao Puli 
661e5aaf047SAppaRao Puli } // namespace redfish
662