xref: /openbmc/bmcweb/features/redfish/lib/event_service.hpp (revision 0fda0f12bb9ae0604a083dfae419be38a1418913)
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 
23e5aaf047SAppaRao Puli namespace redfish
24e5aaf047SAppaRao Puli {
25e5aaf047SAppaRao Puli 
26156d6b00SAppaRao Puli static constexpr const std::array<const char*, 2> supportedEvtFormatTypes = {
27156d6b00SAppaRao Puli     eventFormatType, metricReportFormatType};
28e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRegPrefixes = {
29b304bd79SP Dheeraj Srujan Kumar     "Base", "OpenBMC", "TaskEvent"};
30e5aaf047SAppaRao Puli static constexpr const std::array<const char*, 3> supportedRetryPolicies = {
31e5aaf047SAppaRao Puli     "TerminateAfterRetries", "SuspendRetries", "RetryForever"};
32e5aaf047SAppaRao Puli 
33e56f254cSSunitha Harish #ifdef BMCWEB_ENABLE_IBM_MANAGEMENT_CONSOLE
34e56f254cSSunitha Harish static constexpr const std::array<const char*, 2> supportedResourceTypes = {
35e56f254cSSunitha Harish     "IBMConfigFile", "Task"};
36e56f254cSSunitha Harish #else
37e56f254cSSunitha Harish static constexpr const std::array<const char*, 1> supportedResourceTypes = {
38e56f254cSSunitha Harish     "Task"};
39e56f254cSSunitha Harish #endif
40e56f254cSSunitha Harish 
41e5aaf047SAppaRao Puli static constexpr const uint8_t maxNoOfSubscriptions = 20;
42e5aaf047SAppaRao Puli 
437e860f15SJohn Edward Broadbent inline void requestRoutesEventService(App& app)
44e5aaf047SAppaRao Puli {
457e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
46ed398213SEd Tanous         .privileges(redfish::privileges::getEventService)
47*0fda0f12SGeorge Liu         .methods(
48*0fda0f12SGeorge Liu             boost::beast::http::verb::
49*0fda0f12SGeorge Liu                 get)([](const crow::Request&,
507e860f15SJohn Edward Broadbent                         const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
518d1b46d7Szhanghch05             asyncResp->res.jsonValue = {
52e5aaf047SAppaRao Puli                 {"@odata.type", "#EventService.v1_5_0.EventService"},
53e5aaf047SAppaRao Puli                 {"Id", "EventService"},
54e5aaf047SAppaRao Puli                 {"Name", "Event Service"},
55e5aaf047SAppaRao Puli                 {"Subscriptions",
56e5aaf047SAppaRao Puli                  {{"@odata.id", "/redfish/v1/EventService/Subscriptions"}}},
570b4bdd93SAppaRao Puli                 {"Actions",
580b4bdd93SAppaRao Puli                  {{"#EventService.SubmitTestEvent",
59*0fda0f12SGeorge Liu                    {{"target",
60*0fda0f12SGeorge Liu                      "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent"}}}}},
61e5aaf047SAppaRao Puli                 {"@odata.id", "/redfish/v1/EventService"}};
62e5aaf047SAppaRao Puli 
6328afb49cSJunLin Chen             const persistent_data::EventServiceConfig eventServiceConfig =
6428afb49cSJunLin Chen                 persistent_data::EventServiceStore::getInstance()
6528afb49cSJunLin Chen                     .getEventServiceConfig();
667d1cc387SAppaRao Puli 
677d1cc387SAppaRao Puli             asyncResp->res.jsonValue["Status"]["State"] =
6828afb49cSJunLin Chen                 (eventServiceConfig.enabled ? "Enabled" : "Disabled");
6928afb49cSJunLin Chen             asyncResp->res.jsonValue["ServiceEnabled"] =
7028afb49cSJunLin Chen                 eventServiceConfig.enabled;
717e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["DeliveryRetryAttempts"] =
7228afb49cSJunLin Chen                 eventServiceConfig.retryAttempts;
73e5aaf047SAppaRao Puli             asyncResp->res.jsonValue["DeliveryRetryIntervalSeconds"] =
7428afb49cSJunLin Chen                 eventServiceConfig.retryTimeoutInterval;
757e860f15SJohn Edward Broadbent             asyncResp->res.jsonValue["EventFormatTypes"] =
767e860f15SJohn Edward Broadbent                 supportedEvtFormatTypes;
77*0fda0f12SGeorge Liu             asyncResp->res.jsonValue["RegistryPrefixes"] = supportedRegPrefixes;
78*0fda0f12SGeorge Liu             asyncResp->res.jsonValue["ResourceTypes"] = supportedResourceTypes;
7907941a88SAyushi Smriti 
8007941a88SAyushi Smriti             nlohmann::json supportedSSEFilters = {
8107941a88SAyushi Smriti                 {"EventFormatType", true},        {"MessageId", true},
8207941a88SAyushi Smriti                 {"MetricReportDefinition", true}, {"RegistryPrefix", true},
8307941a88SAyushi Smriti                 {"OriginResource", false},        {"ResourceType", false}};
8407941a88SAyushi Smriti 
8507941a88SAyushi Smriti             asyncResp->res.jsonValue["SSEFilterPropertiesSupported"] =
8607941a88SAyushi Smriti                 supportedSSEFilters;
877e860f15SJohn Edward Broadbent         });
88e5aaf047SAppaRao Puli 
897e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/")
90ed398213SEd Tanous         .privileges(redfish::privileges::patchEventService)
917e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
927e860f15SJohn Edward Broadbent             [](const crow::Request& req,
937e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
947e860f15SJohn Edward Broadbent 
95e5aaf047SAppaRao Puli             {
96e5aaf047SAppaRao Puli                 std::optional<bool> serviceEnabled;
97e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryAttemps;
98e5aaf047SAppaRao Puli                 std::optional<uint32_t> retryInterval;
99e5aaf047SAppaRao Puli 
1007e860f15SJohn Edward Broadbent                 if (!json_util::readJson(
1017e860f15SJohn Edward Broadbent                         req, asyncResp->res, "ServiceEnabled", serviceEnabled,
1027e860f15SJohn Edward Broadbent                         "DeliveryRetryAttempts", retryAttemps,
1037e860f15SJohn Edward Broadbent                         "DeliveryRetryIntervalSeconds", retryInterval))
104e5aaf047SAppaRao Puli                 {
105e5aaf047SAppaRao Puli                     return;
106e5aaf047SAppaRao Puli                 }
107e5aaf047SAppaRao Puli 
10828afb49cSJunLin Chen                 persistent_data::EventServiceConfig eventServiceConfig =
10928afb49cSJunLin Chen                     persistent_data::EventServiceStore::getInstance()
11028afb49cSJunLin Chen                         .getEventServiceConfig();
1117d1cc387SAppaRao Puli 
112e5aaf047SAppaRao Puli                 if (serviceEnabled)
113e5aaf047SAppaRao Puli                 {
11428afb49cSJunLin Chen                     eventServiceConfig.enabled = *serviceEnabled;
115e5aaf047SAppaRao Puli                 }
116e5aaf047SAppaRao Puli 
117e5aaf047SAppaRao Puli                 if (retryAttemps)
118e5aaf047SAppaRao Puli                 {
119e5aaf047SAppaRao Puli                     // Supported range [1-3]
120e5aaf047SAppaRao Puli                     if ((*retryAttemps < 1) || (*retryAttemps > 3))
121e5aaf047SAppaRao Puli                     {
122e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
123e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryAttemps),
124e5aaf047SAppaRao Puli                             "DeliveryRetryAttempts", "[1-3]");
125e5aaf047SAppaRao Puli                     }
126e5aaf047SAppaRao Puli                     else
127e5aaf047SAppaRao Puli                     {
12828afb49cSJunLin Chen                         eventServiceConfig.retryAttempts = *retryAttemps;
129e5aaf047SAppaRao Puli                     }
130e5aaf047SAppaRao Puli                 }
131e5aaf047SAppaRao Puli 
132e5aaf047SAppaRao Puli                 if (retryInterval)
133e5aaf047SAppaRao Puli                 {
134e5aaf047SAppaRao Puli                     // Supported range [30 - 180]
135e5aaf047SAppaRao Puli                     if ((*retryInterval < 30) || (*retryInterval > 180))
136e5aaf047SAppaRao Puli                     {
137e5aaf047SAppaRao Puli                         messages::queryParameterOutOfRange(
138e5aaf047SAppaRao Puli                             asyncResp->res, std::to_string(*retryInterval),
139e5aaf047SAppaRao Puli                             "DeliveryRetryIntervalSeconds", "[30-180]");
140e5aaf047SAppaRao Puli                     }
141e5aaf047SAppaRao Puli                     else
142e5aaf047SAppaRao Puli                     {
14328afb49cSJunLin Chen                         eventServiceConfig.retryTimeoutInterval =
14428afb49cSJunLin Chen                             *retryInterval;
145e5aaf047SAppaRao Puli                     }
146e5aaf047SAppaRao Puli                 }
147e5aaf047SAppaRao Puli 
1487d1cc387SAppaRao Puli                 EventServiceManager::getInstance().setEventServiceConfig(
14928afb49cSJunLin Chen                     eventServiceConfig);
1507e860f15SJohn Edward Broadbent             });
1510b4bdd93SAppaRao Puli }
1520b4bdd93SAppaRao Puli 
1537e860f15SJohn Edward Broadbent inline void requestRoutesSubmitTestEvent(App& app)
1540b4bdd93SAppaRao Puli {
1557e860f15SJohn Edward Broadbent 
1567e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(
1577e860f15SJohn Edward Broadbent         app, "/redfish/v1/EventService/Actions/EventService.SubmitTestEvent/")
158ed398213SEd Tanous         .privileges(redfish::privileges::postEventService)
1597e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
1607e860f15SJohn Edward Broadbent             [](const crow::Request&,
1617e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1620b4bdd93SAppaRao Puli                 EventServiceManager::getInstance().sendTestEventLog();
1638d1b46d7Szhanghch05                 asyncResp->res.result(boost::beast::http::status::no_content);
1647e860f15SJohn Edward Broadbent             });
165e5aaf047SAppaRao Puli }
166e5aaf047SAppaRao Puli 
1677e860f15SJohn Edward Broadbent inline void requestRoutesEventDestinationCollection(App& app)
168e5aaf047SAppaRao Puli {
1697e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions")
170ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestinationCollection)
1717e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
1727e860f15SJohn Edward Broadbent             [](const crow::Request&,
1737e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
1748d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
175e5aaf047SAppaRao Puli                     {"@odata.type",
176e5aaf047SAppaRao Puli                      "#EventDestinationCollection.EventDestinationCollection"},
177e5aaf047SAppaRao Puli                     {"@odata.id", "/redfish/v1/EventService/Subscriptions"},
178e5aaf047SAppaRao Puli                     {"Name", "Event Destination Collections"}};
179e5aaf047SAppaRao Puli 
1807e860f15SJohn Edward Broadbent                 nlohmann::json& memberArray =
1817e860f15SJohn Edward Broadbent                     asyncResp->res.jsonValue["Members"];
182e5aaf047SAppaRao Puli 
183b52664e2SAppaRao Puli                 std::vector<std::string> subscripIds =
184b52664e2SAppaRao Puli                     EventServiceManager::getInstance().getAllIDs();
185b52664e2SAppaRao Puli                 memberArray = nlohmann::json::array();
1867e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Members@odata.count"] =
1877e860f15SJohn Edward Broadbent                     subscripIds.size();
188b52664e2SAppaRao Puli 
189b52664e2SAppaRao Puli                 for (const std::string& id : subscripIds)
190e5aaf047SAppaRao Puli                 {
191e5aaf047SAppaRao Puli                     memberArray.push_back(
192e5aaf047SAppaRao Puli                         {{"@odata.id",
193b52664e2SAppaRao Puli                           "/redfish/v1/EventService/Subscriptions/" + id}});
194e5aaf047SAppaRao Puli                 }
1957e860f15SJohn Edward Broadbent             });
1967e860f15SJohn Edward Broadbent     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/")
1977eeafa76SAbhishek Patel         .privileges(redfish::privileges::postEventDestinationCollection)
1987e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::post)(
1997e860f15SJohn Edward Broadbent             [](const crow::Request& req,
2007e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp) {
2017e860f15SJohn Edward Broadbent                 if (EventServiceManager::getInstance()
2027e860f15SJohn Edward Broadbent                         .getNumberOfSubscriptions() >= maxNoOfSubscriptions)
203e5aaf047SAppaRao Puli                 {
204e5aaf047SAppaRao Puli                     messages::eventSubscriptionLimitExceeded(asyncResp->res);
205e5aaf047SAppaRao Puli                     return;
206e5aaf047SAppaRao Puli                 }
207e5aaf047SAppaRao Puli                 std::string destUrl;
208e5aaf047SAppaRao Puli                 std::string protocol;
209e5aaf047SAppaRao Puli                 std::optional<std::string> context;
210e5aaf047SAppaRao Puli                 std::optional<std::string> subscriptionType;
21123a21a1cSEd Tanous                 std::optional<std::string> eventFormatType2;
212e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
213e5aaf047SAppaRao Puli                 std::optional<std::vector<std::string>> msgIds;
214e5aaf047SAppaRao Puli                 std::optional<std::vector<std::string>> regPrefixes;
215e56f254cSSunitha Harish                 std::optional<std::vector<std::string>> resTypes;
216e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
217144b6318SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> mrdJsonArray;
218e5aaf047SAppaRao Puli 
219e5aaf047SAppaRao Puli                 if (!json_util::readJson(
2207e860f15SJohn Edward Broadbent                         req, asyncResp->res, "Destination", destUrl, "Context",
2217e860f15SJohn Edward Broadbent                         context, "Protocol", protocol, "SubscriptionType",
2227e860f15SJohn Edward Broadbent                         subscriptionType, "EventFormatType", eventFormatType2,
2237e860f15SJohn Edward Broadbent                         "HttpHeaders", headers, "RegistryPrefixes", regPrefixes,
2247e860f15SJohn Edward Broadbent                         "MessageIds", msgIds, "DeliveryRetryPolicy",
2257e860f15SJohn Edward Broadbent                         retryPolicy, "MetricReportDefinitions", mrdJsonArray,
2267e860f15SJohn Edward Broadbent                         "ResourceTypes", resTypes))
227e5aaf047SAppaRao Puli                 {
228e5aaf047SAppaRao Puli                     return;
229e5aaf047SAppaRao Puli                 }
230e5aaf047SAppaRao Puli 
231dd28ba82SAppaRao Puli                 if (regPrefixes && msgIds)
232dd28ba82SAppaRao Puli                 {
233dd28ba82SAppaRao Puli                     if (regPrefixes->size() && msgIds->size())
234dd28ba82SAppaRao Puli                     {
235dd28ba82SAppaRao Puli                         messages::mutualExclusiveProperties(
236dd28ba82SAppaRao Puli                             asyncResp->res, "RegistryPrefixes", "MessageIds");
237dd28ba82SAppaRao Puli                         return;
238dd28ba82SAppaRao Puli                     }
239dd28ba82SAppaRao Puli                 }
240dd28ba82SAppaRao Puli 
241e5aaf047SAppaRao Puli                 // Validate the URL using regex expression
242b52664e2SAppaRao Puli                 // Format: <protocol>://<host>:<port>/<uri>
243b52664e2SAppaRao Puli                 // protocol: http/https
244b52664e2SAppaRao Puli                 // host: Exclude ' ', ':', '#', '?'
2454e0453b1SGunnar Mills                 // port: Empty or numeric value with ':' separator.
246b52664e2SAppaRao Puli                 // uri: Start with '/' and Exclude '#', ' '
247b52664e2SAppaRao Puli                 //      Can include query params(ex: '/event?test=1')
248b52664e2SAppaRao Puli                 // TODO: Need to validate hostname extensively(as per rfc)
249b52664e2SAppaRao Puli                 const std::regex urlRegex(
250b52664e2SAppaRao Puli                     "(http|https)://([^/\\x20\\x3f\\x23\\x3a]+):?([0-9]*)(/"
251b52664e2SAppaRao Puli                     "([^\\x20\\x23\\x3f]*\\x3f?([^\\x20\\x23\\x3f])*)?)");
252b52664e2SAppaRao Puli                 std::cmatch match;
253b52664e2SAppaRao Puli                 if (!std::regex_match(destUrl.c_str(), match, urlRegex))
254e5aaf047SAppaRao Puli                 {
255e5aaf047SAppaRao Puli                     messages::propertyValueFormatError(asyncResp->res, destUrl,
256e5aaf047SAppaRao Puli                                                        "Destination");
257e5aaf047SAppaRao Puli                     return;
258e5aaf047SAppaRao Puli                 }
259b52664e2SAppaRao Puli 
2607e860f15SJohn Edward Broadbent                 std::string uriProto =
2617e860f15SJohn Edward Broadbent                     std::string(match[1].first, match[1].second);
262b52664e2SAppaRao Puli                 if (uriProto == "http")
263b52664e2SAppaRao Puli                 {
264b52664e2SAppaRao Puli #ifndef BMCWEB_INSECURE_ENABLE_HTTP_PUSH_STYLE_EVENTING
265b52664e2SAppaRao Puli                     messages::propertyValueFormatError(asyncResp->res, destUrl,
266b52664e2SAppaRao Puli                                                        "Destination");
267b52664e2SAppaRao Puli                     return;
268b52664e2SAppaRao Puli #endif
269b52664e2SAppaRao Puli                 }
270b52664e2SAppaRao Puli 
271b52664e2SAppaRao Puli                 std::string host = std::string(match[2].first, match[2].second);
272b52664e2SAppaRao Puli                 std::string port = std::string(match[3].first, match[3].second);
273b52664e2SAppaRao Puli                 std::string path = std::string(match[4].first, match[4].second);
274b52664e2SAppaRao Puli                 if (port.empty())
275b52664e2SAppaRao Puli                 {
276b52664e2SAppaRao Puli                     if (uriProto == "http")
277b52664e2SAppaRao Puli                     {
278b52664e2SAppaRao Puli                         port = "80";
279b52664e2SAppaRao Puli                     }
280b52664e2SAppaRao Puli                     else
281b52664e2SAppaRao Puli                     {
282b52664e2SAppaRao Puli                         port = "443";
283b52664e2SAppaRao Puli                     }
284b52664e2SAppaRao Puli                 }
285b52664e2SAppaRao Puli                 if (path.empty())
286b52664e2SAppaRao Puli                 {
287b52664e2SAppaRao Puli                     path = "/";
288b52664e2SAppaRao Puli                 }
289b52664e2SAppaRao Puli 
290b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
291b52664e2SAppaRao Puli                     std::make_shared<Subscription>(host, port, path, uriProto);
292b52664e2SAppaRao Puli 
293b52664e2SAppaRao Puli                 subValue->destinationUrl = destUrl;
294e5aaf047SAppaRao Puli 
295e5aaf047SAppaRao Puli                 if (subscriptionType)
296e5aaf047SAppaRao Puli                 {
297e5aaf047SAppaRao Puli                     if (*subscriptionType != "RedfishEvent")
298e5aaf047SAppaRao Puli                     {
2997e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
3007e860f15SJohn Edward Broadbent                                                          *subscriptionType,
3017e860f15SJohn Edward Broadbent                                                          "SubscriptionType");
302e5aaf047SAppaRao Puli                         return;
303e5aaf047SAppaRao Puli                     }
304b52664e2SAppaRao Puli                     subValue->subscriptionType = *subscriptionType;
305e5aaf047SAppaRao Puli                 }
306e5aaf047SAppaRao Puli                 else
307e5aaf047SAppaRao Puli                 {
308b52664e2SAppaRao Puli                     subValue->subscriptionType = "RedfishEvent"; // Default
309e5aaf047SAppaRao Puli                 }
310e5aaf047SAppaRao Puli 
311e5aaf047SAppaRao Puli                 if (protocol != "Redfish")
312e5aaf047SAppaRao Puli                 {
313e5aaf047SAppaRao Puli                     messages::propertyValueNotInList(asyncResp->res, protocol,
314e5aaf047SAppaRao Puli                                                      "Protocol");
315e5aaf047SAppaRao Puli                     return;
316e5aaf047SAppaRao Puli                 }
317b52664e2SAppaRao Puli                 subValue->protocol = protocol;
318e5aaf047SAppaRao Puli 
31923a21a1cSEd Tanous                 if (eventFormatType2)
320e5aaf047SAppaRao Puli                 {
321e5aaf047SAppaRao Puli                     if (std::find(supportedEvtFormatTypes.begin(),
322e5aaf047SAppaRao Puli                                   supportedEvtFormatTypes.end(),
3237e860f15SJohn Edward Broadbent                                   *eventFormatType2) ==
3247e860f15SJohn Edward Broadbent                         supportedEvtFormatTypes.end())
325e5aaf047SAppaRao Puli                     {
3267e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
3277e860f15SJohn Edward Broadbent                                                          *eventFormatType2,
3287e860f15SJohn Edward Broadbent                                                          "EventFormatType");
329e5aaf047SAppaRao Puli                         return;
330e5aaf047SAppaRao Puli                     }
33123a21a1cSEd Tanous                     subValue->eventFormatType = *eventFormatType2;
332e5aaf047SAppaRao Puli                 }
333e5aaf047SAppaRao Puli                 else
334e5aaf047SAppaRao Puli                 {
335e5aaf047SAppaRao Puli                     // If not specified, use default "Event"
33623a21a1cSEd Tanous                     subValue->eventFormatType = "Event";
337e5aaf047SAppaRao Puli                 }
338e5aaf047SAppaRao Puli 
339e5aaf047SAppaRao Puli                 if (context)
340e5aaf047SAppaRao Puli                 {
341b52664e2SAppaRao Puli                     subValue->customText = *context;
342e5aaf047SAppaRao Puli                 }
343e5aaf047SAppaRao Puli 
344e5aaf047SAppaRao Puli                 if (headers)
345e5aaf047SAppaRao Puli                 {
346601c71aeSEd Tanous                     for (const nlohmann::json& headerChunk : *headers)
347601c71aeSEd Tanous                     {
348601c71aeSEd Tanous                         for (const auto& item : headerChunk.items())
349601c71aeSEd Tanous                         {
350601c71aeSEd Tanous                             const std::string* value =
351601c71aeSEd Tanous                                 item.value().get_ptr<const std::string*>();
352601c71aeSEd Tanous                             if (value == nullptr)
353601c71aeSEd Tanous                             {
354601c71aeSEd Tanous                                 messages::propertyValueFormatError(
355601c71aeSEd Tanous                                     asyncResp->res, item.value().dump(2, true),
356601c71aeSEd Tanous                                     "HttpHeaders/" + item.key());
357601c71aeSEd Tanous                                 return;
358601c71aeSEd Tanous                             }
359601c71aeSEd Tanous                             subValue->httpHeaders.set(item.key(), *value);
360601c71aeSEd Tanous                         }
361601c71aeSEd Tanous                     }
362e5aaf047SAppaRao Puli                 }
363e5aaf047SAppaRao Puli 
364e5aaf047SAppaRao Puli                 if (regPrefixes)
365e5aaf047SAppaRao Puli                 {
366e5aaf047SAppaRao Puli                     for (const std::string& it : *regPrefixes)
367e5aaf047SAppaRao Puli                     {
368e5aaf047SAppaRao Puli                         if (std::find(supportedRegPrefixes.begin(),
369e5aaf047SAppaRao Puli                                       supportedRegPrefixes.end(),
370e5aaf047SAppaRao Puli                                       it) == supportedRegPrefixes.end())
371e5aaf047SAppaRao Puli                         {
3727e860f15SJohn Edward Broadbent                             messages::propertyValueNotInList(
3737e860f15SJohn Edward Broadbent                                 asyncResp->res, it, "RegistryPrefixes");
374e5aaf047SAppaRao Puli                             return;
375e5aaf047SAppaRao Puli                         }
376e5aaf047SAppaRao Puli                     }
377b52664e2SAppaRao Puli                     subValue->registryPrefixes = *regPrefixes;
378e5aaf047SAppaRao Puli                 }
379e5aaf047SAppaRao Puli 
380e56f254cSSunitha Harish                 if (resTypes)
381e56f254cSSunitha Harish                 {
382e56f254cSSunitha Harish                     for (const std::string& it : *resTypes)
383e56f254cSSunitha Harish                     {
384e56f254cSSunitha Harish                         if (std::find(supportedResourceTypes.begin(),
385e56f254cSSunitha Harish                                       supportedResourceTypes.end(),
386e56f254cSSunitha Harish                                       it) == supportedResourceTypes.end())
387e56f254cSSunitha Harish                         {
388e56f254cSSunitha Harish                             messages::propertyValueNotInList(asyncResp->res, it,
389e56f254cSSunitha Harish                                                              "ResourceTypes");
390e56f254cSSunitha Harish                             return;
391e56f254cSSunitha Harish                         }
392e56f254cSSunitha Harish                     }
393e56f254cSSunitha Harish                     subValue->resourceTypes = *resTypes;
394e56f254cSSunitha Harish                 }
395e56f254cSSunitha Harish 
396e5aaf047SAppaRao Puli                 if (msgIds)
397e5aaf047SAppaRao Puli                 {
398b304bd79SP Dheeraj Srujan Kumar                     std::vector<std::string> registryPrefix;
399b304bd79SP Dheeraj Srujan Kumar 
4007e860f15SJohn Edward Broadbent                     // If no registry prefixes are mentioned, consider all
4017e860f15SJohn Edward Broadbent                     // supported prefixes
402b304bd79SP Dheeraj Srujan Kumar                     if (subValue->registryPrefixes.empty())
403b304bd79SP Dheeraj Srujan Kumar                     {
404b304bd79SP Dheeraj Srujan Kumar                         registryPrefix.assign(supportedRegPrefixes.begin(),
405b304bd79SP Dheeraj Srujan Kumar                                               supportedRegPrefixes.end());
406b304bd79SP Dheeraj Srujan Kumar                     }
407b304bd79SP Dheeraj Srujan Kumar                     else
408b304bd79SP Dheeraj Srujan Kumar                     {
409b304bd79SP Dheeraj Srujan Kumar                         registryPrefix = subValue->registryPrefixes;
410b304bd79SP Dheeraj Srujan Kumar                     }
411b304bd79SP Dheeraj Srujan Kumar 
412b304bd79SP Dheeraj Srujan Kumar                     for (const std::string& id : *msgIds)
413b304bd79SP Dheeraj Srujan Kumar                     {
414b304bd79SP Dheeraj Srujan Kumar                         bool validId = false;
415b304bd79SP Dheeraj Srujan Kumar 
416b304bd79SP Dheeraj Srujan Kumar                         // Check for Message ID in each of the selected Registry
417b304bd79SP Dheeraj Srujan Kumar                         for (const std::string& it : registryPrefix)
418b304bd79SP Dheeraj Srujan Kumar                         {
419b304bd79SP Dheeraj Srujan Kumar                             const boost::beast::span<
420b304bd79SP Dheeraj Srujan Kumar                                 const redfish::message_registries::MessageEntry>
4217e860f15SJohn Edward Broadbent                                 registry = redfish::message_registries::
4227e860f15SJohn Edward Broadbent                                     getRegistryFromPrefix(it);
423b304bd79SP Dheeraj Srujan Kumar 
424b304bd79SP Dheeraj Srujan Kumar                             if (std::any_of(
425b304bd79SP Dheeraj Srujan Kumar                                     registry.cbegin(), registry.cend(),
4267e860f15SJohn Edward Broadbent                                     [&id](const redfish::message_registries::
4277e860f15SJohn Edward Broadbent                                               MessageEntry& messageEntry) {
428b304bd79SP Dheeraj Srujan Kumar                                         return !id.compare(messageEntry.first);
429b304bd79SP Dheeraj Srujan Kumar                                     }))
430b304bd79SP Dheeraj Srujan Kumar                             {
431b304bd79SP Dheeraj Srujan Kumar                                 validId = true;
432b304bd79SP Dheeraj Srujan Kumar                                 break;
433b304bd79SP Dheeraj Srujan Kumar                             }
434b304bd79SP Dheeraj Srujan Kumar                         }
435b304bd79SP Dheeraj Srujan Kumar 
436b304bd79SP Dheeraj Srujan Kumar                         if (!validId)
437b304bd79SP Dheeraj Srujan Kumar                         {
438b304bd79SP Dheeraj Srujan Kumar                             messages::propertyValueNotInList(asyncResp->res, id,
439b304bd79SP Dheeraj Srujan Kumar                                                              "MessageIds");
440b304bd79SP Dheeraj Srujan Kumar                             return;
441b304bd79SP Dheeraj Srujan Kumar                         }
442b304bd79SP Dheeraj Srujan Kumar                     }
443b304bd79SP Dheeraj Srujan Kumar 
444b52664e2SAppaRao Puli                     subValue->registryMsgIds = *msgIds;
445e5aaf047SAppaRao Puli                 }
446e5aaf047SAppaRao Puli 
447e5aaf047SAppaRao Puli                 if (retryPolicy)
448e5aaf047SAppaRao Puli                 {
449e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
450e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
451e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
452e5aaf047SAppaRao Puli                     {
4537e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
4547e860f15SJohn Edward Broadbent                                                          *retryPolicy,
455e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
456e5aaf047SAppaRao Puli                         return;
457e5aaf047SAppaRao Puli                     }
458b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
459e5aaf047SAppaRao Puli                 }
460e5aaf047SAppaRao Puli                 else
461e5aaf047SAppaRao Puli                 {
462e5aaf047SAppaRao Puli                     // Default "TerminateAfterRetries"
463b52664e2SAppaRao Puli                     subValue->retryPolicy = "TerminateAfterRetries";
464e5aaf047SAppaRao Puli                 }
465e5aaf047SAppaRao Puli 
466144b6318SAppaRao Puli                 if (mrdJsonArray)
467156d6b00SAppaRao Puli                 {
468144b6318SAppaRao Puli                     for (nlohmann::json& mrdObj : *mrdJsonArray)
469144b6318SAppaRao Puli                     {
470144b6318SAppaRao Puli                         std::string mrdUri;
4717e860f15SJohn Edward Broadbent                         if (json_util::getValueFromJsonObject(
4727e860f15SJohn Edward Broadbent                                 mrdObj, "@odata.id", mrdUri))
473144b6318SAppaRao Puli                         {
4747e860f15SJohn Edward Broadbent                             subValue->metricReportDefinitions.emplace_back(
4757e860f15SJohn Edward Broadbent                                 mrdUri);
476144b6318SAppaRao Puli                         }
477144b6318SAppaRao Puli                         else
478144b6318SAppaRao Puli                         {
479144b6318SAppaRao Puli                             messages::propertyValueFormatError(
48071f52d96SEd Tanous                                 asyncResp->res,
4817e860f15SJohn Edward Broadbent                                 mrdObj.dump(
4827e860f15SJohn Edward Broadbent                                     2, ' ', true,
48371f52d96SEd Tanous                                     nlohmann::json::error_handler_t::replace),
484144b6318SAppaRao Puli                                 "MetricReportDefinitions");
485144b6318SAppaRao Puli                             return;
486144b6318SAppaRao Puli                         }
487144b6318SAppaRao Puli                     }
488156d6b00SAppaRao Puli                 }
489156d6b00SAppaRao Puli 
490b52664e2SAppaRao Puli                 std::string id =
4917e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().addSubscription(
4927e860f15SJohn Edward Broadbent                         subValue);
493b52664e2SAppaRao Puli                 if (id.empty())
494e5aaf047SAppaRao Puli                 {
495e5aaf047SAppaRao Puli                     messages::internalError(asyncResp->res);
496e5aaf047SAppaRao Puli                     return;
497e5aaf047SAppaRao Puli                 }
498e5aaf047SAppaRao Puli 
499e5aaf047SAppaRao Puli                 messages::created(asyncResp->res);
500e5aaf047SAppaRao Puli                 asyncResp->res.addHeader(
501e5aaf047SAppaRao Puli                     "Location", "/redfish/v1/EventService/Subscriptions/" + id);
5027e860f15SJohn Edward Broadbent             });
503e5aaf047SAppaRao Puli }
504e5aaf047SAppaRao Puli 
5057e860f15SJohn Edward Broadbent inline void requestRoutesEventDestination(App& app)
506e5aaf047SAppaRao Puli {
5079d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
508ed398213SEd Tanous         .privileges(redfish::privileges::getEventDestination)
5097e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::get)(
5107e860f15SJohn Edward Broadbent             [](const crow::Request&,
5117e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5127e860f15SJohn Edward Broadbent                const std::string& param) {
513b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5147e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
515b52664e2SAppaRao Puli                 if (subValue == nullptr)
516e5aaf047SAppaRao Puli                 {
5177e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5187e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
519e5aaf047SAppaRao Puli                     return;
520e5aaf047SAppaRao Puli                 }
5217e860f15SJohn Edward Broadbent                 const std::string& id = param;
522e5aaf047SAppaRao Puli 
5238d1b46d7Szhanghch05                 asyncResp->res.jsonValue = {
5247e860f15SJohn Edward Broadbent                     {"@odata.type",
5257e860f15SJohn Edward Broadbent                      "#EventDestination.v1_7_0.EventDestination"},
526e5aaf047SAppaRao Puli                     {"Protocol", "Redfish"}};
527e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["@odata.id"] =
528e5aaf047SAppaRao Puli                     "/redfish/v1/EventService/Subscriptions/" + id;
529e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Id"] = id;
530e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["Name"] = "Event Destination " + id;
5317e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["Destination"] =
5327e860f15SJohn Edward Broadbent                     subValue->destinationUrl;
533b52664e2SAppaRao Puli                 asyncResp->res.jsonValue["Context"] = subValue->customText;
534e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["SubscriptionType"] =
535b52664e2SAppaRao Puli                     subValue->subscriptionType;
536ad22fefeSEd Tanous                 asyncResp->res.jsonValue["HttpHeaders"] =
537ad22fefeSEd Tanous                     nlohmann::json::array();
5387e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["EventFormatType"] =
5397e860f15SJohn Edward Broadbent                     subValue->eventFormatType;
540e5aaf047SAppaRao Puli                 asyncResp->res.jsonValue["RegistryPrefixes"] =
541b52664e2SAppaRao Puli                     subValue->registryPrefixes;
5427e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["ResourceTypes"] =
5437e860f15SJohn Edward Broadbent                     subValue->resourceTypes;
544e56f254cSSunitha Harish 
5457e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MessageIds"] =
5467e860f15SJohn Edward Broadbent                     subValue->registryMsgIds;
5477e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["DeliveryRetryPolicy"] =
5487e860f15SJohn Edward Broadbent                     subValue->retryPolicy;
549144b6318SAppaRao Puli 
550144b6318SAppaRao Puli                 std::vector<nlohmann::json> mrdJsonArray;
551144b6318SAppaRao Puli                 for (const auto& mdrUri : subValue->metricReportDefinitions)
552144b6318SAppaRao Puli                 {
553144b6318SAppaRao Puli                     mrdJsonArray.push_back({{"@odata.id", mdrUri}});
554144b6318SAppaRao Puli                 }
5557e860f15SJohn Edward Broadbent                 asyncResp->res.jsonValue["MetricReportDefinitions"] =
5567e860f15SJohn Edward Broadbent                     mrdJsonArray;
5577e860f15SJohn Edward Broadbent             });
5589d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
559ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
560ed398213SEd Tanous         // ConfigureSelf
5617eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
562ed398213SEd Tanous         //.privileges(redfish::privileges::patchEventDestination)
563432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
5647e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::patch)(
5657e860f15SJohn Edward Broadbent             [](const crow::Request& req,
5667e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
5677e860f15SJohn Edward Broadbent                const std::string& param) {
568b52664e2SAppaRao Puli                 std::shared_ptr<Subscription> subValue =
5697e860f15SJohn Edward Broadbent                     EventServiceManager::getInstance().getSubscription(param);
570b52664e2SAppaRao Puli                 if (subValue == nullptr)
571e5aaf047SAppaRao Puli                 {
5727e860f15SJohn Edward Broadbent                     asyncResp->res.result(
5737e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
574e5aaf047SAppaRao Puli                     return;
575e5aaf047SAppaRao Puli                 }
576e5aaf047SAppaRao Puli 
577e5aaf047SAppaRao Puli                 std::optional<std::string> context;
578e5aaf047SAppaRao Puli                 std::optional<std::string> retryPolicy;
579e5aaf047SAppaRao Puli                 std::optional<std::vector<nlohmann::json>> headers;
580e5aaf047SAppaRao Puli 
5817e860f15SJohn Edward Broadbent                 if (!json_util::readJson(req, asyncResp->res, "Context",
5827e860f15SJohn Edward Broadbent                                          context, "DeliveryRetryPolicy",
5837e860f15SJohn Edward Broadbent                                          retryPolicy, "HttpHeaders", headers))
584e5aaf047SAppaRao Puli                 {
585e5aaf047SAppaRao Puli                     return;
586e5aaf047SAppaRao Puli                 }
587e5aaf047SAppaRao Puli 
588e5aaf047SAppaRao Puli                 if (context)
589e5aaf047SAppaRao Puli                 {
590b52664e2SAppaRao Puli                     subValue->customText = *context;
591e5aaf047SAppaRao Puli                 }
592e5aaf047SAppaRao Puli 
593e5aaf047SAppaRao Puli                 if (headers)
594e5aaf047SAppaRao Puli                 {
595601c71aeSEd Tanous                     boost::beast::http::fields fields;
596601c71aeSEd Tanous                     for (const nlohmann::json& headerChunk : *headers)
597601c71aeSEd Tanous                     {
598601c71aeSEd Tanous                         for (auto& it : headerChunk.items())
599601c71aeSEd Tanous                         {
600601c71aeSEd Tanous                             const std::string* value =
601601c71aeSEd Tanous                                 it.value().get_ptr<const std::string*>();
602601c71aeSEd Tanous                             if (value == nullptr)
603601c71aeSEd Tanous                             {
604601c71aeSEd Tanous                                 messages::propertyValueFormatError(
605601c71aeSEd Tanous                                     asyncResp->res,
606601c71aeSEd Tanous                                     it.value().dump(2, ' ', true),
607601c71aeSEd Tanous                                     "HttpHeaders/" + it.key());
608601c71aeSEd Tanous                                 return;
609601c71aeSEd Tanous                             }
610601c71aeSEd Tanous                             fields.set(it.key(), *value);
611601c71aeSEd Tanous                         }
612601c71aeSEd Tanous                     }
613601c71aeSEd Tanous                     subValue->httpHeaders = fields;
614e5aaf047SAppaRao Puli                 }
615e5aaf047SAppaRao Puli 
616e5aaf047SAppaRao Puli                 if (retryPolicy)
617e5aaf047SAppaRao Puli                 {
618e5aaf047SAppaRao Puli                     if (std::find(supportedRetryPolicies.begin(),
619e5aaf047SAppaRao Puli                                   supportedRetryPolicies.end(),
620e5aaf047SAppaRao Puli                                   *retryPolicy) == supportedRetryPolicies.end())
621e5aaf047SAppaRao Puli                     {
6227e860f15SJohn Edward Broadbent                         messages::propertyValueNotInList(asyncResp->res,
6237e860f15SJohn Edward Broadbent                                                          *retryPolicy,
624e5aaf047SAppaRao Puli                                                          "DeliveryRetryPolicy");
625e5aaf047SAppaRao Puli                         return;
626e5aaf047SAppaRao Puli                     }
627b52664e2SAppaRao Puli                     subValue->retryPolicy = *retryPolicy;
628fe44eb0bSAyushi Smriti                     subValue->updateRetryPolicy();
629e5aaf047SAppaRao Puli                 }
630e5aaf047SAppaRao Puli 
631b52664e2SAppaRao Puli                 EventServiceManager::getInstance().updateSubscriptionData();
6327e860f15SJohn Edward Broadbent             });
6339d41aec6SRavi Teja     BMCWEB_ROUTE(app, "/redfish/v1/EventService/Subscriptions/<str>/")
634ed398213SEd Tanous         // The below privilege is wrong, it should be ConfigureManager OR
635ed398213SEd Tanous         // ConfigureSelf
6367eeafa76SAbhishek Patel         // https://github.com/openbmc/bmcweb/issues/220
637ed398213SEd Tanous         //.privileges(redfish::privileges::deleteEventDestination)
638432a890cSEd Tanous         .privileges({{"ConfigureManager"}})
6397e860f15SJohn Edward Broadbent         .methods(boost::beast::http::verb::delete_)(
6407e860f15SJohn Edward Broadbent             [](const crow::Request&,
6417e860f15SJohn Edward Broadbent                const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
6427e860f15SJohn Edward Broadbent                const std::string& param) {
6437e860f15SJohn Edward Broadbent                 if (!EventServiceManager::getInstance().isSubscriptionExist(
6447e860f15SJohn Edward Broadbent                         param))
645e5aaf047SAppaRao Puli                 {
6467e860f15SJohn Edward Broadbent                     asyncResp->res.result(
6477e860f15SJohn Edward Broadbent                         boost::beast::http::status::not_found);
648e5aaf047SAppaRao Puli                     return;
649e5aaf047SAppaRao Puli                 }
6507e860f15SJohn Edward Broadbent                 EventServiceManager::getInstance().deleteSubscription(param);
6517e860f15SJohn Edward Broadbent             });
652e5aaf047SAppaRao Puli }
653e5aaf047SAppaRao Puli 
654e5aaf047SAppaRao Puli } // namespace redfish
655